2. 传感器数据采集基础:常见传感器类型与接口协议

好,咱们进入正题。传感器数据采集,说白了就是让设备“感知”世界。你想想看,一个物联网系统如果没有传感器,就像人没有眼睛和耳朵,啥也干不了。这一节,我带你过一遍最常见的传感器类型,以及它们怎么跟处理器“说话”。

2.1 常见传感器类型

我在项目里摸爬滚打这么多年,接触过的传感器少说也有上百种。但万变不离其宗,最常用的其实就那几类。咱们一个一个说。

2.1.1 温度传感器

温度传感器,这玩意儿太常见了。从你家里的空调到工业锅炉,到处都有它的身影。

  • 热电偶:测量范围极广,从零下几百度到上千度都能搞定。我曾在钢铁厂的项目里用过,那环境,啧啧,普通传感器上去就废了。热电偶皮实耐用,但精度一般,需要冷端补偿。
  • 热敏电阻:便宜,响应快。但非线性严重,你得做查表或者公式拟合。我个人习惯用NTC(负温度系数)的,因为它在常温段灵敏度高。
  • 数字温度传感器:比如DS18B20,直接输出数字信号,用一根线就能通信。嗯,这里要注意,它的精度虽然够用,但采样速度慢,不适合快速变化的场景。
我的经验: 如果你做消费级产品,用数字传感器最省事。但要是工业现场,我建议用PT100铂电阻,虽然贵点,但稳定性和线性度好太多。我曾经因为图便宜用了热敏电阻,结果产品在高温环境下数据漂移得一塌糊涂,后来全换成了PT100。

2.1.2 湿度传感器

湿度测量其实比温度复杂。温度是物理量,湿度是化学量,容易受干扰。

  • 电容式湿度传感器:主流方案。利用高分子材料吸湿后介电常数变化的原理。比如SHT30、DHT22这些。我建议用SHT系列,精度高,而且有I2C接口,省事。
  • 电阻式湿度传感器:便宜,但容易老化,漂移严重。说实话,我基本不用这种,除非成本压得特别低。
避坑指南: 我曾经在一个户外气象站项目里,把湿度传感器直接暴露在雨水中,结果没两天就坏了。后来加了防水透气膜,才解决问题。记住,湿度传感器最怕结露和污染。

2.1.3 压力传感器

压力传感器,应用场景很广:气压、液压、水压、胎压……

  • 压阻式压力传感器:利用硅压阻效应,精度高,体积小。MEMS工艺做的,现在很成熟。比如BMP280,既能测气压也能测温度。
  • 电容式压力传感器:灵敏度高,但线性度差一些。适合低压差测量。
  • 应变式压力传感器:工业级,量程大,但体积也大。我在液压系统里用过,那家伙,跟个小铁疙瘩似的。

说白了,选压力传感器主要看量程和精度。你测大气压,用BMP280就行;测水管压力,得用不锈钢隔膜的工业传感器。

2.1.4 光照传感器

光照传感器,听起来简单,但类型也不少。

  • 光敏电阻:最便宜,但响应慢,精度差。做开关量检测还行,比如判断白天黑夜。
  • 光电二极管/三极管:响应快,线性度好。适合做光强精确测量。
  • 数字环境光传感器:比如BH1750,直接输出lux值,I2C接口。我个人很喜欢这颗芯片,因为它内置了光谱校正,测出来的值跟人眼感知很接近。

2.2 传感器接口协议

传感器采集到物理量后,怎么把数据传给处理器?这就涉及到接口协议了。我重点讲三种最常用的:I2C、SPI、UART。

2.2.1 I2C(Inter-Integrated Circuit)

I2C,我习惯叫它“I方C”。两根线:SDA(数据线)和SCL(时钟线)。支持多主多从,每个设备有唯一地址。

  • 优点:引脚少,接线简单。一个总线上可以挂多个传感器。
  • 缺点:速度相对慢(标准模式100kHz,快速模式400kHz),距离短(一般不超过1米)。
  • 适用场景:板内通信,比如传感器和MCU在同一块PCB上。

我举个例子,读取SHT30温湿度传感器的数据:

// 伪代码示例:I2C读取SHT30
i2c_start();                    // 发送起始信号
i2c_write(0x44 << 1);          // 设备地址+写位
i2c_write(0x2C);                // 发送命令高位
i2c_write(0x06);                // 发送命令低位(高重复性测量)
i2c_stop();                     // 发送停止信号

delay(15);                      // 等待测量完成

