3、温度传感器应用:DS18B20、NTC热敏电阻、SHT30温湿度传感器驱动开发与校准
各位同学,大家好。今天我们来聊聊暖通空调系统里最基础、也最关键的环节——温度采集。
说实话,我在这个行业摸爬滚打十几年,见过太多因为温度测不准导致的能效翻车案例。有的项目,明明空调主机选型没问题,末端设备也到位了,结果运行能耗就是下不来。一查,原来是传感器偏差了2度,整个控制逻辑全乱套。
所以这节课,我打算把三种最常用的温度传感器——DS18B20、NTC热敏电阻、SHT30温湿度传感器,从驱动开发到校准,掰开了揉碎了讲清楚。
3.1 DS18B20:一线总线的老将
DS18B20,这玩意儿在暖通行业里太常见了。它最大的特点就是便宜、抗干扰、而且只用一根数据线就能通信。
驱动开发要点
DS18B20用的是单总线协议(One-Wire)。说白了,就是一根线上既要传数据,又要传时钟。时序要求比较严格,尤其是复位脉冲和存在脉冲的时序。
我个人习惯用定时器中断来做延时,而不是简单的空循环。为什么?因为空循环在中断里会被打断,时序就乱了。你想想看,如果MCU正在处理其他中断,DS18B20的时序窗口就错过了。
核心时序步骤:
- 复位:主机拉低总线480μs以上,然后释放
- 存在脉冲:DS18B20拉低总线60-240μs,表示应答
- 写时序:写0拉低60μs,写1拉低1-15μs后释放
- 读时序:主机拉低1-15μs后释放,在15μs内采样
// DS18B20 读取温度示例(伪代码)
uint8_t ds18b20_reset(void) {
uint8_t presence;
GPIO_LOW(); // 拉低总线
delay_us(480); // 保持480μs
GPIO_HIGH(); // 释放总线
delay_us(60); // 等待60μs
presence = GPIO_READ(); // 读取存在脉冲
delay_us(420); // 等待剩余时间
return presence; // 0表示存在
}
float ds18b20_read_temp(void) {
uint8_t temp_l, temp_h;
int16_t raw_temp;
ds18b20_reset();
ds18b20_write_byte(0xCC); // 跳过ROM
ds18b20_write_byte(0x44); // 启动温度转换
delay_ms(750); // 等待转换完成
ds18b20_reset();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE); // 读取暂存器
temp_l = ds18b20_read_byte();
temp_h = ds18b20_read_byte();
raw_temp = (temp_h << 8) | temp_l;
return raw_temp * 0.0625; // 12位分辨率,每LSB对应0.0625°C
}
避坑指南:我曾经在一个项目里,DS18B20的读数总是跳变。查了半天,发现是总线没加上拉电阻。记住,单总线必须外接4.7kΩ上拉电阻到VCC,否则信号不稳定。
3.2 NTC热敏电阻:模拟量的艺术
NTC热敏电阻,说白了就是温度变了,电阻值跟着变。它比DS18B20便宜,但需要ADC采样和查表计算。
硬件连接与分压电路
NTC不能直接接ADC,必须搭一个分压电路。我常用的接法是:NTC串联一个固定电阻,中间抽头接ADC输入。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 固定电阻R_ref | 10kΩ | 与NTC在25°C时阻值相同 |
| ADC参考电压 | 3.3V或5V | 取决于MCU |
| 采样精度 | 12位以上 | 推荐16位ADC |
查表法实现温度转换
NTC的阻值与温度的关系是非线性的。用公式算太慢,我建议用查表法。提前把温度-ADC值对应关系存到Flash里,运行时直接查。
// NTC查表法示例(简化版)
const uint16_t ntc_table[] = {
// 温度(°C) : ADC值 (假设12位ADC, Vref=3.3V)
0, 4095, // 0°C时ADC值
10, 3800,
20, 3400,
25, 3100, // 25°C时ADC值
30, 2800,
40, 2200,
50, 1600,
};
float ntc_get_temp(uint16_t adc_value) {
uint8_t i;
for(i = 0; i < sizeof(ntc_table)/2; i += 2) {
if(adc_value >= ntc_table[i+1]) {
// 线性插值
float ratio = (float)(adc_value - ntc_table[i+1]) /
(ntc_table[i-1] - ntc_table[i+1]);
return ntc_table[i] + ratio * 10;
}
}
return -40; // 超出范围
}
注意:NTC的自热效应。电流流过NTC会产生热量,导致测量值偏高。我一般控制流过NTC的电流在100μA以内,这样自热误差可以忽略。
3.3 SHT30:数字温湿度一体方案
SHT30是Sensirion家的产品,I2C接口,精度高,而且自带校准。暖通空调里,温湿度都要测的场合,用它最省事。
I2C驱动与数据读取
SHT30的I2C地址是0x44(ADDR引脚接GND)或0x45(ADDR引脚接VCC)。我习惯用0x44,省一根线。
// SHT30读取温湿度示例
#define SHT30_ADDR 0x44
uint8_t sht30_read_data(float *temp, float *hum) {
uint8_t buf[6];
// 发送测量命令:0x2C 0x06(高重复性)
i2c_start(SHT30_ADDR << 1);
i2c_write(0x2C);
i2c_write(0x06);
i2c_stop();
delay_ms(15); // 等待测量完成
// 读取6字节数据
i2c_start((SHT30_ADDR << 1) | 0x01);
for(i = 0; i < 6; i++) {
buf[i] = i2c_read(i < 5);
}
i2c_stop();
// 计算温度:T = -45 + 175 * (raw / 65535)
uint16_t raw_temp = (buf[0] << 8) | buf[1];
*temp = -45.0f + 175.0f * raw_temp / 65535.0f;
// 计算湿度:RH = 100 * (raw / 65535)
uint16_t raw_hum = (buf[3] << 8) | buf[4];
*hum = 100.0f * raw_hum / 65535.0f;
return 0; // 成功
}
个人经验:SHT30的I2C时钟频率不要超过400kHz。我试过1MHz,结果数据偶尔会错位。另外,SHT30的CRC校验一定要做,尤其是用在工业现场时。我曾经因为没做CRC,被一个电磁干扰搞得数据全乱套。
3.4 传感器校准:让数据更可靠
传感器出厂时都有一定误差。DS18B20的典型误差是±0.5°C,NTC更差,可能到±1°C。SHT30好一些,±0.2°C。但暖通空调系统里,我们往往需要±0.1°C的精度。
两点校准法
我常用的方法是两点校准。拿一个高精度参考温度计(比如铂电阻PT100),在0°C和50°C两个点做校准。
- 把传感器和参考温度计一起放进恒温槽,设定0°C
- 记录传感器读数和参考值,得到偏移量offset1
- 设定50°C,记录偏移量offset2
- 线性插值,得到全量程的校准曲线
// 两点校准示例
typedef struct {
float offset_low; // 低温点偏移
float offset_high; // 高温点偏移
float temp_low; // 低温点温度
float temp_high; // 高温点温度
} calib_t;
float apply_calibration(float raw_temp, calib_t *cal) {
float ratio = (raw_temp - cal->temp_low) /
(cal->temp_high - cal->temp_low);
float offset = cal->offset_low +
ratio * (cal->offset_high - cal->offset_low);
return raw_temp - offset;
}
校准注意事项:
- 恒温槽的稳定时间至少30分钟
- 每个校准点测量10次取平均
- 校准参数保存在EEPROM里,掉电不丢失
- 建议每半年重新校准一次
3.5 三种传感器的选型建议
| 传感器 | 精度 | 成本 | 接口 | 适用场景 |
|---|---|---|---|---|
| DS18B20 | ±0.5°C | 低 | 单总线 | 多点测温、长距离 |
| NTC | ±1°C | 极低 | 模拟量 | 大批量、低成本 |
| SHT30 | ±0.2°C | 中 | I2C | 温湿度同时测量 |
嗯,最后说一句。传感器选型没有绝对的好坏,关键看你的项目需求。如果预算充足,我建议用SHT30,省心。如果要做多点测温,DS18B20是首选。如果成本敏感,NTC也能用,但要做好校准。
好了,这节课就到这里。下一节我们讲执行器驱动,包括风机、水泵、电动阀的控制。到时候见。