第三章 多传感器数据采集:从硬件到软件的完整链路

大家好,我是这次课程的主讲工程师。今天我们来聊聊多传感器数据采集这个环节。说实话,我在安全预警系统里踩过最大的坑,就是数据采集这块。传感器选型不对、接口协议不匹配、软件框架设计不合理——任何一个环节出问题,整个系统都得返工。

这一章,我会从硬件方案、接口协议、软件框架三个维度,把我这些年积累的经验和教训都摊开来讲。你想想看,一个安全预警系统,前端传感器要是数据都采不准,后面云边协同再牛也是白搭。

3.1 数据采集硬件方案

先说说硬件选型。我个人习惯把传感器分为三类:环境感知类(温度、湿度、烟雾)、物理量感知类(振动、压力、位移)、以及特殊感知类(红外、微波、激光雷达)。

在安全预警场景下,我建议采用模块化设计。什么意思呢?就是每个传感器做成独立的小板子,通过统一的接口连接到主控板上。这样做的好处是——哪个传感器坏了,直接换模块,不用动整个系统。

核心硬件选型建议:

  • 主控芯片:STM32F4系列或ESP32,前者稳定,后者带WiFi/蓝牙
  • 传感器模组:DHT22(温湿度)、MPU6050(六轴姿态)、MQ系列(气体检测)
  • 通信模块:LoRa(远距离)、ZigBee(组网)、NB-IoT(蜂窝)
  • 电源管理:TPS5430(降压)、MAX17048(电量监测)

我在一个化工厂的项目里,曾经用过24个传感器同时采集。当时选的是STM32F407,主频168MHz,外设接口够多。但有个教训——电源纹波。传感器对电源质量很敏感,尤其是模拟输出的传感器。后来我加了LC滤波和独立LDO,问题才解决。

3.2 传感器接口协议详解

接口协议这块,说白了就是传感器和主控之间怎么「说话」。常见的就四种:I2C、SPI、UART、GPIO。每种协议都有自己的脾气,选错了,数据就乱套了。

3.2.1 I2C(两线制)

I2C只有两根线:SCL(时钟)和SDA(数据)。它最大的特点是多设备共用总线。你可以在一条总线上挂几十个传感器,每个设备有自己的地址。

我的经验:I2C适合短距离(1米以内)、低速(400kHz以下)的场景。我曾经在一条I2C总线上挂了8个传感器,结果发现总线电容太大,信号变形了。解决办法是降低时钟频率到100kHz,或者加总线缓冲器。

// I2C读取温湿度传感器示例(伪代码)
void read_sensor_i2c(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
    i2c_start();                // 起始信号
    i2c_write(addr << 1);      // 设备地址 + 写位
    i2c_write(reg);             // 寄存器地址
    i2c_stop();
    
    i2c_start();                // 重复起始
    i2c_write((addr << 1) | 1); // 设备地址 + 读位
    for (int i = 0; i < len; i++) {
        data[i] = i2c_read(i == len-1 ? NACK : ACK);
    }
    i2c_stop();
}

3.2.2 SPI(四线制)

SPI比I2C快得多,最高能跑到几十MHz。它用四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。每个设备需要独立的CS引脚。

注意:SPI没有标准的设备地址,全靠CS片选。如果你要接多个传感器,主控的GPIO引脚要够用。我有个项目接了6个SPI传感器,结果GPIO不够,最后用了一个I2C转SPI的桥接芯片才搞定。

// SPI读取加速度计示例
uint8_t spi_read_byte(uint8_t reg) {
    uint8_t data;
    CS_LOW();                    // 拉低片选
    spi_transfer(reg | 0x80);    // 发送寄存器地址(读标志)
    data = spi_transfer(0x00);   // 读取数据
    CS_HIGH();                   // 拉高片选
    return data;
}

3.2.3 UART(串口)

UART是异步通信,不需要时钟线。它用TX和RX两根线,加上GND共地。很多GPS模块、激光雷达都用UART接口。

UART有个好处——距离远。RS232能传15米,RS485能传1200米。我在一个大型仓库的安全预警项目里,传感器分布在各个角落,就是用RS485总线把所有UART设备连起来的。

避坑指南:我曾经在UART通信中忽略了波特率匹配的问题。传感器默认是9600,我代码里配成了115200,结果读出来的全是乱码。排查了整整半天才发现。所以,一定要先确认传感器的数据手册,波特率、数据位、停止位、校验位,一个都不能错。