i2c_start();                    // 重新开始
i2c_write(0x44 << 1 | 0x01);  // 设备地址+读位
data[0] = i2c_read(ACK);        // 读取温度高字节
data[1] = i2c_read(ACK);        // 读取温度低字节
data[2] = i2c_read(NACK);       // 读取CRC(可选)
i2c_stop();
我的习惯: 用I2C时,我总会在总线上加4.7kΩ的上拉电阻。别小看这个,我曾经因为没加上拉电阻,折腾了一整天,结果发现信号根本拉不起来。

2.2.2 SPI(Serial Peripheral Interface)

SPI,全双工,速度比I2C快得多。四根线:MOSI、MISO、SCLK、CS(片选)。

  • 优点:速度快(几十MHz没问题),数据传输效率高。
  • 缺点:引脚多(每多一个设备就多一根CS线),不支持多主。
  • 适用场景:高速数据采集,比如加速度计、陀螺仪、ADC等。

我举个例子,读取MPU6050六轴传感器的数据:

// 伪代码示例:SPI读取MPU6050加速度计数据
cs_low();                       // 拉低片选,选中设备
spi_transfer(0x3B);             // 发送寄存器地址(加速度X轴高字节)
data[0] = spi_transfer(0x00);   // 读取数据
data[1] = spi_transfer(0x00);   // 读取下一个字节
cs_high();                      // 拉高片选,释放总线

// 组合数据
int16_t accel_x = (data[0] << 8) | data[1];
避坑指南: 我曾经在SPI通信时,忘了配置时钟极性(CPOL)和相位(CPHA),结果读出来的数据全是乱的。后来用示波器一看,才发现时钟边沿对不上。记住,SPI有四种模式,一定要看数据手册。

2.2.3 UART(Universal Asynchronous Receiver/Transmitter)

UART,就是串口。两根线:TX和RX。异步通信,不需要时钟线。

  • 优点:简单,距离远(RS232可以传十几米),很多设备都支持。
  • 缺点:只能点对点通信,速度一般(通常115200bps)。
  • 适用场景:GPS模块、蓝牙模块、某些工业传感器。

举个例子,读取GPS模块的NMEA数据:

// 伪代码示例:UART接收GPS数据
char buffer[128];
int index = 0;

while (1) {
    char c = uart_read();       // 从UART读取一个字节
    if (c == '$') {             // NMEA语句以$开头
        index = 0;
    }
    buffer[index++] = c;
    if (c == '\n') {            // 遇到换行符,一条语句结束
        buffer[index] = '\0';
        parse_nmea(buffer);     // 解析语句
        index = 0;
    }
}

2.3 数据采集原理

传感器把物理量变成电信号,但MCU只能处理数字信号。所以中间需要经过几个步骤。

2.3.1 信号调理

传感器输出的信号往往很微弱,或者有噪声。需要先做调理:

  • 放大:用运放把信号放大到ADC能识别的范围(比如0-3.3V)。
  • 滤波:用低通滤波器滤掉高频噪声。我习惯在ADC前端加一个RC低通滤波,截止频率根据信号频率来定。
  • 电平转换:有些传感器输出是0-5V,但MCU是3.3V,需要做电平匹配。

2.3.2 模数转换(ADC)

ADC把模拟信号变成数字量。关键参数:

  • 分辨率:比如12位ADC,输出范围0-4095。分辨率越高,精度越高。
  • 采样率:每秒采多少次。根据奈奎斯特定理,采样率至少是信号最高频率的两倍。
  • 参考电压:决定了ADC的量程。比如参考电压3.3V,12位ADC,那么每个LSB代表3.3/4096 ≈ 0.8mV。

举个例子,读取一个模拟温度传感器(比如LM35):

// 伪代码示例:ADC读取LM35温度传感器
uint16_t adc_value = adc_read(ADC_CHANNEL_0);  // 读取ADC原始值
float voltage = adc_value * 3.3 / 4096.0;      // 转换为电压
float temperature = voltage * 100.0;            // LM35: 10mV/°C

printf("Temperature: %.2f °C\n", temperature);

2.3.3 数据滤波与处理

原始数据往往有噪声,不能直接用。我常用的滤波方法:

  • 限幅滤波:如果当前值跟上一次的值差太多,就丢弃。比如温度不可能一秒内跳10度。
  • 中值滤波:连续采5次,取中间值。能有效去除脉冲噪声。
  • 滑动平均滤波:维护一个队列,每次取平均值。平滑效果好,但会有延迟。
核心要点: 数据采集不是简单的“读出来就行”。信号调理、ADC配置、软件滤波,每一步都影响最终数据的质量。我见过太多新手,直接读ADC原始值就用,结果数据跳得像心电图一样。

好了,这一节的内容就这些。传感器类型、接口协议、采集原理,这三块是物联网设备的基础。下一节,咱们聊聊怎么把这些传感器数据聚合起来,做边缘计算。到时候我会分享一些我在实际项目中的架构设计经验。