stm32串行设备接口SPI控制max31865
本人是刚入行的嵌入式,之前也没有多少项目经验,故在公司的这几个月里,可谓是如履薄冰,对于公司不同项目使用的不同的设备之多,数据手册之繁杂,让我不禁望洋兴叹,故而不愿意放弃周末这大好的自我提升时间,努力耕耘,特开此园,与诸君共论(咳咳,有点羞耻,算了就这样吧,不改了)。
现阶段我比较注重各种协议,所以今后几个月内会不间断的更新各种简单常用的协议,这也算给自己立一个flag吧,督促自己。
——————————————————————————————————————————分割线———————————————————————————————————
本篇讲述的是常用的工业级标准串行协议SPI,经常用于各种嵌入式系统,能够将微处理器连接到各种片外传感器、存储器和控制设备等。
SPI使用两根数据线、一根时钟线、一根控制线(片选线)实现串行通信:
MOSI | 主设备数据输出从设备数据输入线 |
MISO | 主设备数据输出从设备数据输入线 |
SCK | 主设备输出从设备输入时钟线(用于同步数据位) |
NSS(CS) | 主设备输出从设备输入片选线(低电平有效) |
SPI由于其时钟SCK的极性和相性的不同,其工作模式一共有4种:
在这里我要感谢我的高频电子线路的老师,谢谢他教会我的许多模电知识(话说我模电课是在干嘛?)
对于不知道什么是极性和相性的同学,可以先简单的将这两个名词分别记为极性(波形的上下高低起伏)、相性(波形沿时间线的前后的变化)(实在不了解的就当作名词使用)
在SPI的SCK时钟线极性为0时,SPI在空闲时SCK为低电平,工作时由低电平起跳到高电平
SCK时钟线极性为1时,SPI在空闲时SCK为高电平,工作时由高电平起跳到低电平
在SPI的SCK时钟线相性为0时,SPI会在工作时从第一个时钟沿开始采集数据
SCK时钟线相性为1时,SPI会在工作时从第二个时钟沿开始采集数据
但我一般不会去记这四种工作模式分别是什么极性什么相位,我只会记住极性为0是低电平跳到高电平,相性为0是第一个边沿采集,反之亦然,这样不管在遇到什么从设备时,你都能根据datasheet优雅的设置SPI工作模式。
对于整个SPI通信协议来说,由数据的收发和对收发的控制两部分组成,其收发数据的整个流程为:
主设备将数据copy到SPI发送缓存区——》主设备拉低要通信的从设备的NSS(CS)片选线电平——》SPI检测到片选线被拉低后进入工作模式——》位移寄存器将发送缓存区的数据并串转换发送出去(同时,在从设备中数据由位移寄存器串并转换到接收缓存区中)
这里要注意:不管是主设备还是从设备的位移转换器都在主设备的SCK作用下完成移位的,故从设备想要发送数据到主设备必须依赖主设备的时钟,也就是主设备要空发一个没用的数据,从设备利用此时主设备给的时钟趁机将数据发给主设备(从设备好惨啊~~~)
这是SPI的方框图,对于收发控制方面感兴趣的可以看一下(晚上照的,灯光不好,请见谅)
图中的NSS(CS)就是片选,低电平有效,可以使得主设备在与多个设备连接时,也能单独与某一个从设备进行通信,而不受干扰(这就是渣男的梦想吗?doge)
图中右下部分CR1这个寄存器中的SSM位是用于控制上面说讲的NSS是否有效的,SSM为0时,此时NSS就有效;SSM为1时,此时NSS就无效,
但此时NSS无效了我该怎么实现片选这个功能呢?
此时就可以通过图中边上的那个CR1寄存器中的SSI位来实现,此位一般主设备设为1,当某个从设备设为0时,表示选中该设备了
一般在实际项目的使用中都会用到多个从设备,所有的从设备都共用MOSI、MISO、SCK这三根线,但每个从设备都必须拥有独属于自己的NSS片选线,但我不可能有几个从设备就直接从主设备连几根NSS线,这太消耗资源了,此时一般都会使用多路复用器来控制。
SPI寄存器一共有7个,分别为CR1(控制寄存器1)、CR2(控制寄存器2)、SR(状态寄存器)、DR(数字寄存器)、CRCPR(CRC多项式寄存器)、RXCRCR(接收CRC寄存器)、TXCRCR(发送CRC寄存器);
这些寄存器在STM32中都是被定义过的,可以不用管该寄存器的地址,我在这里就不一一列举各个寄存器的使用了,感兴趣的可以私下了解一番。
——————————————————————————分割线————————————————————————————————————-——————————————
以上就是对于SPI的理论知识,对于具体的代码实现的话,由于大家所应用的环境不同,故我这里只能给出一份基于STM32F407GT6通过SPI控制MAX31865温度采集的代码示范:
//本来想写点注释的,但……懒癌犯了,直接复制应该没有问题的
int main(void)
{
int temvalue = 0,RTDs = 0,i = 0;
uint16_t data = 0;
float temps = 0;
uint16_t dtemp[2] = {0};
char tem_buff[30] = "0";
char *temptr = tem_buff; RCC_Configuration(); delay_init();
uart_init(115200);
SPI2_Init();
MAX31865_Init();
LED_Init(); delay_ms(10);
GPIO_ResetBits (GPIOB, GPIO_Pin_12);
SPI2_ReadWriteByte(0x80);
SPI2_ReadWriteByte(0xC1);
GPIO_SetBits (GPIOB, GPIO_Pin_12);
while(1)
{
dtemp[0] ='0';
dtemp[1] ='0';
data = 0;
temps = 0;
RTDs = 0;
SPI_ReadWrite(dtemp);
data=((dtemp[0]<<7) | dtemp[1]);
temps=data;
temps = (temps*402)/32768;
RTDs = (int)temps;
temvalue = 9e-10*(temps*temps*temps*temps)+4e-7*(temps*temps*temps)+0.0008*(temps*temps)+2.3828*temps-246.81;
sprintf(temptr,"RTD:%d temp:%d,data:%d\r\n",RTDs,temvalue,data); for(i = 0;i<30;i++)
{
USART_SendData(UART4, temptr[i]);
while(USART_GetFlagStatus(UART4,USART_FLAG_TC) ==RESET);
} GPIO_ResetBits(GPIOC,GPIO_Pin_14);
delay_ms(500);
GPIO_SetBits(GPIOC,GPIO_Pin_14);
delay_ms(500); } }
void MAX31865_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12); GPIO_SetBits (GPIOB, GPIO_Pin_12); //cs_H
SPI2_Init();
SPI2_SetSpeed(SPI_BaudRatePrescaler_256); }
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div4);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { }
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08) { }
}
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); }
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOA, ENABLE );//PORTBʱÖÓʹÄÜ RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2ʱÖÓʹÄÜ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15¸´ÓÃÍÆÍìÊä³ö cs miso mosi
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯GPIOB GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15ÉÏÀ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2, ENABLE); SPI2_ReadWriteByte(0xff); }
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler;
SPI_Cmd(SPI2,ENABLE); }
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0; while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)
{ return 0;
}
}
SPI_I2S_SendData(SPI2, TxData);
retry=0; while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200)
{ return 0;
}
}
return SPI_I2S_ReceiveData(SPI2); }
stm32串行设备接口SPI控制max31865的更多相关文章
- Arduino 串行外设接口(SPI)
时间有限有其他项目工作在忙,感觉作者写的不错,就先记录下来了. 这几天用SPI--Arduino 在供应商的电子原件上游离游走,重要的是可以读写了, 下面是在查资料看到的一篇不错的文章关于用Ardui ...
- Arduino 串行外设接口——W3Cschool
来源:https://www.w3cschool.cn/arduino/arduino_serial_peripheral_interface.html Arduino 串行外设接口 由 drbear ...
- Serializable 可串行化接口
Serializable 可串行化接口 定义一个User类,实现Serializable接口: package com.monkey1025; import java.io.Serializable; ...
- 嵌入式驱动开发之dsp fpga通信接口---spi串行外围接口、emif sram接口
-----------------------------------------author:pkf ------------------------------------------------ ...
- 痞子衡嵌入式:串行EEPROM接口事实标准及SPI EEPROM简介
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是EEPROM接口标准及SPI EEPROM. 痞子衡之前写过一篇文章 <SLC Parallel NOR简介>,介绍过并行N ...
- STM32学习笔记——SPI串行通讯(向原子哥学习)
一.SPI 简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在 EEPROM, FLASH,实时时钟,AD 转换器,还有数 ...
- SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)
SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...
- 【高速接口-RapidIO】2、RapidIO串行物理层的包与控制符号
一.RapidIO串行物理层背景介绍 上篇博文提到RapidIO的物理层支持串行物理层与并行物理层两种,由于Xilinx 部分FPGA内部已经集成了串行高速收发器,所以用FPGA实现RapidIO大多 ...
- 第24章 SPI—读写串行FLASH—零死角玩转STM32-F429系列
第24章 SPI—读写串行FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
随机推荐
- linux ar
转载:Linux ar命令 | 菜鸟教程 (runoob.com) Linux ar命令用于建立或修改备存文件,或是从备存文件中抽取文件. ar可让您集合许多文件,成为单一的备存文件.在备存文件中,所 ...
- linux命令中find, which、whereis、locate,有什么区别?
whatis 用于查询一个命令执行什么功能,并将查询结果打印到终端上 which 查看可执行文件的位置 whereis 查看文件的位置 man Linux提供了丰富的帮助手册,当你需要查看某个命令的参 ...
- 树的子结构 牛客网 剑指Offer
树的子结构 牛客网 剑指Offer 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) # class TreeNode: # def __init_ ...
- word-ladder leetcoder C++
Given two words (start and end), and a dictionary, find the length of shortest transformation sequen ...
- 并发编程从零开始(十四)-Executors工具类
并发编程从零开始(十四)-Executors工具类 12 Executors工具类 concurrent包提供了Executors工具类,利用它可以创建各种不同类型的线程池 12.1 四种对比 单线程 ...
- 谷粒 | 11 | nginx windows版简单安装使用
nginx配置 下载安装 传送门:官网下载 官网提供三种版本: Mainline version:Mainline 是 Nginx 目前主力在做的版本,可以说是开发版 Stable version:最 ...
- 限制q-error,防止产生次优计划
原文:<Preventing bad plans by bounding the impact of cardinality estimation errors> 摘要 文章定义了一个衡量 ...
- IDEA 运行maven工程报错:No goals have been specified for this build.....解决办法
出现这种错误可以在pom.xml里配置, 找到<build>标签在下面<plugins>标签上面加上<defaultGoal>compile</default ...
- vue+node+mongondb实战之mongodb登陆操作
页面搭建基本完成,只是样式还没有美化,由于采取的前后端分离开发,所有页面逻辑全部由vue来负责,后台采用express框架只用来提供 接口,注册就是讲数据存入数据库,比较简单,而登陆碰了一些小问题,发 ...
- printf("%d\n",printf("%d",printf("%d",i)));
#include <stdio.h> int printf( const char *format, ... );首先 得看printf的返回类型是 int 这个函数的返回值是 你输出的位 ...