嵌入式开发笔记:SPI通讯协议精讲——从片选配置到电夹爪实战
文章目录
- 嵌入式开发笔记:SPI通讯协议精讲——从片选配置到电夹爪实战
-
- @[toc]
- 1. 前言:为什么SPI是嵌入式开发者的必修课
- 2. SPI总线基础:四根线背后的故事
-
- 2.1 四根信号线
- 2.2 一主多从的拓扑结构
- 3. SPI的四种工作模式:CPOL与CPHA
-
- 3.1 CPOL:时钟极性
- 3.2 CPHA:时钟相位
- 3.3 四种模式组合
- 4. 片选(CS)配置:SPI的灵魂所在
-
- 4.1 CS的本质:低电平有效
- 4.2 硬件片选 vs 软件片选
- 4.3 CS的时序要求
- 5. 多从机场景下的片选方案设计
-
- 5.1 方案一:独立片选(推荐)
- 5.2 方案二:菊花链(Daisy Chain)
- 5.3 方案三:译码器扩展
- 6. 实战案例:电夹爪的SPI通信与控制
-
- 6.1 系统架构
- 6.2 通信协议设计
- 6.3 片选配置要点
- 6.4 代码示例
- 6.5 常见问题与排查
- 7. SPI调试心得:那些年踩过的坑
-
- 7.1 片选相关的坑
- 7.2 时钟相关的坑
- 7.3 调试工具推荐
- 8. 总结
- @[toc]
- 1. 前言:为什么SPI是嵌入式开发者的必修课
- 2. SPI总线基础:四根线背后的故事
-
- 2.1 四根信号线
- 2.2 一主多从的拓扑结构
- 3. SPI的四种工作模式:CPOL与CPHA
-
- 3.1 CPOL:时钟极性
- 3.2 CPHA:时钟相位
- 3.3 四种模式组合
- 4. 片选(CS)配置:SPI的灵魂所在
-
- 4.1 CS的本质:低电平有效
- 4.2 硬件片选 vs 软件片选
- 4.3 CS的时序要求
- 5. 多从机场景下的片选方案设计
-
- 5.1 方案一:独立片选(推荐)
- 5.2 方案二:菊花链(Daisy Chain)
- 5.3 方案三:译码器扩展
- 6. 实战案例:电夹爪的SPI通信与控制
-
- 6.1 系统架构
- 6.2 通信协议设计
- 6.3 片选配置要点
- 6.4 代码示例
- 6.5 常见问题与排查
- 7. SPI调试心得:那些年踩过的坑
-
- 7.1 片选相关的坑
- 7.2 时钟相关的坑
- 7.3 调试工具推荐
- 8. 总结
1. 前言:为什么SPI是嵌入式开发者的必修课
在嵌入式开发中,SPI(Serial Peripheral Interface)是最常用的高速同步串行通信协议之一。无论是Flash存储芯片、LCD显示屏、传感器模块,还是本文将要重点讲解的电夹爪,SPI都扮演着不可或缺的角色。
与I²C相比,SPI拥有更高的数据吞吐能力、更强的灵活性以及更低的协议复杂度。但正因为其灵活性,SPI的配置——尤其是片选(CS)信号的配置——往往成为新手工程师最容易栽跟头的地方。
本文将从一个实际项目视角出发,深入剖析SPI协议原理,重点讲解片选配置的种种细节,并以电夹爪控制为例,展示SPI在工业设备中的典型应用。 
2. SPI总线基础:四根线背后的故事
SPI是一种全双工、同步的串行通信协议,由Motorola公司首创。其通信采用主从模式,一个主设备(Master)可以控制一个或多个从设备(Slave)。
2.1 四根信号线
标准的SPI接口由以下四根线组成:
| SCK | Serial Clock | 主机输出 | 主设备生成的时钟信号,控制数据传输节奏 |
| MOSI | Master Out Slave In | 主机输出 | 主设备发送数据,从设备接收 |
| MISO | Master In Slave Out | 主机输入 | 从设备发送数据,主设备接收 |
| CS/SS | Chip Select / Slave Select | 主机输出 | 片选信号,用于激活某个从设备 |
SPI是全双工通信:在每个SCK周期,主设备向从设备发送一位数据的同时,也会接收从设备响应的一位数据。
2.2 一主多从的拓扑结构
在实际项目中,一个MCU往往需要连接多个SPI从设备。典型的一主多从拓扑如下:
- 共享总线:所有从设备并联SCK、MOSI、MISO三根线
- 独立片选:每个从设备有独立的CS引脚,由主设备分别控制
MCU (Master)
├── SCK ────────┬────────┬────────┐
├── MOSI ────────┼────────┼────────┤
├── MISO ◄───────┼────────┼────────┤
├── CS0 ────────► Flash │ │
├── CS1 ────────► LCD │ │
└── CS2 ────────► 电夹爪 │ │
SPI通信以CS线置低电平为开始信号,以CS线被拉高作为结束信号。当CS为高电平时,从设备与SPI总线断开连接,不响应任何通信。
3. SPI的四种工作模式:CPOL与CPHA
SPI的灵活性很大程度上体现在时钟极性(CPOL) 和时钟相位(CPHA) 这两个参数上。主设备和从设备必须工作在相同的模式下才能正常通信。
3.1 CPOL:时钟极性
CPOL决定SCK在空闲状态时的电平:
- CPOL = 0:SCK空闲时为低电平
- CPOL = 1:SCK空闲时为高电平
3.2 CPHA:时钟相位
CPHA决定数据在SCK的哪个边沿被采样:
- CPHA = 0:在SCK的第一个跳变沿采样数据
- CPHA = 1:在SCK的第二个跳变沿采样数据
3.3 四种模式组合
| 模式0 | 0 | 0 | 低电平 | 第一个边沿(上升沿) |
| 模式1 | 0 | 1 | 低电平 | 第二个边沿(下降沿) |
| 模式2 | 1 | 0 | 高电平 | 第一个边沿(下降沿) |
| 模式3 | 1 | 1 | 高电平 | 第二个边沿(上升沿) |
实际工程中,模式0和模式3最为常用。具体用哪种模式,必须查阅从设备的数据手册。
📌 配图位置:建议在此处插入一张“SPI四种模式时序对比图”。
4. 片选(CS)配置:SPI的灵魂所在
如果说SPI的四根线是一支乐队,那么CS就是指挥家——它决定了什么时候开始演奏、什么时候停止。片选配置不当,是整个SPI通信中最常见的故障根源。
4.1 CS的本质:低电平有效
SPI的CS信号通常是低电平有效:
- CS = 低电平:从设备被选中,开始响应SPI通信
- CS = 高电平:从设备未被选中,与总线断开
关键点:当从设备未被选中时,其MISO引脚必须设置为高阻态,否则会与总线上其他设备产生冲突。
4.2 硬件片选 vs 软件片选
片选控制方式分为两种:
| 硬件片选 | 由SPI外设硬件自动控制CS | CPU负担小,时序精准 | 灵活性差,部分MCU硬件CS有BUG |
| 软件片选 | 由代码通过GPIO手动拉高/拉低CS | 灵活可控,易于调试 | 占用CPU时间 |
硬件片选的“坑” :有些MCU的SPI硬件CS在TX FIFO为空时会自动拉高,这会导致多字节连续传输时CS在帧间隙被意外释放。遇到这种情况,果断改用软件片选是最直接的解决方案。
软件片选的实现(以STM32 HAL库为例):
// 片选拉低(选中从设备)
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
// SPI数据传输
HAL_SPI_TransmitReceive(&hspi, tx_data, rx_data, length, timeout);
// 片选拉高(释放从设备)
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
💡 工程建议:在实际项目中,优先使用软件片选。虽然多写几行代码,但能避免很多硬件片选带来的时序问题,调试起来也更加直观。
4.3 CS的时序要求
不同从设备对CS的时序要求不同,通常需要关注:
- 建立时间:CS拉低到第一个SCK时钟到来之间的时间(通常>10ns)
- 保持时间:最后一个SCK时钟到CS拉高之间的时间(通常>20ns)
- CS释放延时:两次通信之间CS保持高电平的时间
调试技巧:用示波器或逻辑分析仪抓取CS、SCK、MOSI、MISO的波形,是排查SPI问题最有效的手段。
5. 多从机场景下的片选方案设计
当需要连接多个SPI从设备时,片选方案的设计就变得至关重要。
5.1 方案一:独立片选(推荐)
每个从设备分配一个独立的GPIO作为CS引脚。
优点:
- 时序清晰,各从设备互不干扰
- 响应迅速,实时性好
- 调试方便,可单独控制每个设备
缺点:
- 占用较多的GPIO引脚
- 当从设备数量很多时,GPIO可能不够用
代码示例(STM32):
// SPI外设的MOSI、MISO、SCK正常使用
// 片选改用GPIO控制
#define CS_SLAVE1_PIN GPIO_PIN_1
#define CS_SLAVE1_PORT GPIOC
#define CS_SLAVE2_PIN GPIO_PIN_2
#define CS_SLAVE2_PORT GPIOC
// 选中从设备1
HAL_GPIO_WritePin(CS_SLAVE1_PORT, CS_SLAVE1_PIN, GPIO_PIN_RESET);
// 通信…
HAL_GPIO_WritePin(CS_SLAVE1_PORT, CS_SLAVE1_PIN, GPIO_PIN_SET);
5.2 方案二:菊花链(Daisy Chain)
所有从设备的CS连接在一起,数据从一个从设备串行传递到下一个。
优点:节省GPIO资源
缺点:
- 协议复杂,需要从设备支持菊花链模式
- 延迟累积,通信效率降低
- 一个设备故障会影响整个链路
适用场景:从设备数量多、GPIO资源紧张、且从设备本身支持菊花链的情况。
5.3 方案三:译码器扩展
当GPIO实在不够用时,可以使用3-8译码器(如74HC138)来扩展片选信号。
3个GPIO → 74HC138 → 8路CS输出
适用场景:从设备数量多(>5个)、且对实时性要求不极端苛刻的系统。
6. 实战案例:电夹爪的SPI通信与控制
电夹爪(电动夹爪)是工业自动化和机器人领域常见的末端执行器。现代电夹爪通常集成了无刷伺服系统、高精度力传感器,支持精密力、位混合控制。而SPI正是其内部控制器与主控MCU之间常用的通信方式之一。
6.1 系统架构
典型的电夹爪SPI控制系统架构如下:
主控MCU (Master)
│
├── SCK ────► 电夹爪控制器 (Slave)
├── MOSI ───► 电夹爪控制器
├── MISO ◄─── 电夹爪控制器
└── CS ────► 电夹爪控制器 (独立片选)
│
├── 电机驱动 (位置/速度/力矩控制)
├── 力传感器 (夹持力反馈)
└── 位置传感器 (开合位置反馈)
6.2 通信协议设计
电夹爪的SPI通信通常采用命令-响应模式,主控发送指令帧,电夹爪返回状态帧。
典型指令格式:
| Byte 0 | 命令码 | 如0x01=打开、0x02=闭合、0x03=设置夹持力 |
| Byte 1 | 数据高字节 | 参数值 |
| Byte 2 | 数据低字节 | 参数值 |
| Byte 3 | 校验和 | 简单校验或CRC |
典型响应格式:
| Byte 0 | 状态码 | 0x00=成功、0x01=忙、0x02=错误 |
| Byte 1 | 当前位置高字节 | 夹爪开合位置反馈 |
| Byte 2 | 当前位置低字节 | |
| Byte 3 | 当前夹持力 | 力传感器反馈值 |
6.3 片选配置要点
在电夹爪的SPI通信中,片选配置尤为关键:
6.4 代码示例
// 电夹爪SPI通信示例(STM32 HAL库)
#define CLAW_CS_PORT GPIOC
#define CLAW_CS_PIN GPIO_PIN_1
// 发送指令并读取响应
uint8_t claw_send_command(uint8_t cmd, uint16_t param, uint8_t *response, uint8_t resp_len)
{
uint8_t tx_buf[4];
uint8_t rx_buf[4];
// 组装指令
tx_buf[0] = cmd;
tx_buf[1] = (param >> 8) & 0xFF;
tx_buf[2] = param & 0xFF;
tx_buf[3] = cmd + tx_buf[1] + tx_buf[2]; // 简单校验
// 软件片选:拉低CS,选中电夹爪
HAL_GPIO_WritePin(CLAW_CS_PORT, CLAW_CS_PIN, GPIO_PIN_RESET);
// 等待一小段时间满足CS建立时间
delay_us(10);
// SPI收发数据
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 4, 100);
// 软件片选:拉高CS,释放电夹爪
HAL_GPIO_WritePin(CLAW_CS_PORT, CLAW_CS_PIN, GPIO_PIN_SET);
// 复制响应数据
if (response && resp_len > 0) {
memcpy(response, rx_buf, (resp_len < 4) ? resp_len : 4);
}
return rx_buf[0]; // 返回状态码
}
// 控制电夹爪闭合(带夹持力设置)
uint8_t claw_close(uint16_t force)
{
return claw_send_command(0x02, force, NULL, 0);
}
// 读取电夹爪状态
uint8_t claw_get_status(uint16_t *position, uint8_t *force)
{
uint8_t response[4];
uint8_t status = claw_send_command(0x04, 0, response, 4);
if (status == 0x00) {
*position = (response[1] << 8) | response[2];
*force = response[3];
}
return status;
}
6.5 常见问题与排查
| 电夹爪无响应 | CS未正确拉低 | 检查GPIO配置和电平 |
| 数据错乱 | SPI模式不匹配 | 核对CPOL/CPHA是否与电夹爪手册一致 |
| 通信不稳定 | 时钟频率过高 | 降低SCK频率 |
| CS无法释放 | 硬件片选自动控制 | 改用软件片选 |
7. SPI调试心得:那些年踩过的坑
在多年的嵌入式开发中,SPI调试积累了一些“血泪经验”,分享给大家:
7.1 片选相关的坑
CS拉低后立即发数据:有些从设备需要CS拉低后等待一段时间才能接收数据。务必查阅数据手册的建立时间(t_setup) 参数。
多从机共用总线时MISO冲突:当某个从设备未被选中时,其MISO必须为高阻态。如果从设备不支持三态门,需要在硬件上加缓冲器隔离。
硬件片选自动释放:部分MCU的硬件CS在数据发送完成后会自动拉高,导致需要CS持续低电平的多字节操作失败。解决方案:改用软件片选。
7.2 时钟相关的坑
模式不匹配:主从设备的CPOL/CPHA必须一致。用示波器看SCK的空闲电平,一眼就能判断CPOL是否正确。
时钟频率过高:SPI时钟频率受限于最慢的从设备。不要以为MCU能跑多快就设多快。
7.3 调试工具推荐
- 逻辑分析仪:查看CS、SCK、MOSI、MISO的完整时序,是SPI调试的“眼睛”
- 示波器:观察信号质量(上升沿、下降沿、毛刺)
- 环回测试:将MOSI与MISO短接,自发自收,验证SPI硬件是否正常
8. 总结
SPI协议虽然只有四根线,但其中的门道却不少。本文从SPI的基础原理出发,重点讲解了片选(CS)信号的配置与管理,这是SPI通信中最关键也最容易出问题的环节。
核心要点回顾:
SPI的配置看起来简单,但每一个细节——从CS的拉低时机到SCK的空闲电平——都可能影响通信的成败。希望本文能帮助你在实际项目中少走弯路,让SPI通信“一次成功”。
📚 参考资料
- CiA DS402 CANopen驱动与运动控制设备行规
- SPI协议标准文档(Motorola)
- 各品牌MCU参考手册与电夹爪产品数据手册
本文为嵌入式开发笔记系列文章,如有疑问或建议,欢迎在评论区留言讨论。



