3、MEMS传感器接口协议:I2C协议详解、SPI协议详解、接口选择与功耗权衡
各位工程师朋友,今天我们来聊聊MEMS传感器最核心的“沟通方式”——接口协议。说白了,传感器采集到的数据怎么传到MCU?靠的就是I2C和SPI这两大协议。我做了十几年嵌入式,选错接口导致项目返工的情况见过太多次了。今天就把我踩过的坑和积累的经验,一次性讲清楚。
3.1 I2C协议详解
I2C,全称Inter-Integrated Circuit,是飞利浦公司(现NXP)在1980年代推出的。它只需要两根线:SDA(数据线)和SCL(时钟线)。我最早接触I2C是在一个温湿度传感器项目上,当时觉得两根线就能挂一堆传感器,太方便了。
3.1.1 物理层与电气特性
- 总线拓扑:主从架构,一个主设备(通常是MCU)可以挂多个从设备(传感器)。每个从设备有唯一7位或10位地址。
- 上拉电阻:SDA和SCL必须接上拉电阻到VDD。阻值通常选4.7kΩ,但低功耗场景下我建议用10kΩ甚至更高——上拉电阻越小,总线功耗越大。
- 电平标准:常见3.3V和1.8V。注意,不同电压域的设备不能直接挂同一总线,需要电平转换芯片。
3.1.2 通信时序
I2C的时序其实不复杂,但细节决定成败。标准模式100kHz,快速模式400kHz,高速模式3.4MHz。MEMS传感器通常用100kHz或400kHz。
基本流程:
- 起始条件:SCL高电平时,SDA从高到低跳变。
- 发送地址:7位地址+读写位(0写1读)。从设备在第9个时钟周期拉低SDA作为应答(ACK)。
- 数据传输:每字节8位,MSB先发。每字节后跟一个ACK位。
- 停止条件:SCL高电平时,SDA从低到高跳变。
// I2C读取传感器数据的典型代码片段(伪代码)
uint8_t i2c_read_byte(uint8_t dev_addr, uint8_t reg_addr) {
i2c_start(); // 发送起始条件
i2c_write_byte(dev_addr << 1); // 设备地址 + 写位
i2c_wait_ack();
i2c_write_byte(reg_addr); // 寄存器地址
i2c_wait_ack();
i2c_start(); // 重复起始条件
i2c_write_byte(dev_addr << 1 | 0x01); // 设备地址 + 读位
i2c_wait_ack();
uint8_t data = i2c_read_byte(); // 读取数据
i2c_send_nack(); // 发送非应答
i2c_stop(); // 发送停止条件
return data;
}
3.1.3 I2C的优缺点
| 优点 | 缺点 |
|---|---|
| 引脚少(仅2线) | 速度上限较低(通常400kHz) |
| 支持多从设备 | 每字节需应答,协议开销大 |
| 硬件实现简单 | 总线电容限制设备数量 |
| 有标准化的地址分配 | 从设备不能主动发起通信 |
3.2 SPI协议详解
SPI,全称Serial Peripheral Interface,是摩托罗拉公司推出的。它需要4根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。
我第一次用SPI是在一个加速度计项目上,当时需要高速采集数据做振动分析。I2C的400kHz根本不够用,换成SPI后直接跑到10MHz,数据吞吐量上去了,但布线也复杂了。
3.2.1 物理层与电气特性
- 总线拓扑:主从架构,但每个从设备需要独立的CS线。所以从设备越多,需要的GPIO越多。
- 全双工:MOSI和MISO可以同时传输数据,这是SPI相比I2C最大的优势。
- 无上拉电阻:SPI是推挽输出,不需要上拉电阻。这一点在低功耗设计中很友好。
3.2.2 四种模式
SPI有4种模式,由CPOL(时钟极性)和CPHA(时钟相位)决定。说白了就是:时钟空闲时是高还是低?数据在时钟上升沿还是下降沿采样?
| 模式 | CPOL | CPHA | 说明 |
|---|---|---|---|
| 0 | 0 | 0 | 空闲低,上升沿采样 |
| 1 | 0 | 1 | 空闲低,下降沿采样 |
| 2 | 1 | 0 | 空闲高,上升沿采样 |
| 3 | 1 | 1 | 空闲高,下降沿采样 |
// SPI读取传感器数据的典型代码片段(伪代码)
uint16_t spi_read_register(uint8_t cs_pin, uint8_t reg_addr) {
uint16_t result = 0;
gpio_write(cs_pin, 0); // 拉低片选,选中设备
spi_transfer_byte(reg_addr); // 发送寄存器地址
result = spi_transfer_byte(0x00); // 发送任意数据,同时接收
gpio_write(cs_pin, 1); // 拉高片选,释放设备
return result;
}
3.2.3 SPI的优缺点
| 优点 | 缺点 |
|---|---|
| 速度快(可达几十MHz) | 引脚多(至少4线) |
| 全双工通信 | 每增加一个从设备需多一根CS线 |
| 协议开销小 | 没有标准化的设备寻址 |
| 硬件实现简单 | 不支持多主设备 |
3.3 接口选择与功耗权衡
好了,两个协议都讲完了。现在的问题是:到底选哪个?
我个人的经验是:没有绝对的好坏,只有适不适合你的场景。你想想看,一个电池供电的温湿度传感器,每秒采集一次数据,用I2C完全够用,何必上SPI?但如果你在做高速惯性导航,需要几千Hz的加速度数据,那SPI就是唯一选择。
3.3.1 功耗对比
功耗是MEMS传感器系统设计中最关键的因素之一。我专门做过对比测试:
| 参数 | I2C (100kHz) | SPI (1MHz) |
|---|---|---|
| 静态功耗(总线空闲) | 较高(上拉电阻持续耗电) | 极低(无上拉电阻) |
| 动态功耗(传输中) | 较低(频率低) | 较高(频率高) |
| 单次传输功耗 | 较高(协议开销大) | 较低(传输时间短) |
| 待机功耗 | 需考虑上拉电阻 | 几乎为零 |
3.3.2 我的选择原则
- 数据速率 < 100kbps:优先I2C。引脚少,布线简单。
- 数据速率 > 1Mbps:必须SPI。I2C扛不住。
- 电池供电、间歇工作:SPI更优。总线空闲功耗低。
- 需要挂多个传感器:I2C更方便。一根总线挂十几个设备没问题。
- 对实时性要求高:SPI。全双工+低延迟。
3.3.3 一个实际案例
我之前做过一个可穿戴设备,用了三轴加速度计+气压计+温度传感器。最初设计全部用I2C,挂在一根总线上。结果发现一个问题:气压计读取时,加速度计的数据会偶尔丢包。后来分析发现是I2C总线被长时间占用。
解决方案:加速度计用SPI(高速数据),气压计和温度传感器用I2C(低速数据)。这样既保证了加速度数据的实时性,又保留了I2C的简洁性。
3.4 知识体系总览
下面这张图是我自己总结的,把本章的核心逻辑串起来了。你一看就明白:
这张图把I2C和SPI的核心特性、以及如何根据功耗需求做选择,都画清楚了。你保存下来,以后选型时拿出来看一眼,基本不会出错。
好了,关于MEMS传感器的接口协议,今天就聊到这里。I2C和SPI各有千秋,关键是要理解你的系统需求——数据速率、功耗预算、引脚数量、从设备数量,这些因素综合起来,才能做出最优选择。下次你拿到一款新传感器,不妨先问问自己:这个场景下,I2C和SPI哪个更合适?