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 引脚,布线略多。

选型经验:温湿度传感器几乎总是走 I2C;加速度计若只需“运动/静止”二值判断,可用其内置中断引脚 + I2C 配置;若需连续采样波形或 FIFO 批量读取,优先 SPI。

二、总线连接与地址/片选规划

以 nRF52840 为例,一个可行的引脚分配如下(示例,实际以硬件设计为准):

信号nRF 引脚连接对象说明
SCLP0.27SHT30、LIS2DH12I2C 时钟,外接 4.7 kΩ 上拉
SDAP0.26SHT30、LIS2DH12I2C 数据,外接 4.7 kΩ 上拉
SCKP0.29ADXL362SPI 时钟
MOSIP0.30ADXL362主机输出
MISOP0.31ADXL362主机输入
CSP0.28ADXL362片选,低有效
INT1P0.11ADXL362 / LIS2DH12运动中断输入,GPIOTE 边沿触发
REEDP0.12干簧管外壳开合检测,上拉输入

I2C 地址需避免冲突:SHT30 默认 0x44(ADDR 接低)或 0x45;LIS2DH12 为 0x18 或 0x19(SA0 决定)。规划时应把地址写进设备树或配置宏,便于统一管理。

三、中断与轮询:两种采集策略的取舍

轮询(polling)实现简单:主循环按固定周期读取传感器寄存器,判断阈值。缺点是 CPU 空转、功耗高,且周期太短浪费电、太长会漏事件。中断(interrupt)则由传感器在事件发生时拉低 INT 引脚,触发 nRF 的 GPIOTE 中断,CPU 被唤醒后再读取数据,功耗显著更低,适合电池供电的资产追踪器。

实际工程中常采用“混合策略”:加速度计配置运动/静止中断,静止时 CPU 深度睡眠;一旦运动中断到来,唤醒后切换到较高频率轮询采集一段时间的加速度与温湿度,确认资产状态变化后再回到低功耗中断模式。

nRF 资产追踪:GPIO / I2C / SPI 采集链路 nRF52 / nRF53 SoC TWI (I2C) SPIM GPIOTE GPIO 输入 SHT30 温湿度 I2C 地址 0x44 周期测量 / 单次测量 LIS2DH12 加速度计 I2C 地址 0x18 INT1 运动中断 ADXL362 加速度计 SPI 模式 0,CS=P0.28 FIFO 批量读取 干簧管 / 按键 REED=P0.12 上拉输入 开合 → 边沿事件 SCL/SDA SCK/MOSI/MISO INT1 / REED 中断 采集结果 → 资产状态:静止/运动、温度、湿度、外壳开合 → 上报云端

四、中断采集的实现要点

以 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 → 标记“潮湿风险”。
  • 干簧管由闭合变断开 → 判定“外壳被打开”,立即上报。

这些阈值应作为配置参数存放,便于按资产类型调整。判读逻辑放在应用层,与驱动层解耦,方便后续接入云端规则引擎。

注意:I2C 读取失败时不要直接丢弃,应记录错误计数并在连续失败 3 次后重新初始化总线;SPI 读取 FIFO 时要先读状态寄存器确认数据就绪,避免读到旧数据。

七、低功耗与可靠性检查

资产追踪器多为电池供电,采集链路必须兼顾功耗。检查要点包括:静止时关闭 SPI 时钟、把未使用引脚配置为断开或输出低;I2C 上拉电阻不宜过小以免静态漏流;GPIOTE 中断使用 HITOLO 或 LOTOHI 而非 Toggle,减少误唤醒;采集完成后及时进入 System ON 睡眠。可靠性方面,建议为每次采集打时间戳,并在上报前做一次 CRC 或范围校验,避免异常值污染云端数据。

完成以上配置后,设备即可在低功耗前提下稳定读取加速度、温湿度和外壳状态,为后续的资产状态判定与云端上报提供可靠的数据基础。