STM32使用SPI协议主从通信

这篇具有很好参考价值的文章主要介绍了STM32使用SPI协议主从通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一、理论部分     

SPI简介  

SPI特征

SPI物理层

SPI协议层

SPI配置过程

SPI数据发送与接收过程

二、代码部分

主机代码

从机代码


前言

这是一篇学习笔记,记录自己学习SPI通信。方便之后运用的时候回顾。参考《STM32中文参考手册》

一、理论部分     

SPI简介  

         SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设  
备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC LCD 等设备与 MCU 间,
要求通讯速率较高的场合。   

SPI特征

3 线全双工同步传输
● 带或不带第三根双向数据线的双线单工同步传输
8 16 位传输帧格式选择
● 主或从操作
● 支持多主模式
8 个主模式波特率预分频系数 ( 最大为 f PCLK /2)
● 从模式频率 ( 最大为 f PCLK /2)
● 主模式和从模式的快速通信
● 主模式和从模式下均可以由软件或硬件进行 NSS 管理:主 / 从操作模式的动态改变
● 可编程的时钟极性和相位
● 可编程的数据顺序, MSB 在前或 LSB 在前
● 可触发中断的专用发送和接收标志
SPI 总线忙状态标志
● 支持可靠通信的硬件 CRC
        ─ 在发送模式下, CRC 值可以被作为最后一个字节发送
        ─ 在全双工模式中对接收到的最后一个字节自动进行 CRC 校验
● 可触发中断的主模式故障、过载以及 CRC 错误标志
● 支持 DMA 功能的 1 字节发送和接收缓冲器:产生发送和接受请求

SPI物理层

 SPI通信设备连接图

stm32 spi从机,stm32,单片机,物联网

SPI框图

stm32 spi从机,stm32,单片机,物联网

通常 SPI 通过 4 个引脚与外部器件相连:
MISO :主设备输入 / 从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
MOSI :主设备输出 / 从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
SCK :串口时钟,作为主设备的输出,从设备的输入
NSS :从设备选择。这是一个可选的引脚,用来选择主 / 从设备。它的功能是用来作为“片
选引脚”,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。从设备的 NSS
引脚可以由主设备的一个标准 I/O 引脚来驱动。一旦被使能 (SSOE ) NSS 引脚也可以作为
输出引脚,并在 SPI 处于主模式时拉低;此时,所有的 SPI 设备,如果它们的 NSS 引脚连接
到主设备的 NSS 引脚,则会检测到低电平,如果它们被设置为 NSS 硬件模式,就会自动进
入从设备状态。当配置为主设备、 NSS 配置为输入引脚 (MSTR=1 SSOE=0) 时,如果 NSS
被拉低,则这个 SPI 设备进入主模式失败状态:即 MSTR 位被自动清除,此设备进入从模式

SPI协议层

数据时钟时序图
stm32 spi从机,stm32,单片机,物联网

SPI配置过程

 SPI主模式配置

1. 通过SPI_CR1寄存器的BR[2:0]位定义串行时钟波特率。
2. 选择CPOL
CPHA位,定义数据传输和串行时钟间的相位关系
3. 设置
DFF位来定义8位或16位数据帧格式。
4. 配置
SPI_CR1寄存器的LSBFIRST位定义帧格式。
5. 如果需要
NSS引脚工作在输入模式,硬件模式下,在整个数据帧传输期间应把NSS脚连接到高电平;在软件模式下,需设置SPI_CR1寄存器的SSM位和SSI位。如果NSS引脚工作在输出模式,则只需设置SSOE位。
6. 必须设置
MSTR位和SPE(只当NSS脚被连到高电平,这些位才能保持置位)。 在这个配置中,MOSI引脚是数据输出,而MISO引脚是数据输入。

SPI从模式配置

1. 设置 DFF 位以定义数据帧格式为 8 位或 16 位。
2. 选择 CPOL CPHA 位来定义数据传输和串行时钟之间的相位关系。 为保证正确 的数据传输,从设备和主设备的CPOL CPHA 位必须配置成相同的方式。
3. 帧格式 (SPI_CR1 寄存器中的 LSBFIRST 位定义的 ”MSB 在前 还是 ”LSB 在前 ”) 必须与主设备相同。
4. 硬件模式下 ( 参考从选择 (NSS) 脚管理部分 ) ,在完整的数据帧 (8 位或 16 ) 传输过程中,NSS引脚必须为低电平。在 NSS 软件模式下,设置 SPI_CR1 寄存器中的 SSM 位并清除 SSI 位。
5. 清除 MSTR 位、设置 SPE (SPI_CR1 寄存器 ) ,使相应引脚工作于 SPI 模式下。 在这个配置中,MOSI 引脚是数据输入, MISO 引脚是数据输出。

