news 2026/7/19 8:29:08

SPI通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SPI通信

1.SPI通信简介

SCK:串行时钟线

MOSI:主机输出、从机输入(主机向从机发送数据)

MISO:主机输入、从机输出(主机从从机接收数据)

SS:从机选择(从机寻址)

2.SPI硬件电路

SS线都是低电平有效的,同一时间只有一条SS线能被置低电平(即同一时间只能选中一个从机)

当从机被选中时(即SS线被置低电平时),MISO才会是推挽输出,否则会被设置成高阻态(被断开)

3.SPI时序基本单元

1.起始和发送

就是起始就是选择从机,结束从机选中状态

2.收发数据时序(模式功能都一样)

1.模式0

MISO初始时为高阻态,结束时要重新配置为高阻态

数据提前移出和移入(MOSI在第0个边沿移出,在第1个边沿移入)

原因:数据要先移出才能移入

2.模式1

MISO初始时为高阻态,结束时要重新配置为高阻态

3.模式2

MISO初始时为高阻态,结束时要重新配置为高阻态

4.模式3

MISO初始时为高阻态,结束时要重新配置为高阻态

3.收发SPI时序格式(以芯片W25Q64作为参考)

基本格式:起始+指令码(读写等功能)+数据将被写入的地址+数据

4.基本配置格式(手动实现时序)

//从机选择(写SS的引脚) void MySPI_W_SS(uint8_t BitValue) { GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue); } //时钟线 void MySPI_W_SCK(uint8_t BitValue) { GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue); } //主机将数据写入从机(发送) void MySPI_W_MOSI(uint8_t BitValue) { GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue); } //主机接收从机数据(接收) uint8_t MySPI_R_MISO(void) { return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6); } //初始化 void MySPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //将SCK、MOSI、SS配置成推挽输出 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将主机输入、从机输出的MISO配置成上拉输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //置默认电平 MySPI_W_SS(1); MySPI_W_SCK(0); } //起始时序 void MySPI_Start(void) { MySPI_W_SS(0); } //终止时序 void MySPI_Stop(void) { MySPI_W_SS(1); } //交换一个字节(模式0收发数据) //注意:从机的操作是从机自动进行的,软件代码只需管主机 //方法一:使用掩码,取出每一位数据进行操作 uint8_t MySPI_SwapByte(uint8_t ByteSend) { uint8_t i, ByteReceive = 0x00; for (i = 0; i < 8; i ++) { MySPI_W_MOSI(!!(ByteSend & (0x80 >> i))); MySPI_W_SCK(1); if (MySPI_R_MISO()){ByteReceive |= (0x80 >> i);} MySPI_W_SCK(0); } return ByteReceive; } //方法二:将数据本身进行移位,相当于将主机数据一位一位移出再一位一位移入从机数据 //uint8_t MySPI_SwapByte(uint8_t ByteSend) //{ // uint8_t i; // // for (i = 0; i < 8; i ++) // { // MySPI_W_MOSI(!!(ByteSend & 0x80); // ByteSend<<=1; // MySPI_W_SCK(1); // if (MySPI_R_MISO()){ByteSend |= 0x01;} // MySPI_W_SCK(0); // } // // return ByteSend; //}

4.硬件实现SPI通信(STM32内部的SPI外设)

1.SPI外设简介

注意:SPI1挂载在APB2,PCLK是72MHz;而SPI2挂载在APB1,PCLK是36MHz

2.STM32中SPI外设的内部结构图

LSBFIRST:帧格式,可以选择数据是低位先行还是高位先行(给0,先发送MSB即高位先行;给1,先发送LSB即低位先行)

TXE:发送寄存器空

RXNE:接受寄存器非空

NSS:从机选择(低电平有效) 当SSOE置1时,NSS配置成输出(即成为主机);当SSOE清0后,NSS变为输入(即成为从机)

3.SPI基本结构图

4.硬件SPI的操作流程

1.主模式全双工连续传输(效率高)

示例为模式三

发送数据解释:开始时TXE=1表示发送寄存器空,TXE为0时,数据进入发送寄存器;TXE再次为1时,数据由发送寄存器进入移位寄存器,同时下一个数据紧接着进入发送寄存器

