3. GPIO与传感器数据采集
资产追踪设备的核心价值在于“感知”——它必须持续知道资产当前是静止还是移动、是否被搬动、所处环境的温湿度是否越界。在 nRF52/nRF53 系列 SoC 上,这些感知能力由 GPIO、I2C(TWI)和 SPI 三类外设协同完成:GPIO 负责按键、干簧管、LED 等离散信号与中断唤醒;I2C 连接温湿度传感器和部分低功耗加速度计;SPI 则以更高吞吐连接需要频繁读取 FIFO 的加速度计。本节围绕“接口选型—总线连接—中断与轮询采集—数据判读”这条主线展开,最终让设备能稳定输出资产状态数据。
一、先明确三类接口的分工
nRF 的 GPIO 是通用可编程引脚,每个引脚可配置为输入、输出、上拉/下拉、开漏,并可挂接 GPIOTE 任务与事件,实现“边沿触发中断”和“低功耗唤醒”。资产追踪中典型的 GPIO 用途包括:干簧管/霍尔开关检测外壳开合、按键触发配网、LED 指示状态、以及作为传感器中断引脚(INT1/INT2)的输入。
I2C(Nordic 称为 TWI)是两线总线,SCL/SDA 需外接上拉电阻(典型 4.7 kΩ,400 kHz 时可用 2.2~4.7 kΩ)。它适合连接 SHT3x/SHT4x 温湿度传感器、LIS2DH12/LIS3DH 等低速加速度计、以及 BME280 等环境传感器。优点是引脚少、可挂多设备;缺点是速率有限,不适合高频读取大 FIFO。
SPI 是四线总线(SCK、MOSI、MISO、CS),速率可达 8 MHz 甚至更高,适合 LIS3DH、LSM6DS3、ADXL362 等需要突发读取 FIFO 的加速度计。代价是每个从设备需要独立 CS 引脚,布线略多。
二、总线连接与地址/片选规划
以 nRF52840 为例,一个可行的引脚分配如下(示例,实际以硬件设计为准):
| 信号 | nRF 引脚 | 连接对象 | 说明 |
|---|---|---|---|
| SCL | P0.27 | SHT30、LIS2DH12 | I2C 时钟,外接 4.7 kΩ 上拉 |
| SDA | P0.26 | SHT30、LIS2DH12 | I2C 数据,外接 4.7 kΩ 上拉 |
| SCK | P0.29 | ADXL362 | SPI 时钟 |
| MOSI | P0.30 | ADXL362 | 主机输出 |
| MISO | P0.31 | ADXL362 | 主机输入 |
| CS | P0.28 | ADXL362 | 片选,低有效 |
| INT1 | P0.11 | ADXL362 / LIS2DH12 | 运动中断输入,GPIOTE 边沿触发 |
| REED | P0.12 | 干簧管 | 外壳开合检测,上拉输入 |
I2C 地址需避免冲突:SHT30 默认 0x44(ADDR 接低)或 0x45;LIS2DH12 为 0x18 或 0x19(SA0 决定)。规划时应把地址写进设备树或配置宏,便于统一管理。
三、中断与轮询:两种采集策略的取舍
轮询(polling)实现简单:主循环按固定周期读取传感器寄存器,判断阈值。缺点是 CPU 空转、功耗高,且周期太短浪费电、太长会漏事件。中断(interrupt)则由传感器在事件发生时拉低 INT 引脚,触发 nRF 的 GPIOTE 中断,CPU 被唤醒后再读取数据,功耗显著更低,适合电池供电的资产追踪器。
实际工程中常采用“混合策略”:加速度计配置运动/静止中断,静止时 CPU 深度睡眠;一旦运动中断到来,唤醒后切换到较高频率轮询采集一段时间的加速度与温湿度,确认资产状态变化后再回到低功耗中断模式。
四、中断采集的实现要点
以 LIS2DH12 的 INT1 运动中断为例,配置流程如下:先通过 I2C 写 CTRL_REG1 设置 ODR(如 10 Hz)与使能轴;写 INT1_CFG 使能 X/Y/Z 高事件(AOI=1 表示“或”逻辑);写 INT1_THS 设置阈值(如 0x10,对应约 128 mg);写 INT1_DURATION 设置持续时间(如 0x02,避免抖动误触发);最后写 CTRL_REG3 把 INT1 路由到物理引脚。
在 nRF 侧,把该引脚配置为输入并挂接 GPIOTE IN 事件。使用 nRF5 SDK 时可用 nrf_drv_gpiote_in_init() 指定 NRF_GPIOTE_POLARITY_HITOLO(高到低)触发;使用 nRF Connect SDK 时则通过 GPIO_INT_EDGE_TO_ACTIVE 与 gpio_pin_interrupt_configure() 完成。中断回调中不要做耗时操作,只置一个标志或发送信号量,由主线程读取数据。
// nRF Connect SDK 示例:配置 INT1 下降沿中断
static struct gpio_callback accel_cb;
gpio_pin_configure(dev, INT1_PIN, GPIO_INPUT | GPIO_PULL_UP);
gpio_pin_interrupt_configure(dev, INT1_PIN, GPIO_INT_EDGE_TO_ACTIVE);
gpio_init_callback(&accel_cb, accel_int_handler, BIT(INT1_PIN));
gpio_add_callback(dev, &accel_cb);
void accel_int_handler(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
k_sem_give(&accel_sem); // 仅唤醒,不做 I2C 读
}
五、轮询采集温湿度的实现
SHT30 支持单次测量模式:发送命令 0x2C06(高重复性、时钟拉伸关闭),等待约 15 ms 后读取 6 字节数据,前 3 字节为温度、后 3 字节为湿度,末字节为 CRC。温度换算:T(°C) = -45 + 175 × (raw / 65535);湿度换算:RH(%) = 100 × (raw / 65535)。
// 伪代码:SHT30 单次测量
uint8_t cmd[2] = {0x2C, 0x06};
i2c_write(SHT30_ADDR, cmd, 2);
k_sleep(K_MSEC(20));
uint8_t buf[6];
i2c_read(SHT30_ADDR, buf, 6);
uint16_t t_raw = (buf[0] << 8) | buf[1];
uint16_t h_raw = (buf[3] << 8) | buf[4];
float temp = -45.0f + 175.0f * t_raw / 65535.0f;
float hum = 100.0f * h_raw / 65535.0f;
轮询周期建议与资产状态匹配:静止时 60 s 一次,运动时 5 s 一次。若使用 Zephyr,可把采集封装为工作队列任务,由定时器周期提交,避免阻塞主循环。
六、数据判读与状态映射
采集到的原始数据需要映射为资产状态。一个可用的判断规则示例:
- 加速度三轴合成幅值 |a| 与 1 g 偏差持续超过 0.15 g 且超过 2 s → 判定“运动”。
- 温度超过 45 °C 或低于 -10 °C → 标记“环境越界”,触发告警上报。
- 湿度超过 80% RH 持续 10 min → 标记“潮湿风险”。
- 干簧管由闭合变断开 → 判定“外壳被打开”,立即上报。
这些阈值应作为配置参数存放,便于按资产类型调整。判读逻辑放在应用层,与驱动层解耦,方便后续接入云端规则引擎。
七、低功耗与可靠性检查
资产追踪器多为电池供电,采集链路必须兼顾功耗。检查要点包括:静止时关闭 SPI 时钟、把未使用引脚配置为断开或输出低;I2C 上拉电阻不宜过小以免静态漏流;GPIOTE 中断使用 HITOLO 或 LOTOHI 而非 Toggle,减少误唤醒;采集完成后及时进入 System ON 睡眠。可靠性方面,建议为每次采集打时间戳,并在上报前做一次 CRC 或范围校验,避免异常值污染云端数据。
完成以上配置后,设备即可在低功耗前提下稳定读取加速度、温湿度和外壳状态,为后续的资产状态判定与云端上报提供可靠的数据基础。