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/ ...
随机推荐
- hdu 3199 Hamming Problem(构造?枚举?)
题意: For each three prime numbers p1, p2 and p3, let's define Hamming sequence Hi(p1, p2, p3), i=1, . ...
- linux 内核源代码情景分析——linux 内核源码中的汇编语言代码
1. 用汇编语言编写部分核心代码的原因: ① 操作系统内核中的底层程序直接与硬件打交道,需要用到一些专用的指令,而这些指令在C语言中并无对应的语言成分: ② CPU中的一些特殊指令也没有对应的C语言成 ...
- 如何系统学习C 语言(中)之 指针篇
谈到指针,我们可能会想到钟表上的指针,但这里的指针不是现实生活中看得见摸得着的钟表上的指针,c 语言中的指针只存在于逻辑思维中,物理上并不存在. 同时,指针也是C 语言中最精华的部分,通过灵活地运用指 ...
- ssl 原理和建立连接过程
ssl ("Secure Sockets Layer")加密原理 和https的关系https = http + ssl ssl 位置: SSL握手 证书主要作用是在SSL握手中, ...
- python编程中的流程控制
内容概要 成员运算 身份运算 流程控制 详细 1.成员运算 定义:判断某个个体在不在某个群体内 关键词:in(在) /// not in(不在) 例: num_list = [1, 2, 3, 4, ...
- RabbitMQ的安装及入门使(Windows)
1.安装Erlang所以在安装rabbitMQ之前,需要先安装Erlang .点击下载Erlang 执行下载下来的Erlang,全部点击"下一步"就行.安装完成设置一下环境变量. ...
- 数组 & 对象 & 函数
数组 数组也是一个对象,不同的是对象用字符串作为属性名,而数组用数字作为索引,数组的索引从0开始 创建数组: //方式一:构造器,可以在创建数组时指定 Var arr = new Array(1,2, ...
- RocketMQ源码详解 | Consumer篇 · 其一:消息的 Pull 和 Push
概述 当消息被存储后,消费者就会将其消费. 这句话简要的概述了一条消息的最总去向,也引出了本文将讨论的问题: 消息什么时候才对被消费者可见? 是在 page cache 中吗?还是在落盘后?还是像 K ...
- 12组-Alpha冲刺-3/6
一.基本情况 队名:字节不跳动 组长博客:https://www.cnblogs.com/147258369k/p/15546442.html 小组人数:10人 二.冲刺概况汇报 侯钦凯 过去两天完成 ...
- 一文分析 Android现状及发展前景
Coding这些年,一直低头"搬砖",好像从未仔细审视过Android的发展现状,亦未好好思考Android的发展前景."低头干活,还要抬头看路",写一篇文章简 ...