SPI数据发送与接收过程

主模式通讯过程

stm32 spi从机,stm32,单片机,物联网

从模式通讯过程

stm32 spi从机,stm32,单片机,物联网

 

 

接收与发送缓冲器
在接收时,接收到的数据被存放在一个内部的接收缓冲器中;在发送时,在被发送之前,数据
将首先被存放在一个内部的发送缓冲器中。 对SPI_DR 寄存器的读操作,将返回接收缓冲器的内容;写入 SPI_DR 寄存器的数据将被写入发 送缓冲器中。
主模式下开始传输
● 全双工模式
当写入数据到 SPI_DR 寄存器 ( 发送缓冲器 ) 后,传输开始;
在传送第一位数据的同时,数据被并行地从发送缓冲器传送到 8 位的移位寄存器中,
然后按顺序被串行地移位送到 MOSI 引脚上;
与此同时,在 MISO 引脚上接收到的数据,按顺序被串行地移位进入 8 位的移位寄存器
中,然后被并行地传送到 SPI_DR 寄存器 ( 接收缓冲器 ) 中。
从模式下开始传输
● 全双工模式
当从设备接收到时钟信号并且第一个数据位出现在它的 MOSI 时,数据传输开始,随
后的数据位依次移动进入移位寄存器;
与此同时,在传输第一个数据位时,发送缓冲器中的数据被并行地传送到 8 位的移位
寄存器,随后被串行地发送到 MISO 引脚上。软件必须保证在 SPI 主设备开始数据传
输之前在发送寄存器中写入要发送的数据。
主或从模式下 全双工发送和接收过程模式
软件必须遵循下述过程,发送和接收数据
1. 设置 SPE 位为 ’1’ ,使能 SPI 模块;
2. SPI_DR 寄存器中写入第一个要发送的数据,这个操作会清除 TXE 标志;
3. 等待 TXE=1 ,然后写入第二个要发送的数据。等待 RXNE=1 ,然后读出 SPI_DR 寄存器并获得第一个接收到的数据,读SPI_DR 的同时清除了 RXNE 位。重复这些操作,发送后续的数据同时接n-1 个数据;
4. 等待 RXNE=1 ,然后接收最后一个数据;
5. 等待 TXE=1 ,在 BSY=0 之后关闭 SPI 模块。
也可以在响应 RXNE TXE 标志的上升沿产生的中断的处理程序中实现这个过程。

二、代码部分

    我的想法是在串口助手上发送给主机什么,主机就发什么给从机。之后从机把接收的数据再返回给主机,最终再串口助手上打印出来。验证SPI的全双工通讯。主机和从机都采用中断的方式发送和接收。

主机代码

SPI配置代码

void SPI2_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;
	
	/* SPI的IO口和SPI外设打开时钟 */
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;        //PB12推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/* SPI的IO口设置 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_SetBits(GPIOB,GPIO_Pin_12);
	
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值: 
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
	
	
}

串口中断部分文章来源地址https://www.toymoban.com/news/detail-647319.html

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u16 r,i;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);
		r =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空 
		SPI_I2S_SendData(SPI2, r);
		while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte	
		i = SPI_I2S_ReceiveData(SPI2);	
		
		GPIO_SetBits(GPIOB,GPIO_Pin_12);
		USART_senddate(USART1,i) ;
	} 
} 	  

从机代码

void SPI2_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* SPI的IO口和SPI外设打开时钟 */
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;        //PB12推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //下拉输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/* SPI的IO口设置 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
	
	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
	
	
	SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE);//开启相关中断
	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;//SPI2中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、	
	
}
u16 i;
void SPI2_IRQHandler(void) 
{ 
	//接收数据 
	if(SPI_I2S_GetITStatus(SPI2,SPI_I2S_IT_RXNE) != RESET)
	{
		i = SPI_I2S_ReceiveData(SPI2);
		while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
		SPI_I2S_SendData(SPI2,i);		
		USART_senddate(USART1, i);	
	}
   
} 

