玩转STM32-通信协议SPI(详细-慢工出细活)

文章目录

  • 一、SPI的基础知识
    • 1.1 接口定义
    • 1.2 单机和多机通信
  • 二、STM32的SPI工作过程
    • 2.1 从选择(NSS)脚管理
    • 2.2 时钟相位与极性
    • 2.3 SPI主模式
    • 2.4 SPI从模式
  • 三、应用实例

一、SPI的基础知识

1.1 接口定义

SPI系统可直接与各个厂家生产的多种标准外围器件接口,它只需4条线:串行时钟线(SCK)、主机输入/从机输出数据线(MISO)、主机输出/从机输入数据线(MOSI)和低电平有效的从机选择线(NSS)。
(1)MISO:该引脚在从模式下发送数据,在主模式下接收数据。
(2)MOSI:该引脚在主模式下发送数据,在从模式下接收数据。
(3)SCK:串口时钟,作为主设备的输出,从设备的输入。
(4)NSS:这个是一个可选的引脚,用来选择主/从设备。它的功能是用来作为片选引脚,让主设备可以单独地与特定从设备通信,避免数据线上的冲突。
SPI是一个环形总线结构,由NSS、SCK、MISO、MOSI构成,单主和单从设备连接图如下图所示,NSS引脚设置为输入,MOSI引脚相互连接,MISO引脚相互连接,数据在主和从之间串行地传输(MSB位在前)。通信总是由主设备发起,主设备通过MOSI脚把数据发送给从设备,从设备通过MISO引脚传回数据,属于全双工通信,数据输出和数据输入由同一个时钟信号同步,时钟信号由主设备通过SCK引脚提供。主机SPI时钟发生器在驱动移位寄存器移位的同时,产生时序由SCK引脚输出后控制从机移位寄存器。在SCK的控制下,主机移位寄存器的数据通过MOSI移位到从机移位寄存器中,而从机移位寄存器之前的数据通过MISO移位到主机移位寄存器中。
在这里插入图片描述

1.2 单机和多机通信

在多主机系统中,SPI还可以作为微处理器之间的通信。SPI子系统可以在软件控制下构成复杂或简单的系统,如一个主微控制器和几个从微控制器;几个微处理器互连,构成多主机系统,以及主微处理器和一个或多个从外围器件。

  1. 单主机通信
    多数应用场合用一个微处理器作为主机,它触发和控制向一个或多个外围器件传输数据或控制多个外围器件向主机传送数据,这些外围器件接收或提供传输的数据。
    这种主从SPI可用于微处理器与外围器件进行全双工、同步串行通信。SPI可以同时发出和接收串行数据。当SPI工作时,移位寄存器中的数据逐位从输出引脚输出(高位在前),同时从输入引脚接收的数据逐位移到移位寄存器(高位在前)。发出一个字节后,从另一个外围器件接收的字节数据进入移位寄存器。主SPI的是中国信号使传输过程同步。
    在这里插入图片描述
    许多简单的从外围器件只能接收主SPI的数据或只向主机发送数据。例如:串行-并行移位寄存器只能作为8位输出口。设置为主机的微处理器SPI控制向移位寄存器的发送过程。由于移位寄存器并不向SPI发出数据,因此SPI可以忽略接受的数据。
  2. 多主机通信
    SPI双主机多从机通信如下图所示。MOSI和MISO两个数据引脚用于接收和发送串行数据,高位MSB在前,地位LSB在后。当SPI设置为主机时,MISO是主机数据输入端,MOSI是主机数据输出端;当SPI设置为从机时,MISO是从机数据输出端,MOSI是从机数据输入端。
    在这里插入图片描述
    SCK是通过MISO和MOSI输入和输出数据的同步时钟。当SPI设置为主机时,SCK是主机时钟输出端;当SPI设置为从机时,SCK是从机时钟输入端。
    当SPI设置为主机时,SCK信号由内部微处理器总线时钟获得。当主机启动一次传输时,在SCK引脚自动产生8个时钟周期。对于主机或从机,都是从一个跳变沿进行采样,在另一个跳变沿移位输出或输入数据。
    NSS用于选择允许接收主机时钟和数据的从机。在数据传输之前NSS必须变为低电平,并在传输过程中保持为低电平。主机的NSS必须接到高电平。

