3、Sensor硬件接口:I2C/SPI接口区别、中断引脚与GPIO配置、电源管理与电压域
好,咱们今天聊聊Sensor的硬件接口。这部分内容,说白了就是Sensor和主控芯片之间怎么“说话”的。我做了这么多年驱动,发现很多软件问题,追根溯源都是硬件接口没搞明白。你想想看,协议没配对,中断信号没拉对,电源没供上,驱动写得再漂亮也白搭。
3.1 I2C vs SPI:两种主流接口的实战选择
Sensor常用的接口,无非就是I2C和SPI。很多初学者会问,到底哪个好?我的回答是:没有的好,只有合不合适的场景。
3.1.1 I2C接口:两线制,接线简单
I2C只用两根线:SCL(时钟线)和SDA(数据线)。它的优点是引脚少,布线方便。我做过一个项目,板子空间紧张得要命,I2C简直就是救星。
但I2C也有短板——速度。标准模式100kHz,快速模式400kHz,高速模式也就3.4MHz。对于加速度计、陀螺仪这类数据量不大的Sensor,I2C完全够用。但如果你要搞高帧率的图像Sensor,I2C就有点吃力了。
这里有个关键点:I2C地址。每个I2C设备都有一个7位或10位地址。同一总线上不能挂两个相同地址的设备。我遇到过一个问题,两个Sensor用了同一个地址,结果数据全乱了。后来查了半天,才发现是地址冲突。
3.1.2 SPI接口:四线制,速度更快
SPI用四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。它的速度可以跑到几十MHz,甚至上百MHz。对于需要高速数据吞吐的Sensor,比如高精度气压计、磁力计,SPI是更好的选择。
SPI还有一个好处:全双工。发送和接收可以同时进行。I2C是半双工,同一时间只能一个方向传输。
但SPI的缺点也很明显——引脚多。每多一个设备,就要多一根CS线。如果板子上有七八个SPI设备,那CS线就占了一大片GPIO。
| 特性 | I2C | SPI |
|---|---|---|
| 引脚数 | 2(SCL, SDA) | 4+(SCLK, MOSI, MISO, CS) |
| 速度 | 100kHz ~ 3.4MHz | 可达几十MHz |
| 通信方式 | 半双工 | 全双工 |
| 设备寻址 | 软件地址(7位/10位) | 硬件片选(CS) |
| 适用场景 | 低速、引脚受限 | 高速、大数据量 |
3.2 中断引脚与GPIO配置
Sensor的中断引脚,是驱动和硬件交互的“门铃”。Sensor检测到数据准备好、阈值超限、或者FIFO满时,就会拉高或拉低中断引脚,通知主控来取数据。
3.2.1 中断类型:电平触发 vs 边沿触发
电平触发:中断引脚保持高电平或低电平,直到主控读取数据后清除。边沿触发:只在电平变化的那一刻产生中断。
我个人更倾向于用电平触发。为什么?因为边沿触发容易丢中断。如果主控正在忙,没来得及响应,边沿就过去了。电平触发则不同,只要电平还在,中断就一直有效。
但电平触发也有坑——中断锁死。如果主控读取数据后,没有正确清除中断标志,中断引脚会一直保持有效电平,导致CPU不断响应中断。嗯,这个我踩过。
3.2.2 GPIO配置要点
配置中断引脚时,有几个关键点:
- 上下拉电阻: 很多Sensor的中断引脚是开漏输出,需要外部上拉电阻。我习惯用4.7kΩ或10kΩ。
- 中断极性: 高电平有效还是低电平有效?这要和Sensor的寄存器配置一致。
- GPIO复用: 有些SoC的GPIO可以配置为中断输入。记得在设备树或代码里设置好。
3.3 电源管理与电压域
电源管理,是嵌入式系统里绕不开的话题。Sensor的功耗虽然不大,但积少成多。而且,电压域搞错了,Sensor可能直接烧掉。
3.3.1 电压域匹配
Sensor的工作电压,通常有1.8V、2.5V、3.3V等。主控的I/O电压也可能不同。如果电压不匹配,轻则通信失败,重则烧毁芯片。
我见过一个案例:有人把3.3V的Sensor接到了1.8V的I2C总线上。结果呢?Sensor能工作,但I2C信号电平不够,数据经常出错。后来加了电平转换芯片才解决。
电平转换的方式有几种:
- 分立MOS管: 便宜,但需要多个元件。
- 专用电平转换芯片: 如TXS0102、PCA9306,集成度高。
- SoC内置: 有些SoC的GPIO支持多种电压,直接配置即可。
3.3.2 电源开关与低功耗模式
很多Sensor支持多种电源模式:
- 正常模式: 全速运行,功耗最高。
- 休眠模式: 关闭大部分电路,只保留唤醒逻辑。
- 待机模式: 介于两者之间。
在驱动里,我通常会这样管理电源:
/* 伪代码示例 */
void sensor_power_control(bool enable) {
if (enable) {
/* 打开电源 */
gpio_set_value(power_pin, 1);
msleep(10); /* 等待电源稳定 */
/* 初始化Sensor */
sensor_init();
} else {
/* 进入休眠 */
sensor_write_reg(0x20, 0x00); /* 关闭所有功能 */
gpio_set_value(power_pin, 0);
}
}
3.4 知识体系总览
下面这张图,是我自己总结的Sensor硬件接口知识体系。你可以把它当作一个检查清单,做项目时对照着看。
好了,这一章的内容就到这里。硬件接口是Sensor驱动的基石,搞懂了这些,后面写代码心里才有底。