4、传感器接口与通信:I2C/SPI协议基础、GD32与加速度传感器的硬件连接、寄存器读写操作

加速度传感器与MCU之间的数据交换,本质上是在物理层通过特定电气接口、在逻辑层通过通信协议完成的。GD32微控制器与加速度传感器(如ADXL345、LIS3DH、MMA8452Q)之间最常用的两种通信方式是I2C(Inter-Integrated Circuit)和SPI(Serial Peripheral Interface)。本章将深入剖析这两种协议的工作原理、GD32与传感器的硬件连接方法、寄存器读写操作流程,并结合实际项目中的常见问题给出排障思路。

GD32与加速度传感器通信链路架构 GD32 MCU I2C: PB6(SCL)/PB7(SDA) SPI: PA5(SCK)/PA6(MISO) PA7(MOSI)/PA4(CS) GPIO: PB0(INT1) 加速度传感器 ADXL345 / LIS3DH SCL/SCLK, SDA/SDIO SDO/ADDR, CS, INT1 VDD(3.3V), GND I2C: SCL + SDA (上拉电阻 4.7kΩ) SPI: SCK + MOSI + MISO + CS INT1 → PB0 (外部中断,唤醒MCU) 电源域 VDD: 3.3V (LDO输出) GND: 共地 传感器供电 VDD: 3.3V (与MCU同源) 去耦电容: 0.1µF + 10µF 3.3V 电源轨 寄存器读写操作流程 ① 写寄存器: 发送设备地址+W → 寄存器地址 → 数据 ② 读寄存器: 发送设备地址+W → 寄存器地址 → 重启 → 设备地址+R → 读取数据

4.1 I2C与SPI协议核心原理

I2C和SPI是嵌入式系统中最常用的板级通信协议,两者在引脚占用、传输速率、时序复杂度上各有取舍。理解它们的本质差异,是正确设计传感器接口的第一步。

4.1.1 I2C协议:两线制多设备总线

I2C由Philips(现NXP)发明,仅需两根信号线:SCL(串行时钟线)和SDA(串行数据线)。所有设备通过开漏输出连接到这两根线上,并外接上拉电阻(典型值4.7kΩ)。I2C采用7位或10位设备地址寻址,理论上一条总线上可挂载多达128个设备。其通信速率分为标准模式(100kbit/s)、快速模式(400kbit/s)和高速模式(3.4Mbit/s)。

I2C的时序核心在于起始条件(SCL高电平时SDA下降沿)、停止条件(SCL高电平时SDA上升沿)以及应答位(ACK)机制。每次传输以起始条件开始,发送设备地址+读写标志位,从设备在地址匹配后拉低SDA作为应答。随后传输寄存器地址和数据字节,每字节后都需要应答确认。

4.1.2 SPI协议:四线制高速全双工

SPI采用主从架构,需要至少四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)和CS(片选,低电平有效)。SPI没有设备地址概念,每个从设备独占一根CS线,因此挂载设备越多,占用的GPIO也越多。SPI的传输速率远高于I2C,典型可达10Mbit/s以上,且支持全双工通信。

SPI的时序由时钟极性(CPOL)和时钟相位(CPHA)决定。CPOL决定空闲时SCLK的电平(0或1),CPHA决定数据在时钟的哪个边沿采样(第一个或第二个边沿)。GD32的SPI外设支持四种组合模式,与传感器通信时需查阅数据手册确认其要求的模式(ADXL345支持SPI模式0和模式3)。

对比维度 I2C SPI
信号线数量 2根(SCL+SDA) 4根(SCLK+MOSI+MISO+CS)
设备寻址 7位/10位地址,软件可配置 片选线CS,硬件选择
传输速率 100k~3.4Mbit/s 可达10Mbit/s以上
通信模式 半双工(分时读写) 全双工(同时收发)
多设备支持 一条总线多设备,地址区分 每个设备独立CS,占用GPIO
硬件复杂度 需上拉电阻,开漏输出 推挽输出,无需上拉
典型应用 低速传感器、EEPROM、RTC 高速传感器、Flash、显示屏
选型建议:对于加速度传感器这类数据量不大(通常几十字节/次)、但需要频繁读取的场景,I2C因其引脚占用少、接线简单而更受欢迎。若项目对实时性要求极高(如振动监测),或传感器支持SPI且速率优势明显,则优先考虑SPI。

