第三章 I2C/SPI总线实战:时序分析、多设备挂载、速率优化、常见故障排查
各位同学,今天我们来聊聊嵌入式开发中最常用的两种总线——I2C和SPI。说实话,我见过太多工程师在这上面栽跟头了。我自己刚入行那会儿,也曾经被一个I2C的ACK信号折磨了整整三天。嗯,今天就把这些经验一次性讲透。
3.1 时序分析:别被示波器骗了
先说说I2C的时序。I2C总线就两根线:SCL(时钟)和SDA(数据)。但别小看这两根线,里面的门道可不少。
I2C的起始条件和停止条件:
- 起始条件:SCL高电平时,SDA从高变低
- 停止条件:SCL高电平时,SDA从低变高
- 数据采样:SCL低电平时改变SDA,高电平时采样
关键点:我见过有人把起始和停止条件搞反了,结果总线一直卡在某个状态。记住一个口诀——「高时变,低时稳」。
SPI的时序相对简单一些,但要注意四种模式(CPOL和CPHA的组合)。我个人习惯用模式0(CPOL=0, CPHA=0),因为大多数传感器都支持这个模式。
// SPI模式0的典型配置
spi_config_t config = {
.mode = SPI_MODE_0, // CPOL=0, CPHA=0
.freq = 1000000, // 1MHz
.bit_order = MSB_FIRST,
.cs_polarity = LOW_ACTIVE
};
小技巧:调试时序时,别光看示波器上的波形。我建议先用逻辑分析仪抓一下,它能帮你看到完整的协议帧,包括地址、数据、ACK/NACK。
3.2 多设备挂载:地址冲突和片选管理
I2C和SPI都能挂多个设备,但方式完全不同。
I2C多设备:每个设备有唯一的7位或10位地址。我遇到过最坑的事——两个传感器用了同一个地址,结果总线上一片混乱。解决办法是检查数据手册,看有没有地址引脚可以调整。
| 地址位 | 典型值 | 说明 |
|---|---|---|
| 7位地址 | 0x68 | MPU6050默认地址 |
| AD0=0 | 0x68 | 地址引脚接地 |
| AD0=1 | 0x69 | 地址引脚接VCC |
SPI多设备:每个设备有独立的片选(CS)引脚。这里有个坑——片选信号的电平极性。有些设备是高电平有效,有些是低电平有效。我曾经因为搞反了极性,导致两个设备同时响应,数据全乱了。
警告:SPI总线上挂多个设备时,一定要确保未选中的设备处于高阻态。否则它们会干扰总线,造成数据错误。
3.3 速率优化:别一味追求高频
很多人觉得总线速率越高越好,其实不然。我做过一个项目,把SPI频率从1MHz提到10MHz,结果数据反而出错了。为什么?因为信号完整性出了问题。
I2C速率优化:
- 标准模式:100kHz
- 快速模式:400kHz
- 高速模式:3.4MHz
我个人建议,除非你的走线很短(<10cm),否则别用高速模式。上拉电阻也很关键——速率越高,上拉电阻要越小。一般100kHz用4.7kΩ,400kHz用2.2kΩ。
SPI速率优化:
- 检查从设备的最大支持频率
- 考虑PCB走线的寄生电容
- 适当增加驱动能力
// 动态调整SPI速率
void spi_set_freq(uint32_t freq_hz) {
uint32_t prescaler = get_prescaler(freq_hz);
SPI1->CR1 = (SPI1->CR1 & ~SPI_CR1_BR_MASK) | prescaler;
}
经验之谈:调试速率时,先用低速跑通功能,再逐步提高频率。每次提高后,连续读100次数据,看看有没有错误。这样能快速定位速率瓶颈。
3.4 常见故障排查:从波形到代码
这部分是我最想分享的。这些年我排查过的总线故障,少说也有上百个了。总结下来,无非就这几类:
故障1:总线卡死(I2C常见)
现象:SCL一直为低,SDA也拉不上去。
原因:从设备没有释放总线,或者主设备产生了错误的停止条件。
解决办法:
- 检查从设备是否正常工作(供电、复位)
- 手动发送9个时钟脉冲,让从设备释放总线
- 重新初始化I2C外设
故障2:数据错位(SPI常见)
现象:读回来的数据总是少一位或多一位。
原因:时钟极性和相位不匹配,或者片选信号时序不对。
解决办法:
- 用逻辑分析仪抓取波形,对比数据手册
- 检查CPOL和CPHA的配置
- 确认片选信号在数据传输前后有足够的建立时间
我曾经...遇到过一个问题:SPI读温度传感器,数据总是跳变。查了两天,最后发现是片选信号毛刺导致的。加了一个10nF的电容就解决了。嗯,有时候硬件问题比软件更隐蔽。
故障3:地址无响应(I2C常见)
现象:发送从设备地址后,没有收到ACK。
原因:地址错误、设备未上电、总线被拉死。
排查步骤:
- 用万用表测量SDA和SCL的电压
- 确认上拉电阻是否正常
- 用示波器看起始条件是否完整
- 换个地址再试(有些设备支持多个地址)
3.5 实战技巧:我的调试工具箱
最后分享一些我常用的调试方法:
- 逻辑分析仪:必备工具,建议买24MHz采样率以上的
- 示波器:看信号质量,特别是上升沿和下降沿
- 串口打印:在关键节点打印调试信息,比看波形快
- 软件模拟:用GPIO模拟I2C/SPI,可以精确控制每个时序
// 软件模拟I2C的起始条件
void i2c_start(void) {
SDA_HIGH();
delay_us(5);
SCL_HIGH();
delay_us(5);
SDA_LOW(); // SCL高时,SDA从高变低
delay_us(5);
SCL_LOW(); // 准备发送数据
}
个人建议:刚开始学的时候,先用软件模拟的方式跑通一个传感器。虽然慢,但你能清楚地看到每个时序细节。等理解了原理,再用硬件外设提高效率。
好了,关于I2C和SPI总线的实战内容就讲到这里。记住,调试总线问题,耐心比技术更重要。很多时候,问题就出在一个不起眼的细节上——比如少了一个上拉电阻,或者多了一段长走线。
可可精品资料库