3.2.4 GPIO(通用输入输出)

GPIO是最简单的接口,就一个引脚,要么高电平要么低电平。很多开关量传感器(比如门磁、红外对射)就用GPIO。

但GPIO也有讲究。比如上拉/下拉电阻,我见过有人把GPIO直接悬空,结果电平乱跳,系统误报了一整夜。正确的做法是:内部上拉或者外部加10kΩ上拉电阻。

// GPIO读取门磁状态
#define DOOR_SENSOR_PIN  GPIO_PIN_0
#define DOOR_PORT        GPIOA

uint8_t read_door_status() {
    return HAL_GPIO_ReadPin(DOOR_PORT, DOOR_SENSOR_PIN);
    // 返回0:门关闭(安全),返回1:门打开(报警)
}

3.3 数据采集软件框架

硬件选好了,协议搞定了,接下来就是软件框架。我见过太多人上来就写业务逻辑,结果后面要加传感器、改采样率,代码改得想哭。

我个人推荐分层架构。说白了,就是把代码分成三层:驱动层、抽象层、应用层。

为什么分层?你想想看,如果今天把DHT22换成SHT30,驱动层代码要改,但抽象层和应用层不用动。这就是解耦的好处。

3.3.1 驱动层(HAL)

驱动层直接和硬件打交道。每个传感器一个驱动文件,里面封装了读写寄存器、初始化、校准等操作。

// 驱动层接口示例(sensor_dht22.h)
#ifndef __SENSOR_DHT22_H__
#define __SENSOR_DHT22_H__

typedef struct {
    float temperature;
    float humidity;
    uint8_t crc_ok;
} dht22_data_t;

int dht22_init(GPIO_TypeDef *port, uint16_t pin);
int dht22_read(dht22_data_t *data);

#endif

3.3.2 抽象层(Sensor Abstraction)

抽象层把不同传感器的差异抹平。比如温度传感器,不管你是DHT22、DS18B20还是BME280,抽象层都提供一个统一的接口:float get_temperature()

// 抽象层接口
typedef struct {
    int (*init)(void);
    int (*read)(sensor_data_t *data);
    void (*deinit)(void);
} sensor_ops_t;

// 注册传感器
void sensor_register(sensor_type_t type, sensor_ops_t *ops);
// 统一读取
int sensor_read(sensor_type_t type, sensor_data_t *data);

3.3.3 应用层(Application)

应用层只管业务逻辑。比如:每5秒采集一次数据,如果温度超过60度就报警。它不关心底层用的是I2C还是SPI。

// 应用层代码
void safety_monitor_task(void *param) {
    sensor_data_t data;
    while (1) {
        if (sensor_read(SENSOR_TEMP, &data) == 0) {
            if (data.temperature > 60.0f) {
                alarm_trigger(ALARM_OVERHEAT);
                log_warning("温度过高: %.2f°C", data.temperature);
            }
        }
        vTaskDelay(pdMS_TO_TICKS(5000));  // 5秒采集一次
    }
}

3.4 本章知识体系总览

下面这张图,是我用SVG画的本章核心逻辑。你可以看到从硬件选型到接口协议,再到软件框架的完整链路。

多传感器数据采集知识体系 数据采集硬件方案 主控芯片 传感器模组 通信模块 电源管理 传感器接口协议 I2C(两线制) SPI(四线制) UART(串口) GPIO(开关量) 数据采集软件框架(分层架构) 驱动层(HAL) 抽象层(接口统一) 应用层(业务逻辑) 硬件选型 → 接口匹配 → 软件分层 → 稳定采集

3.5 本章小结

数据采集是整个安全预警系统的地基。地基不稳,上面云边协同再牛也没用。

  • 硬件方案:模块化设计,注意电源纹波和接口数量
  • 接口协议:I2C适合多设备短距离,SPI适合高速,UART适合远距离,GPIO适合开关量
  • 软件框架:分层架构,驱动层、抽象层、应用层各司其职

嗯,这一章就到这里。记住一句话:采集做不好,后面全是白忙活。下一章我们会聊传感器数据预处理,包括滤波、校准、异常检测——这些才是让数据真正「能用」的关键步骤。


专注资料整理