接收数据解释:开始时RXNE=0表示接受寄存器空,RXNE为1时,数据由移位寄存器进入接受寄存器,完成后清除RXNE(即直接置0)

这种数据传输模式是交叉的,并不是发送一个数据后马上接收此数据

2.非连续传输

基本逻辑:发送一个数据,然后等待此数据被接收,最后发送下一个字节。

注意:相较主模式全双工连续传输传输速度明显更慢

3.硬件SPI的实战代码

1.部分函数功能
//写DR数据寄存器 void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); //读DR数据寄存器 uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
2.配置思路
1.RCC开启时钟(把SPI外设和对应的GPIO口的时钟打开)
2.配置GPIO(SCK、MOSI配置成复用推挽输出模式。MISO配置成上拉输入模式,SS配置成通用推挽输出)
3.配置SPI外设
4.开启SPI(使能)
3.基本配置格式(使用库函数实现时序)
//从机选择 void MySPI_W_SS(uint8_t BitValue) { GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue); } //初始化 void MySPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //SPI1是APB2上的外设 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //开启SS从机选择时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //SCK和MOSI复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //MISO上拉输入模式 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //SPI初始化 SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//SPI模式,决定SPI是主机还是从机 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//数据传输模式(此处为双线全双工) SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位数据帧 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位先行 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//128分频(SPI1外设72/128) //配置模式(模式0、1、2、3) SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//选择NSS模式(硬件NSS或软件NSS,此处为软件NSS) SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); MySPI_W_SS(1); } //起始时序 void MySPI_Start(void) { MySPI_W_SS(0); } //终止时序 void MySPI_Stop(void) { MySPI_W_SS(1); } //交换一个字节 uint8_t MySPI_SwapByte(uint8_t ByteSend) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);//等待TXE SPI_I2S_SendData(SPI1, ByteSend);//将数据写入DR while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);//等待RNXE return SPI_I2S_ReceiveData(SPI1);//将DR中的数据读出 }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 22:11:34

7、Docker 镜像构建、注册与存储全解析

Docker 镜像构建、注册与存储全解析 1. 引言 在容器化技术的世界里,Docker 无疑是一颗耀眼的明星。它为开发者和运维人员提供了便捷的应用打包、部署和管理方式。本文将深入探讨 Docker 镜像的构建、存储和分发,以及 Docker 卷的使用,帮助你更好地掌握 Docker 技术。 2. …

作者头像 李华
网站建设 2026/7/18 11:16:20

Python语法基础笔记(四)

一、类型转换int &#xff08;&#xff09;&#xff1a;转换为一个整数&#xff0c;只能转换由纯数字组成的字符串float->int : 会去掉小数点及后面的阿数值&#xff0c;只保留整数部分str-> int : 如果字符串中有数字和正负号&#xff08;-&#xff09;以外的字符就会报…

作者头像 李华
网站建设 2026/7/18 3:20:54

13、找回丢失文件的实用方法

找回丢失文件的实用方法 在日常使用计算机的过程中,我们经常会遇到找不到特定文件的情况。由于文件可能存储在多个位置,手动搜索多个目录会非常耗时。不过,系统提供了一些实用工具来帮助我们快速定位丢失的文件。下面将详细介绍这些工具及其使用方法。 1. find 命令 find…

作者头像 李华
网站建设 2026/7/19 6:35:34

14、Linux 用户与用户组管理全解析

Linux 用户与用户组管理全解析 1. 管理基础与 root 账户 在 Linux 系统中,安装完成后默认仅创建了 root 账户,这是唯一可直接访问系统的账户。为了让其他用户也能使用系统,管理员需要为他们创建新的账户。 root 账户也被称为超级用户,拥有系统的最高权限,可以对任何文件…

作者头像 李华
网站建设 2026/7/14 18:09:13

30亿参数撬动87%成本下降:ERNIE 4.5 VL重塑多模态AI产业格局

30亿参数撬动87%成本下降&#xff1a;ERNIE 4.5 VL重塑多模态AI产业格局 【免费下载链接】ERNIE-4.5-VL-28B-A3B-Paddle 项目地址: https://ai.gitcode.com/hf_mirrors/baidu/ERNIE-4.5-VL-28B-A3B-Paddle 导语 百度ERNIE 4.5 VL多模态大模型以280亿总参数、仅激活30亿…

作者头像 李华