二、STM32的SPI工作过程

2.1 从选择(NSS)脚管理

通过SPI_CR1寄存器的SSM位可以设置NSS的两种模式:软件NSS模式和硬件NSS模式。硬件/软件的从选择管理如下图所示。
在这里插入图片描述

  1. 软件NSS模式
    可以通过设置SPI_CR1寄存器的SSM位来使能这种模式。在这种模式下NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1的SSI位来驱动。
  2. 硬件NSS模式
    (1)NSS输出被使能:当STM32F10xxx工作为主SPI,并且NSS输出已经通过SPI_CR2寄存器的SSOE位使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS引脚相连并配置为硬件NSS的SPI设备,将自动变成从SPI设备。
    当一个SPI设备需要发送广播数据,它必须拉低NSS信号,以通知所有其它的设备它是主设备;如果它不能拉低NSS,这意味着总线上有另外一个主设备在通信,这时将产生一个硬件失败错误(Hard Fault)。
    (2)NSS输出被关闭:允许操作于多主环境。

2.2 时钟相位与极性

SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态保持低电平;如果CPOL被置’1’,SCK引脚在空闲状态保持高电平。 如果CPHA(时钟相位)位被置’1’,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0’,SCK时钟的第一边沿(CPOL位为’0’时就是上升沿,CPOL位为’1’时就是下降沿)进行数据位采样,数据在第一个时钟边沿被锁存。CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
下图显示了SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK脚、MISO脚、MOSI脚直接连接的主或从时序图。
来自数据手册

2.3 SPI主模式

  1. 主模式配置过程
    在主配置时,在SCK脚产生串行时钟。 配置步骤
    1) 通过SPI_CR1寄存器的BR[2:0]位定义串行时钟波特率。
    2)选择CPOL和CPHA位,定义数据传输和串行时钟间的相位关系(见图212)。
    3) 设置DFF位来定义8位或16位数据帧格式。
    4)配置SPI_CR1寄存器的LSBFIRST位定义帧格式。
    5)如果需要NSS引脚工作在输入模式,硬件模式下,在整个数据帧传输期间应把NSS脚连接到高电平;在软件模式下,需设置SPI_CR1寄存器的SSM位和SSI位。如果NSS引脚工作在输出模式,则只需设置SSOE位。
    6)必须设置MSTR位和SPE位(只当NSS脚被连到高电平,这些位才能保持置位)。
    在这个配置中,MOSI引脚是数据输出,而MISO引脚是数据输入。
  2. 数据发送过程
    当写入数据至发送缓冲器时,发送过程开始。 在发送第一个数据位时,数据字被并行地(通过内部总线)传入移位寄存器,而后串行地移出到MOSI脚上;MSB在先还是LSB在先,取决于SPI_CR1寄存器中的LSBFIRST位的设置。数据从发送缓冲器传输到移位寄存器时TXE标志将被置位,如果设置了SPI_CR1寄存器中的TXEIE位,将产生中断。
  3. 数据接收过程
    对于接收器来说,当数据传输完成时:
    1)传送移位寄存器里的数据到接收缓冲器,并且RXNE标志被置位。
    2) 如果设置了SPI_CR2寄存器中的RXNEIE位,则产生中断。
    在最后采样时钟沿,RXNE位被设置,在移位寄存器中接收到的数据字被传送到接收缓冲器。读SPI_DR寄存器时,SPI设备返回接收缓冲器中的数据。 读SPI_DR寄存器将清除RXNE位。 一旦传输开始,如果下一个将发送的数据被放进了发送缓冲器,就可以维持一个连续的传输流。在试图写发送缓冲器之前,需确认TXE标志应该为’1’。

2.4 SPI从模式

