在嵌入式系统的通信协议中,SPI协议凭借其高速、简单的特性,成为连接微控制器与外设的“常客”。无论是传感器、显示屏还是存储芯片,很多都依赖SPI协议实现数据交互。今天,我们就来深入拆解SPI协议的工作原理、通信过程及实际应用,帮你搞懂这个嵌入式开发中的“高频考点”。

SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行通信协议,由摩托罗拉公司提出,主要用于短距离、高速率的芯片间通信。它采用“主从架构”,即一个主设备(通常是MCU,如STM32、Arduino)可以连接多个从设备(如OLED屏、ADC芯片、Flash等),主设备通过时钟信号同步控制数据传输,无需额外的地址线,硬件结构相对简单。
SPI协议的通信依靠4根信号线实现,记住它们的功能,就能理解数据是如何“跑”起来的:
1. SCLK(Serial Clock):时钟线
由主设备产生,用于同步主从设备的数据传输节奏。时钟频率决定了通信速度,不同外设支持的最高时钟频率不同(如有的传感器支持1MHz,有的Flash可达50MHz),需根据外设手册配置。
2. MOSI(Master Out Slave In):主发从收线
主设备通过这条线向从设备发送数据。
3. MISO(Master In Slave Out):主收从发线
从设备通过这条线向主设备返回数据。
4. SS(Slave Select):从设备选择线
也称CS(Chip Select),由主设备控制,低电平(通常)表示选中该从设备。多个从设备时,需为每个从设备分配独立的SS线,或通过硬件/软件方式共享。

SPI的核心是“同步传输”,主设备通过SCLK时钟信号控制数据在MOSI和MISO线上的传输,每次时钟脉冲对应1位数据的发送和接收,且主从设备同时收发数据(全双工)。
关键时序参数需注意:
- CPOL(Clock Polarity):时钟极性
定义SCLK在空闲状态(无数据传输)时的电平。CPOL=0时,空闲状态为低电平;CPOL=1时,空闲状态为高电平。
- CPHA(Clock Phase):时钟相位
定义数据采样的时刻。CPHA=0时,在SCLK的第一个跳变沿(上升沿或下降沿,由CPOL决定)采样数据;CPHA=1时,在第二个跳变沿采样。
根据CPOL和CPHA的组合,SPI有4种工作模式(Mode 0~3),实际应用中需根据外设手册选择匹配的模式,否则会出现数据错误。
举个最常用的Mode 0(CPOL=0,CPHA=0)为例:
- 空闲时SCLK为低电平;
- 数据在SCLK的上升沿被从设备采样(主设备在下降沿发送数据),下降沿时主设备采样从设备返回的数据。

当主设备连接多个从设备时,通过SS线的高低电平来选择目标从设备:
- 主设备想与某个从设备通信时,将该设备的SS线拉低,其他从设备的SS线保持高电平(不工作);
- 通信过程中,只有被选中的从设备会响应主设备的指令,避免数据冲突。
硬件连接上,多个从设备的MOSI、MISO、SCLK线可并联,仅SS线独立连接到主设备的不同GPIO口,简化电路设计。

优点:
1. 高速率:相比I2C,SPI时钟频率更高(可达几十MHz甚至上百MHz),适合大数据量传输(如显示屏刷新);
2. 全双工:主从设备可同时收发数据,效率高;
3. 硬件简单:无需地址线,仅需4根线(多从设备时增加SS线);
4. 协议灵活:支持多种工作模式,适配不同外设。
缺点:
1. 主从架构固定:从设备无法主动发起通信,只能被动响应主设备;
2. 信号线较多:相比I2C(仅需2根线),多从设备时SS线会占用更多GPIO;
3. 无内置纠错机制:需软件实现数据校验(如CRC),确保传输可靠性。
因此,SPI适合短距离、高速、全双工的场景,如连接Flash、摄像头、触摸屏等外设;而对布线空间敏感、速率要求不高的场景(如传感器组网),I2C可能更合适。
以STM32为例,使用HAL库配置SPI通信的大致步骤:
1. 初始化GPIO:配置SCLK、MOSI、MISO为复用功能,SS线为推挽输出;
2. 初始化SPI外设:设置工作模式(CPOL、CPHA)、时钟频率、数据位数(通常8位)、MSB/LSB优先(高位在前或低位在前);
3. 发送数据:通过 HAL_SPI_Trans mit() 发送指令或数据;
4. 接收数据:通过 HAL_SPI_Receive() 接收从设备返回的数据;
5. 全双工通信:使用 HAL_SPI_Trans mitReceive() 同时收发数据。
示例伪代码(简化版):
// 初始化SPI
HAL_SPI_Init(&hspi1);
// 选中从设备(拉低SS线)
HAL_GPIO_WritePin(SS_GPIO_Port, SS_Pin, GPIO_PIN_RESET);
// 发送数据(如向传感器写入指令)
uint8_t cmd = 0x01;
HAL_SPI_Trans mit(&hspi1, &cmd, 1, 100);
// 接收数据(读取传感器返回值)
uint8_t data;
HAL_SPI_Receive(&hspi1, &data, 1, 100);
// 取消选中(拉高SS线)
HAL_GPIO_WritePin(SS_GPIO_Port, SS_Pin, GPIO_PIN_SET);
SPI协议以其高速、灵活的特点,在嵌入式系统中应用广泛。掌握其硬件连接、时序模式和多从设备通信逻辑,是实现外设驱动的基础。实际开发中,需结合外设手册配置正确的参数,必要时通过逻辑分析仪抓取时序波形,排查通信问题。
希望这篇分析能帮你理清SPI的核心知识点,下次调试SPI设备时,不妨从时序模式和SS线控制入手,或许能快速定位问题。