4.2 GD32与加速度传感器的硬件连接设计

硬件连接是传感器正常工作的物理基础。以GD32F303系列MCU和ADXL345加速度传感器为例,我们需要从电源、通信接口、中断引脚三个维度进行设计。

4.2.1 电源与去耦设计

ADXL345的工作电压范围为2.0V~3.6V,GD32F303的I/O口兼容3.3V逻辑,因此两者可直接共用一个3.3V电源轨。但需要注意:传感器电源必须加去耦电容,通常在VDD引脚附近放置0.1µF陶瓷电容和10µF钽电容,以滤除高频噪声和电源纹波。若系统中有电机、继电器等大功率负载,建议使用磁珠或LC滤波器将传感器电源与数字电源隔离。

4.2.2 I2C接口连接

当选择I2C模式时,ADXL345的SDO/ADDR引脚接地(7位地址为0x53)或接VDD(地址为0x1D)。GD32的I2C外设引脚(如PB6/PB7)需配置为开漏输出,并外接4.7kΩ上拉电阻至3.3V。连接关系如下:

GD32F303          ADXL345
PB6 (I2C0_SCL) ──→ SCL
PB7 (I2C0_SDA) ──→ SDA
3.3V ──┬── 4.7kΩ ──→ SCL
       └── 4.7kΩ ──→ SDA
GND ──────────────→ GND
PB0 (EXTI0) ──────→ INT1

4.2.3 SPI接口连接

若选择SPI模式,ADXL345的CS引脚必须接高电平(选择I2C模式)或由MCU的GPIO控制(选择SPI模式)。SPI连接时,GD32的SPI0引脚映射为:PA5(SCK)、PA6(MISO)、PA7(MOSI)、PA4(CS)。注意ADXL345的SDO引脚在SPI模式下作为MISO使用,SDI/SDA引脚作为MOSI使用。

关键风险点:I2C和SPI模式的选择由CS引脚的电平决定。若CS引脚悬空或电平不稳定,传感器可能进入错误模式,导致通信失败。上电初始化时,务必先将CS引脚设置为确定电平,再配置通信外设。

4.3 寄存器读写操作与驱动实现

加速度传感器的功能配置和数据读取,本质上都是对内部寄存器的读写操作。以ADXL345为例,其寄存器空间为0x00~0x3D,其中0x00~0x1E为只读数据寄存器,0x1D~0x38为读写配置寄存器。

4.3.1 寄存器写操作流程

写操作通常用于配置传感器的量程、采样率、中断使能等参数。以设置ADXL345为±4g量程、100Hz输出速率为例:

// 伪代码:通过I2C写寄存器
uint8_t write_reg(uint8_t reg_addr, uint8_t data) {
    i2c_start();
    i2c_send_byte(0x53 << 1 | 0);  // 设备地址+写标志
    i2c_send_byte(reg_addr);        // 寄存器地址
    i2c_send_byte(data);            // 写入数据
    i2c_stop();
}

// 配置数据格式寄存器(0x31)为±4g
write_reg(0x31, 0x01);
// 配置带宽速率寄存器(0x2C)为100Hz
write_reg(0x2C, 0x0A);
// 进入测量模式(0x2D)
write_reg(0x2D, 0x08);

4.3.2 寄存器读操作流程

读操作需要先发送寄存器地址,然后重新发送设备地址+读标志,再连续读取数据。ADXL345支持多字节连续读取,读取0x32~0x37即可获得X、Y、Z三轴的16位数据:

// 伪代码:通过I2C读多字节
void read_regs(uint8_t reg_addr, uint8_t *buf, uint8_t len) {
    i2c_start();
    i2c_send_byte(0x53 << 1 | 0);  // 设备地址+写
    i2c_send_byte(reg_addr);        // 寄存器起始地址
    i2c_restart();
    i2c_send_byte(0x53 << 1 | 1);  // 设备地址+读
    for (int i = 0; i < len; i++) {
        buf[i] = i2c_read_byte(i == len-1 ? NACK : ACK);
    }
    i2c_stop();
}

// 读取三轴加速度数据
uint8_t acc_data[6];
read_regs(0x32, acc_data, 6);
int16_t x = (acc_data[1] << 8) | acc_data[0];
int16_t y = (acc_data[3] << 8) | acc_data[2];
int16_t z = (acc_data[5] << 8) | acc_data[4];