在从模式下,SCK引脚用于接收从主设备来的串行时钟。SPI_CR1寄存器中BR[2:0]的设置不影响数据传输速率。

  1. 从模式配置步骤
    1)设置DFF位以定义数据帧格式为8位或16位。
    2) 选择CPOL和CPHA位来定义数据传输和串行时钟之间的相位关系(见图212)。为保证正确的数据传输,从设备和主设备的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引脚是数据输出。
  2. 数据发送过程
    在写操作中,数据字被并行地写入发送缓冲器。 当从设备收到时钟信号,并且在MOSI引脚上出现第一个数据位时,发送过程开始(译注:此时第一个位被发送出去)。余下的位(对于8位数据帧格式,还有7位;对于16位数据帧格式,还有15位)被装进移位寄存器。当发送缓冲器中的数据传输到移位寄存器时,SPI_SP寄存器的TXE标志被设置,如果设置了SPI_CR2寄存器的TXEIE位,将会产生中断。
  3. 数据接收过程
    对于接收器,当数据接收完成时:
    1)移位寄存器中的数据传送到接收缓冲器,SPI_SR 寄存器中的RXNE标志被设置。
    2)如果设置了SPI_CR2寄存器中的RXNEIE位,则产生中断。 在最后一个采样时钟边沿后,RXNE位被置’1’,移位寄存器中接收到的数据字节被传送到接收缓冲器。当读SPI_DR寄存器时,SPI设备返回这个接收缓冲器的数值。 读SPI_DR寄存器时,RXNE位被清除。

三、应用实例

  1. 实例介绍
    STM32通过SPI接口读取Flash W25X16的ID,并通过USART发送到上位机,通过串口调试助手显示ID信息。
  2. 实例程序
    // 串口初始化
void UsartDriver_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStureture;
	USART_InitTypeDef USART_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	// PA9  TX
	GPIO_InitStureture.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStureture.GPIO_Pin = USART_GPIO_TX_PIN;
	GPIO_InitStureture.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(USART_GPIO_PORT,&GPIO_InitStureture);
	
	// PA10 rx
	GPIO_InitStureture.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStureture.GPIO_Pin = USART_GPIO_RX_PIN;
	GPIO_Init(USART_GPIO_PORT,&GPIO_InitStureture);
	
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART_PORT,&USART_InitStructure);
	USART_Cmd(USART_PORT,ENABLE);
}

/*串口1连续发送函数*/
void BdUsart1Trans(float *p, int16_t len)
{
	uint16_t i;
  for(i = 0;i < len; i++)
  {
   USART_SendData(USART1 , p[i]);
   while(USART_GetFlagStatus(USART1 , USART_FLAG_TC) == RESET) {}; // FLAG=0,未发完,等待
  }
}

/*串口1连续接收函数*/
void BdUsart1Recv(char *p, int16_t len)
{
	uint16_t i;
  for(i = 0;i < len; i++)
  {
    if(USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == SET)
		{
			p[i] = USART_ReceiveData(USART1);
		}; // FLAG=1, 收到数据
	}
}

// SPI初始化

// SPI
void SPIDriver_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStureture;
	SPI_InitTypeDef SPI_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1,ENABLE);
	
	GPIO_InitStureture.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStureture.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7;
	GPIO_InitStureture.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStureture);
  // cs
	GPIO_InitStureture.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStureture.GPIO_Pin = GPIO_Pin_2;
	GPIO_Init(GPIOA,&GPIO_InitStureture);
	GPIO_SetBits(GPIOA,GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7);
	// 设置SPI单向或双向的数据模式
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	// 设置主模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	// 8位帧结构
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	// 时钟悬空高
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	// 数据捕获在第二个时钟沿
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	// 内部NSS信号由软件管理
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	// 波特率预分频为256
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
	// 数据从MSB位开始传输
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	// CRC值计算的多项式,大于7即可
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI1,&SPI_InitStructure);
	SPI_Cmd(SPI1,ENABLE);
}