到了这里,关于STM32使用SPI协议主从通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32学习】——SPI通信协议&SPI时序&W25Q64存储芯片&软件SPI读写

    目录 前言 一、SPI通信协议 1.概述​ 2.硬件电路  3.移位示意图 二、SPI时序 1.时序基本单元 2.完整时序波形 三、W25Q64存储芯片 1.芯片简介  2.硬件电路引脚定义  3.芯片框图 4.Flash操作注意事项 四、软件SPI读写W25Q64 五、SPI通信外设 总结 声明:学习笔记来自江科大自化协B站教

    2024年02月09日
    浏览(57)
  • STM32 SPI通信协议1——协议基本原理及管脚定义

            SPI全称为 Serial Peripheral interface ,译为 串行外围设备接口 。SPI主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号编码器之间。         SPI是一种高速,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,

    2024年01月25日
    浏览(39)
  • stm32HAL库 G4 SPI 从机DMA可变长度接受数据乱码问题

    使用一个引脚当作SPI CS, 边沿触发; 在电平位0时候接受SPI数据20个字节 如果实际主机只发了小于20字节时候, 下一个帧就会错乱; 去老外找了之后,需要复位SPi RCC时钟才能复位掉SPI 下面的不行 正确的做法

    2024年02月10日
    浏览(32)
  • STM-32:SPI通信协议/W25Q64简介—软件SPI读写W25Q64

    SPI是串行外设接口(Serial Peripheral Interface)的缩写,是美国摩托罗拉公司(Motorola)最先推出的一种同步串行传输规范,也是一种单片机外设芯片串行扩展接口,是一种高速、全双工、同步通信总线,所以可以在同一时间发送和接收数据,SPI没有定义速度限制,通常能达到甚

    2024年02月16日
    浏览(41)
  • 【快速上手STM32】SPI通信协议&&1.8寸TFT-LCD(ST7735S)

    SPI,英文全称Serial Peripheral Interface,即串行外围设备接口,是一种高速、全双工、同步的串行通信总线。 我们之前说过I2C,那么我们就拿I2C和SPI做个对比。 SPI和I2C对比,优势在于SPI的传输速率比I2C快得多,劣势在于SPI需要用的通信线比较多。 I2C只需要两根线,而SPI至少需要

    2024年04月27日
    浏览(34)
  • STM32使用软件SPI协议操作TFT18彩屏

    时间记录:2024/2/20 (1)SPI设备通过4根线进行通信,CS片选线,选择从设备,SCK时钟线,由主设备产生时钟,主机MOSI线连从机MISO线,由主机向从机发送信息,主机MISO线连接从机MOSI线,由从机向主机发送信息 (2)SPI分为4种通信方式 模式0:CPOL=0,CPHA=0,空闲时SCK时钟线为低

    2024年02月21日
    浏览(30)
  • 树莓派(主)与STM32(从)使用SPI通信(持续更新中)

    使用树莓派向 STM32 发送数据,STM32 收到数据后通过串口的方式将数据打印到电脑上,同时返回给树莓派数据。树莓派接收到数据后打印在控制台上。 SPI 的配置为 树莓派主机 STM32 从机 全双工 8 bit 传输 工作模式 0 :CPOL|CPHA = 00 MSB 优先 禁止 CRC 校验 SPI(Serial Peripheral Interfac

    2024年02月14日
    浏览(139)
  • STM32——SPI通信

    SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 四根通信线: SCK(Serial Clock)【CLK或SCL或CK】、 MOSI(Master Output Slave Input)【DO(Data Output)】、 MISO(Master Input Slave Output)【DI(Data Input)】、 SS(Slave Select)【CS或NSS】 同步,全双工 支持总线挂载多设备

    2024年02月11日
    浏览(36)
  • stm32----SPI协议

    SPI(Serial Peripheral Interface,串行外围设备接口),是Motorola公司提出的一种同步串行接口技术,是一种高速、 全双工 、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,节约了芯片pin的数目,同时为PCB在布局上节省了空间。正是由于这种简单易用的特性,现在越

    2024年02月11日
    浏览(28)
  • STM32使用SPI通信时的一些常见问题及解决方法(主,从)

            最近在做一个多MCU的项目时,MCU之间的数据传输使用了SPI通信,在做从机时遇到了一些 “疑难杂症”,研究了半天,总算是把故障排除了,就又总结了一下SPI常遇到的几种问题写出来整理一下。 目录 一、SPI简介:  二、常见问题: 三、疑难杂症: Q1:使用的HAL库,

    2024年02月21日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包