4.3.3 中断寄存器配置

为了实现运动检测和低功耗唤醒,需要配置ADXL345的中断功能。典型配置包括:使能数据就绪中断(DATA_READY)、活动/静止检测中断(ACTIVITY/INACTIVITY)。配置流程为:设置阈值寄存器(0x24~0x27)、设置持续时间寄存器(0x28~0x2B)、使能中断映射(0x2E)、使能中断源(0x2F)。

实战案例:某可穿戴设备项目需要检测用户跌倒事件。传感器采用ADXL345,I2C接口连接GD32F303。初始现象:设备静止时偶尔触发误报警。通过分析中断日志发现,活动阈值设置为0.5g(寄存器0x24=0x05),持续时间设置为50ms(寄存器0x25=0x05),而用户在正常走路时产生的加速度峰值可达1.2g,导致误触发。解决方案:将活动阈值提高到1.5g(0x24=0x0F),持续时间延长到100ms(0x25=0x0A),同时增加静止检测(静止阈值0.3g,持续时间3秒)。修改后误报率从每天15次降至0次,且真实跌倒事件(加速度峰值>3g)均能正确触发。

4.4 常见通信故障与调试方法

传感器通信故障是嵌入式开发中最常见的问题之一。掌握系统的排障方法,可以大幅缩短开发周期。

4.4.1 通信故障现象与原因对照

故障现象 可能原因 排查方法
I2C无应答(ACK失败) 设备地址错误、上拉电阻缺失、传感器未上电 用示波器测量SCL/SDA波形,检查地址位
SPI读回全0xFF CS电平错误、SPI模式不匹配、MISO接线错误 检查CS是否拉低,确认CPOL/CPHA配置
数据跳变不稳定 电源纹波过大、I2C速率过高、线缆过长 增加去耦电容,降低通信速率,缩短连线
中断不触发 中断寄存器未配置、GPIO未配置为输入 读取中断源寄存器(0x30)确认中断标志

4.4.2 使用逻辑分析仪调试

逻辑分析仪是调试I2C/SPI通信的利器。将逻辑分析仪的通道连接到SCL/SCLK和SDA/MOSI/MISO,设置合适的采样率(至少为通信速率的4倍),即可解码出完整的通信帧。重点观察:起始条件是否正常、地址字节是否正确、ACK位是否存在、数据字节是否与预期一致。

经验提醒:在调试I2C时,如果SDA线一直为低电平,说明有设备拉住了总线(可能是从设备故障或总线死锁)。此时可尝试将SCL线手动翻转9个时钟周期,释放总线。对于SPI,若CS信号有毛刺,会导致从设备误触发,建议在CS引脚加10kΩ下拉电阻。

4.4.3 软件层面的调试技巧

在驱动开发初期,建议采用轮询方式读取传感器数据,确认通信链路正常后再切换为中断方式。每次读写寄存器后,可回读该寄存器验证写入是否成功。例如,写入0x31寄存器后,立即读取0x31,若返回值与写入值一致,则说明通信正常。此外,利用GD32的串口打印调试信息,将读取到的原始寄存器值输出,便于对比分析。

4.5 本章总结与工程实践要点

传感器接口设计是嵌入式系统开发的基石。本章从协议原理、硬件连接、寄存器操作到故障排查,构建了完整的知识体系。在实际项目中,建议遵循以下原则:

  • 优先选择I2C接口,因其引脚占用少、接线简单,适合大多数加速度传感器应用场景。
  • 硬件设计时预留测试点,在SCL、SDA、CS、INT1等关键信号线上预留焊盘,便于调试时连接逻辑分析仪。
  • 驱动代码分层设计,将底层寄存器读写函数与上层数据处理逻辑分离,便于移植和复用。
  • 重视电源完整性,传感器对电源噪声敏感,去耦电容必须靠近VDD引脚放置。
  • 建立通信自检机制,上电后读取设备ID寄存器(ADXL345的DEVID为0xE5),验证通信链路正常后再进行后续配置。

掌握这些核心要点,你就能在GD32平台上快速、稳定地驱动加速度传感器,为后续的数据分类和本地告警功能奠定坚实基础。