// 读取SPI
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
	uint8_t retry = 0;
	//检查指定的SPI标志位设置与否:发送缓存标志位
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET)
	{
		retry++;
		if(retry > 200)return 0;
	}
	//通过外设SPI发送一个数据
	SPI_I2S_SendData(SPI1,TxData);
	retry = 0;
	// 检查指定的SPI标志位设置与否
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET)
	{
		retry++;
		if(retry > 200)return 0;
	}
	//接收数据
	return SPI_I2S_ReceiveData(SPI1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/689056.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

111、二叉树的最小深度

给定一个二叉树&#xff0c;找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 题解&#xff1a;找出最小深度也就是找出根节点相对所有叶子结点的最小高度&#xff0c;在这也表明了根节点的高度是变化的&#xff0c;相对不同的叶子结点有不同的高度。…

Python爬取城市空气质量数据

Python爬取城市空气质量数据 一、思路分析1、寻找数据接口2、发送请求3、解析数据4、保存数据二、完整代码一、思路分析 目标数据所在的网站是天气后报网站,网址为:www.tianqihoubao.com,需要采集武汉市近十年每天的空气质量数据。先看一下爬取后的数据情况: 1、寻找数据…

视频会议开发:为什么必须使用显卡GPU解码渲染视频?

现在&#xff0c;使用视频会议系统远程协同办公、沟通交流&#xff0c;已经非常普遍了。如果我们要开发自己的视频会议系统&#xff0c;那么&#xff0c;GPU解码渲染技术是不可缺少的。 在视频会议系统中&#xff0c;经常需要同时观看会议中多个参会人员的视频图像&#xff0c;…

ALSA 用例配置

ALSA 用例配置。参考 ALSA 用例配置 来了解更详细信息。 ALSA 用例配置 用例配置文件使用 配置文件 语法来定义静态配置树。该树在运行时根据配置树中的条件和动态变量进行评估&#xff08;修改&#xff09;。使用 用例接口 API 解析结果并将其导出到应用程序。 配置目录和主…

LeetCode1143最长公共子序列

题目描述 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08…

贪心算法-数组跳跃游戏(mid)

目录 一、问题描述 二、解题思路 1.回溯法 2.贪心算法 三、代码实现 1.回溯法实现 2.贪心算法实现 四、刷题链接 一、问题描述 二、解题思路 1.回溯法 使用递归的方式&#xff0c;找到所有可能的走步方式&#xff0c;并记录递归深度&#xff08;也就是走步次数&#x…

Vue3_对接腾讯云COS_大文件分片上传和下载

目录 一、腾讯云后台配置 二、安装SDK 1.script 引入方式 2.webpack 引入方式 三、文件上传 1.new COS 实例 2.上传文件 四、文件下载 腾讯云官方文档&#xff1a; 腾讯云官方文档https://cloud.tencent.com/document/product/436/11459 一、腾讯云后台配置 1.登录 对…

成都跃享未来教育咨询有限公司,值得信赖!

在浩渺的教育咨询市场中&#xff0c;成都跃享未来教育咨询有限公司以其独特的魅力和卓越的服务质量&#xff0c;成为了行业内的璀璨明星。作为一家致力于为学生提供全方位教育咨询服务的公司&#xff0c;成都跃享未来教育咨询有限公司始终坚持安全可靠的原则&#xff0c;为广大…

【vue2新增页面跳转列表页,当前页面不会刷新问题,有效果的点个赞嗷】

文章目录 概要案例解决方法小结 概要 开发中遇到的罕有需求&#xff0c;一般来说切换路由页面就会重新渲染&#xff0c;相应接口也会自动刷新。但是有些需求新增页面是走路由的&#xff0c;关闭心中页会关闭当前面包屑&#xff0c;返回上一个&#xff0c;所以这时候由于之前列…

Proxyman 现代直观的 HTTP 调试代理应用程序

Proxyman 是一款现代而直观的 HTTP 调试代理应用程序&#xff0c;它的功能强大&#xff0c;使您可以轻松捕获、检查和操作 HTTP(s) 流量。不再让繁杂的网络调试工具阻碍您的工作&#xff0c;使用 Proxyman&#xff0c;您将轻松应对网络调试的挑战。 下载地址&#xff1a;https…

Allure在jenkins中无法显示的问题

jenkins中使用allure生成报告需要注意工作环境和路径的配置 前提条件&#xff1a; jenkins容器中已安装jdk和allure jenkins中配置全局工具环境&#xff1a; 项目中配置allure路径&#xff1a; 路径来源&#xff1a; Path需要选择相对路径的allure-report、allure-results

Mintegral解析休闲游戏如何靠创意素材吸引玩家

核心玩法简单清晰、容易让人无限上头的休闲游戏&#xff0c;玩法机制一般比较明确、简单&#xff0c;如果要在短时间内吸引玩家注意&#xff0c;除了完整展示游戏流程以外&#xff0c;开发者需要在素材中设置更多亮点性的内容&#xff0c;如吸睛的剧情、爆炸性的视听效果等元素…

033.搜索旋转排序数组

题意 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给方法之前&#xff0c;nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&…

暴雨推出基于英特尔® 至强® 6 能效核处理服务器

随着人工智能技术的快速发展&#xff0c;大模型的应用越来越广泛。据预测&#xff0c;到2024年年底&#xff0c;我国将有5%-8%的企业大模型参数从千亿级跃升至万亿级&#xff0c;算力需求增速将达到320%&#xff0c;这进一步推动了数据中心的持续变革。 超凡性能&#xff0c;绿…

WebGIS常用技术体系记录

1、数据下载 &#xff08;1&#xff09;OSM下载开源矢量数据&#xff0c;数据较全&#xff0c;但是质量一般&#xff1b; &#xff08;2&#xff09;地理空间数据云下载DEM影像&#xff1b; &#xff08;3&#xff09;datav下载行政区 http://datav.aliyun.com/tools/atlas/…

《十八岁出门远行》世界很小,案牍劳形;世界很大,日短心长

《十八岁出门远行》世界很小&#xff0c;案牍劳形&#xff1b;世界很大&#xff0c;日短心长 余华&#xff0c;作家&#xff0c;著有《在细雨中呼喊》《活着》《文城》《兄弟》等。 文章目录 《十八岁出门远行》世界很小&#xff0c;案牍劳形&#xff1b;世界很大&#xff0c;日…

黄金票据~

一. 黄金票据原理 黄金票据一般是伪造的TGT,生成这个TGT&#xff0c;不需要和KDC进行校验&#xff0c;金票可以在本地直接生成&#xff0c;生成的的金票在非域机器和域内机器都可以使用 黄金票据的作用&#xff1a; 可以用来权限维持 可以用来横向移动二. 利用条件 1. 必须…

C++基础与深度解析 | 类与面向对象编程 | 数据成员 | 成员函数 | 访问限定符与友元 | 构造、析构成员函数 | 字面值类、成员指针与bind交互

文章目录 一、结构体与对象聚合二、成员函数&#xff08;方法&#xff09;三、访问限定符与友元1.访问限定符2.友元&#xff08;慎用&#xff09; 四、构造、析构与复制成员函数1.构造函数2.析构函数3.补充 五、字面值类&#xff0c;成员指针与bind交互1.字面值类2.成员指针3.b…

【小白专用 已验证24.6.7】C# MySQL数据库访问操作封装类

一、底层库介绍 本文主要介绍数据库访问操作类&#xff0c;包含&#xff1a;SQL插入脚本、SQL查询脚本、数据库表是否存在判断、带参脚本执行、包含事务回滚脚本执行、存储过程脚本等等。 特殊说明 在使用之前&#xff0c;先安装 MySql.Data 插件 二、底层库源码 2.1 程序源…

android antirollback verno 获取方法

ReadRollbackIndex.exe 获取 调查avbVBMeta结构体 typedef struct AvbVBMetaImageHeader { /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ uint8_t magic[AVB_MAGIC_LEN]; /* 4: The major version of libavb required for this header. */ uint32_t…