资讯动态

25. 嵌入式通信基石:SPI协议工作原理、模式选择与CW32F030硬件SPI应用详解

发布时间:2026/8/3 14:14:25 来源:尧图企业网站定制
嵌入式通信基石SPI协议工作原理、模式选择与CW32F030硬件SPI应用详解大家好我是地文星。最近在项目里用CW32F030驱动一个SPI接口的OLED屏和一个Flash芯片发现很多刚开始接触嵌入式通信的朋友对SPI协议有点“发怵”特别是那四种工作模式经常搞混。今天我就结合CW32F030这款MCU的硬件SPI带大家彻底搞懂SPI。咱们不堆砌术语就从一个工程师的实际使用角度聊聊SPI到底是什么、怎么配、怎么用。1. SPI到底是什么一主多从的“同步对话”咱们先从最根本的说起。SPI全称Serial Peripheral Interface翻译过来就是“串行外设接口”。它是一种同步、串行的通信协议。你可以把它想象成两个人主设备和从设备在打电话而且这个电话很高级允许双方同时说话全双工。核心角色主设备 (Master)通常是咱们的微控制器比如CW32F030。它是对话的发起者和节奏控制者负责产生时钟信号决定什么时候开始和结束通信。从设备 (Slave)比如传感器、存储器Flash、显示屏驱动芯片等。它们被动等待主设备的“呼叫”然后根据主设备的时钟节奏来收发数据。一个主设备可以“呼叫”多个从设备这就是“一主多从”。想象一下主设备是一个项目经理他可以通过点名片选信号来和不同的组员从设备单独开会。通信过程打个比方假设主设备MCU想读取从设备传感器的数据同时也要给它发个命令。主设备先“点名”拉低对应从设备的片选线CS说“小王传感器现在开始跟我对话。”主设备开始有节奏地拍桌子产生时钟SCLK一拍一下。在第一拍主设备通过MOSI线把自己要发的命令一个比特位告诉从设备同时从设备也通过MISO线把自己要发的数据一个比特位告诉主设备。如此反复一拍传一位直到一个字节通常8位或者更长的数据传完。主设备“散会”拉高片选线CS对话结束。关键点因为发送MOSI和接收MISO是两条独立的线所以主从设备可以同时收发数据这就是“全双工”。效率很高。2. SPI的“四线制”硬件接口SPI通信最少需要4根线这也是它最经典的模式。咱们用一张表来清晰说明信号线常见别称方向主设备视角说明SCLKSCK, CLK输出时钟线。由主设备产生是所有数据收发的节奏基准。就像乐队的指挥大家都要跟着它的拍子走。MOSISDO, DO, SI输出主设备输出从设备输入。主设备通过这根线把数据发送给从设备。MISOSDI, DI, SO输入主设备输入从设备输出。主设备通过这根线接收从设备发来的数据。CSNSS, SS输出片选线。主设备通过控制这根线的电平通常是拉低有效来选中要和它通信的特定从设备。每个从设备都需要独占一根CS线连接到主设备。注意有些器件为了节省引脚会使用“三线制”比如只有SCLK, CS和一根双向数据线或者“两线制”比如只有时钟和数据依靠特定协议寻址。但理解“四线制”是掌握SPI的基础。3. SPI的四种工作模式时钟极性与相位这是SPI最让人困惑也最关键的地方。模式选择不对通信绝对失败。别怕咱们拆开看。模式由两个参数决定时钟极性 (CPOL或CKPL)和时钟相位 (CPHA或CKPH)。时钟极性 (CPOL)它定义的是时钟线SCLK在空闲状态即没有传输数据时的电平。CPOL 0空闲时SCLK是低电平。CPOL 1空闲时SCLK是高电平。时钟相位 (CPHA)它定义的是数据在时钟的哪个边沿被采样读取在哪个边沿被更新切换。CPHA 0数据在第一个时钟边沿被采样在第二个边沿更新。CPHA 1数据在第二个时钟边沿被采样在第一个边沿更新。把这两个参数组合起来就得到了4种模式模式0-3。我习惯这样记模式0 (CPOL0, CPHA0)空闲时时钟为低。数据在时钟上升沿被采样因为第一个边沿是从低到高的上升沿。这是最常用的模式之一。模式1 (CPOL0, CPHA1)空闲时时钟为低。数据在时钟下降沿被采样第二个边沿是从高到低的下降沿。模式2 (CPOL1, CPHA0)空闲时时钟为高。数据在时钟下降沿被采样第一个边沿是从高到低的下降沿。模式3 (CPOL1, CPHA1)空闲时时钟为高。数据在时钟上升沿被采样第二个边沿是从低到高的上升沿。这也是非常常用的模式。怎么选模式完全取决于你的从设备在从设备的数据手册Datasheet里一定会写明它支持哪种SPI模式。比如我用的那个SPI Flash芯片就要求用模式0或模式3。如果手册没写可以优先尝试模式0或模式3。4. CW32F030的硬件SPI外设实战理解了原理咱们上手实操。CW32F030内置的硬件SPI外设功能挺全的能帮我们省去用GPIO模拟时序软件SPI的麻烦效率和稳定性都好很多。4.1 主要特性一览根据资料CW32F030的SPI支持以下特性咱们挑重点说主/从模式既可以当主机发号施令也可以当从机听令行事。多种通信模式支持标准的全双工也支持单线半双工省一根线和单工。数据帧灵活数据长度可以是4位到16位不只是8位。数据位序先传最高位MSB还是最低位LSB也可以设置。时钟可配置CPOL和CPHA自由配置支持上述所有4种模式。速度够快当主机时最高速度可以达到系统外设时钟PCLK的一半。多主机支持多个MCU的SPI可以组网。支持DMA这个太有用了传输大量数据时比如刷屏、读写大块Flash可以让DMA来搬运数据CPU解放出来干别的活效率倍增。丰富的中断收发完成、错误等都有中断标志方便事件驱动编程。4.2 基础配置步骤主机模式全双工假设我们要把CW32F030配置为SPI主机以模式0CPOL0 CPHA0与一个从设备通信。以标准库函数为例步骤一般是这样的第一步开启时钟任何外设使用前必须先给它“上电”也就是开启对应的时钟。RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_SPI1, ENABLE); // 使能SPI1的时钟 // 同时也要开启对应GPIO端口的时钟例如SPI1的引脚可能在PA5, PA6, PA7 RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOA, ENABLE);第二步配置SPI所用到的GPIO引脚把对应的GPIO引脚设置为复用功能并配置好上下拉和速度。GPIO_InitTypeDef GPIO_InitStructure; // 以SPI1为例PA5-SCK, PA6-MISO, PA7-MOSI GPIO_InitStructure.Pin GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStructure.Mode GPIO_MODE_AF_PP; // 复用推挽输出 GPIO_InitStructure.Pull GPIO_PULLUP; // 上拉增强驱动根据实际需要调整 GPIO_InitStructure.Speed GPIO_SPEED_HIGH; // 高速SPI通信通常要求较高 GPIO_Init(GPIOA, GPIO_InitStructure); // 片选CS引脚通常用普通GPIO手动控制这里配置一个GPIO例如PA4为输出 GPIO_InitStructure.Pin GPIO_PIN_4; GPIO_InitStructure.Mode GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStructure.Pull GPIO_PULLUP; GPIO_InitStructure.Speed GPIO_SPEED_HIGH; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_PIN_4); // 初始化为高电平不选中第三步配置SPI外设参数这是核心设置工作模式、数据格式、速率等。SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.Direction SPI_DIRECTION_2LINES_FULLDUPLEX; // 双线全双工 SPI_InitStructure.Mode SPI_MODE_MASTER; // 主机模式 SPI_InitStructure.DataSize SPI_DATASIZE_8BIT; // 数据帧8位 SPI_InitStructure.CLKPolarity SPI_POLARITY_LOW; // CPOL0空闲时钟低电平 SPI_InitStructure.CLKPhase SPI_PHASE_1EDGE; // CPHA0第一个边沿采样 // 注意不同库对CPHA的定义可能不同需查手册。这里“1EDGE”通常对应CPHA0。 SPI_InitStructure.BaudRatePrescaler SPI_BAUDRATEPRESCALER_32; // 波特率预分频决定SCLK速度 SPI_InitStructure.FirstBit SPI_FIRSTBIT_MSB; // 数据传输从最高位(MSB)开始 SPI_InitStructure.CRCCalculation SPI_CRCCALCULATION_DISABLE; // 禁用CRC校验通常不用 SPI_InitStructure.CRCPolynomial 7; // 如果启用CRC设置多项式 SPI_Init(SPI1, SPI_InitStructure);提示BaudRatePrescaler波特率预分频器是关键它决定了SCLK的频率。SCLK频率 PCLK / 预分频值。比如PCLK是48MHz预分频选32那么SCLK就是1.5MHz。一定要确保这个频率不超过从设备支持的最高频率。第四步使能SPI外设SPI_Cmd(SPI1, ENABLE);4.3 编写收发函数配置好后就可以进行数据收发了。一个基础的阻塞式发送接收函数如下// 函数通过SPI1交换一个字节同时发送和接收 uint8_t SPI1_ReadWriteByte(uint8_t TxData) { // 等待发送缓冲区为空表示可以写入新的数据 while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) RESET); // 写入要发送的数据这会自动启动一次传输 SPI_SendData(SPI1, TxData); // 等待接收缓冲区非空表示数据已经接收回来 while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) RESET); // 读取接收到的数据 return SPI_ReceiveData(SPI1); } // 使用示例发送命令0x9F读取器件ID并接收3个字节的ID uint8_t id_buf[3]; SPI_CS_LOW(); // 拉低片选选中从设备 SPI1_ReadWriteByte(0x9F); // 发送命令 id_buf[0] SPI1_ReadWriteByte(0xFF); // 发送哑元数据0xFF同时接收第一个ID字节 id_buf[1] SPI1_ReadWriteByte(0xFF); // 接收第二个ID字节 id_buf[2] SPI1_ReadWriteByte(0xFF); // 接收第三个ID字节 SPI_CS_HIGH(); // 拉高片选释放从设备注意SPI是全双工主设备发送的同时也在接收。所以即使你只想读数据也必须发送点东西通常是0xFF或0x00称为“哑元”数据来产生时钟从设备才能把数据“推”到MISO线上。4.4 进阶使用DMA进行高效传输当你需要连续发送一大块数据比如更新显示屏的帧缓冲区时用上面的循环一个个字节发效率太低CPU会被完全占用。这时就该DMA出场了。DMA配置思路配置DMA通道将内存地址你的数据数组设置为源地址对于发送或目标地址对于接收将SPI的数据寄存器地址设置为目标地址对于发送或源地址对于接收。设置传输的数据量。使能SPI的DMA发送和/或接收请求。启动DMA传输。等待DMA传输完成中断或查询标志位。使用DMA后CPU只需要启动传输就可以去处理其他任务等DMA传输完成产生中断时再来处理后续工作即可大大提升了系统效率。具体寄存器或库函数的配置需要参考CW32F030的官方库和例程。5. SPI的优缺点与应用场景最后咱们客观总结一下SPI方便你在项目中选型。优势速度快因为是全双工、点对点、协议简单所以可以达到很高的时钟频率几十MHz很常见。协议简单没有像I2C那样的地址、起始停止位、ACK应答等复杂信号实现和调试都相对容易。灵活性高数据帧长度、位序、时钟模式都可调适应不同器件。劣势占用引脚多每个从设备都需要一根独立的片选线当从设备很多时会占用大量主设备的GPIO。没有硬件流控/应答主设备无法知道从设备是否真的收到了数据除非在应用层自己定义应答协议。通信距离短通常用于板级设备间通信不适合长距离传输。典型应用场景存储器SPI Flash如W25Q系列、SD卡SPI模式。传感器很多数字传感器如气压计BMP280、IMU等提供SPI接口。显示屏小尺寸的OLED、TFT屏常用SPI接口驱动。无线模块如NRF24L01、ESP8266/32SPI接口固件下载与通信。音频编解码器、数字电位器等。希望这篇结合了原理和CW32F030实战的文章能帮你把SPI协议理顺。记住关键四根线、主从同步、模式看从设备手册。多动手写代码、调时序遇到问题用逻辑分析仪抓一下波形对照时序图看很快就能掌握。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价