1. 项目概述
这个多路温度监控系统是我在实验室设备维护过程中萌生的想法。老旧的温控设备经常出现故障,而市面上的成品温控器要么功能过剩要么价格昂贵。于是决定用最基础的51单片机搭建一个实用、可靠的多路温度监控方案。
系统核心功能包括:
- 同时监测4个区域的实时温度
- LCD屏幕显示各通道温度数值
- 可设置温度报警阈值
- 超温时触发声光报警
- 自动控制散热设备
- 配置信息断电保存
这个方案特别适合需要多点温度监控的中小型场景,比如实验室设备柜、小型温室、机房机柜等。整套硬件成本不到50元,却可以实现商业温控器80%的核心功能。
2. 硬件设计与选型
2.1 主控芯片选择
选用STC89C52RC单片机作为主控,主要基于以下考虑:
- 价格低廉(约5元/片)
- 完全兼容传统8051架构
- 内置8K Flash和512B RAM
- 支持ISP在线编程
- 工作电压范围宽(3.3V-5V)
- 抗干扰能力强
虽然性能比不上ARM芯片,但对于温度采集这种低速应用完全够用。实测在12MHz晶振下运行稳定,功耗约25mA。
2.2 温度传感器选型
DS18B20数字温度传感器的优势非常明显:
- 数字输出,省去ADC环节
- ±0.5℃的测量精度
- -55℃~+125℃宽量程
- 单总线接口,节省IO资源
- 每个器件有唯一64位序列号
- 支持寄生供电模式
相比之下,传统的热敏电阻方案需要复杂的校准电路,而模拟输出的LM35则需要占用ADC通道。DS18B20虽然时序要求严格,但一旦调通就非常稳定。
2.3 显示与人机交互
1602字符型LCD是最经济实用的选择:
- 16x2字符显示区域
- 5V供电,与单片机直接兼容
- 4位或8位并行接口
- 自带字库,无需额外驱动
- 功耗仅约1mA
三个机械按键实现设置功能:
- SET键:进入/退出设置模式
- UP键:数值增加
- DOWN键:数值减少
这种组合足够完成阈值设置等基本操作。
2.4 报警与执行机构
报警系统采用声光结合的方式:
- 有源蜂鸣器(5V驱动)
- LED指示灯
- 继电器控制散热设备
继电器选用5V驱动的HRS1H-S-DC5V,触点容量10A/250VAC,足以驱动小型风扇或加热器。
3. 电路设计要点
3.1 单总线接口设计
DS18B20的单总线接口看似简单,实则有很多细节需要注意:
-
上拉电阻选择:
- 标准模式:4.7kΩ
- 长线传输(>20米):2.2kΩ
- 寄生供电模式:1kΩ
-
总线电容控制:
- 总线上每个DS18B20会引入约10pF电容
- 总线总电容应小于100pF
- 长距离传输时需考虑分布电容
-
电源去耦:
- 每个传感器VDD引脚加0.1μF陶瓷电容
- 单片机电源加100μF电解电容
3.2 继电器驱动电路
继电器驱动是容易出问题的环节,必须做好保护:
-
反激二极管:
- 必须使用1N4007等快恢复二极管
- 直接并联在继电器线圈两端
- 阴极接电源正极
-
光耦隔离:
- 推荐使用PC817等光耦
- 隔离电压可达5000V
- 防止继电器干扰单片机
-
缓冲电路:
- 在继电器触点并联0.1μF电容
- 抑制触点火花
- 延长继电器寿命
3.3 电源设计
系统采用5V直流供电,需要注意:
-
稳压电路:
- 建议使用AMS1117-5.0稳压芯片
- 输入电压7-12V
- 输出电流可达800mA
-
滤波处理:
- 输入端加100μF电解电容
- 输出端加10μF钽电容
- 每个IC附近加0.1μF陶瓷电容
-
功耗估算:
- 单片机:25mA
- LCD:1mA
- 4个DS18B20:约5mA
- 继电器:70mA(吸合时)
- 蜂鸣器:15mA
4. 软件设计与实现
4.1 单总线通信协议
DS18B20的通信协议是系统中最复杂的部分,需要精确的时序控制。
4.1.1 初始化时序
复位脉冲至少480μs,之后主机释放总线,等待15-60μs内传感器的存在脉冲。
c复制bit DS18B20_Init() {
bit ack;
DQ = 1; Delay_us(8);
DQ = 0; Delay_us(500); // 拉低480us以上
DQ = 1; Delay_us(60); // 释放总线
ack = DQ; // 读取应答
Delay_us(240);
return !ack; // 返回应答信号
}
4.1.2 读写时序
写时序分为写0和写1,读时序需要15μs内采样数据。
c复制void DS18B20_WriteByte(uint8_t dat) {
for(uint8_t i=0; i<8; i++) {
DQ = 0; Delay_us(2); // 拉低开始写时序
DQ = dat & 0x01; // 输出数据位
Delay_us(60); // 保持60us
DQ = 1; // 释放总线
dat >>= 1;
}
}
uint8_t DS18B20_ReadByte() {
uint8_t dat = 0;
for(uint8_t i=0; i<8; i++) {
DQ = 0; Delay_us(2); // 拉低开始读时序
DQ = 1; Delay_us(8); // 释放总线
dat >>= 1;
if(DQ) dat |= 0x80; // 读取数据位
Delay_us(50); // 等待时序完成
}
return dat;
}
4.2 多路温度采集实现
4.2.1 ROM搜索算法
实现多路采集的关键是ROM搜索算法,这是一个二叉树搜索过程:
- 发送搜索ROM命令(0xF0)
- 读取所有器件的位响应
- 处理冲突位
- 选择一条路径继续搜索
c复制uint8_t DS18B20_SearchRom(uint8_t *rom_code, uint8_t last_diff) {
uint8_t id_bit, cmp_id_bit;
uint8_t search_dir, bit_idx = 1;
uint8_t byte_idx = 0, bit_mask = 1;
uint8_t rom_byte_mask = 1;
uint8_t last_zero = 0;
if(!DS18B20_Init()) return 0;
DS18B20_WriteByte(0xF0); // 搜索ROM命令
do {
id_bit = DS18B20_ReadBit();
cmp_id_bit = DS18B20_ReadBit();
if(id_bit && cmp_id_bit) break; // 所有器件已完成搜索
if(id_bit != cmp_id_bit) {
search_dir = id_bit; // 所有器件该位相同
} else {
// 处理冲突位
if(bit_idx < last_diff) {
search_dir = ((rom_code[byte_idx] & bit_mask) > 0);
} else if(bit_idx == last_diff) {
search_dir = 1;
} else {
search_dir = 0;
}
if(search_dir == 0) last_zero = bit_idx;
}
// 写入搜索方向
DS18B20_WriteBit(search_dir);
// 设置ROM码
if(search_dir == 1)
rom_code[byte_idx] |= bit_mask;
else
rom_code[byte_idx] &= ~bit_mask;
bit_idx++;
bit_mask <<= 1;
if(bit_mask == 0) {
byte_idx++;
bit_mask = 1;
}
} while(byte_idx < 8);
return bit_idx;
}
4.2.2 温度采集流程
完整的温度采集流程如下:
- 初始化总线
- 发送跳过ROM命令(0xCC)
- 发送开始转换命令(0x44)
- 等待转换完成(750ms@12位分辨率)
- 对每个传感器:
- 初始化总线
- 发送匹配ROM命令(0x55)
- 发送64位ROM码
- 发送读取暂存器命令(0xBE)
- 读取9字节数据(包含温度值)
4.3 报警逻辑实现
报警系统在定时器中断中处理,每500ms检查一次:
c复制void Timer0_ISR() interrupt 1 {
static uint8_t count = 0;
TH0 = 0x3C; TL0 = 0xB0; // 50ms定时
if(++count >= 10) { // 500ms
count = 0;
for(uint8_t i=0; i<MAX_SENSORS; i++) {
if(temperature[i] > threshold[i]) {
alarm_status |= (1<<i);
} else {
alarm_status &= ~(1<<i);
}
}
if(alarm_status) {
BEEP = 0; // 启动蜂鸣器
RELAY = 1; // 启动继电器
alarm_flash = ~alarm_flash; // 闪烁标志
} else {
BEEP = 1;
RELAY = 0;
alarm_flash = 0;
}
}
}
4.4 按键处理状态机
按键处理采用状态机实现,支持短按和长按:
c复制void Key_Process() {
static uint8_t key_state[3] = {0};
static uint16_t key_time[3] = {0};
for(uint8_t i=0; i<3; i++) {
switch(key_state[i]) {
case 0: // 等待按键按下
if(KEY_PORT & (1<<i)) break;
key_state[i] = 1;
key_time[i] = 0;
break;
case 1: // 消抖确认
if(KEY_PORT & (1<<i)) {
key_state[i] = 0;
break;
}
key_state[i] = 2;
break;
case 2: // 按下状态
if(KEY_PORT & (1<<i)) {
if(key_time[i] < 20) { // 短按(<400ms)
Key_ShortPress(i);
}
key_state[i] = 0;
} else if(key_time[i] > 50) { // 长按(>1s)
Key_LongPress(i);
key_state[i] = 3; // 等待释放
}
key_time[i]++;
break;
case 3: // 等待长按释放
if(KEY_PORT & (1<<i)) {
key_state[i] = 0;
}
break;
}
}
}
5. 系统优化与调试
5.1 温度采集优化
-
分辨率选择:
- DS18B20支持9-12位分辨率
- 9位:93.75ms转换时间,0.5℃精度
- 12位:750ms转换时间,0.0625℃精度
- 本系统选用12位分辨率
-
轮询策略:
- 四路传感器轮流采集
- 每路间隔200ms
- 完整周期约2秒
- 使用标志位避免重复采集
5.2 显示优化
1602液晶显示优化技巧:
-
减少全屏刷新:
- 只更新变化的部分
- 使用脏标记技术
- 避免频繁清屏
-
自定义字符:
- 创建温度单位符号
- 设计报警指示图标
- 8个自定义字符空间
c复制void LCD_InitCustomChars() {
// 自定义摄氏度符号
uint8_t degree_char[8] = {0x0E,0x0A,0x0E,0x00,0x00,0x00,0x00,0x00};
LCD_SendCmd(0x40); // CGRAM地址
for(uint8_t i=0; i<8; i++) {
LCD_SendData(degree_char[i]);
}
}
5.3 EEPROM存储
STC89C52内部EEPROM使用注意事项:
-
操作流程:
- 关闭中断
- 设置IAP_CONTR寄存器
- 执行擦除/写入
- 重新开启中断
-
数据保护:
- 关键数据加校验和
- 使用多个存储位置
- 默认值处理
c复制void EEPROM_Write(uint16_t addr, uint8_t *buf, uint8_t len) {
IAP_CONTR = 0x80; // 使能IAP
IAP_CMD = 2; // 写模式
for(uint8_t i=0; i<len; i++) {
IAP_ADDRH = addr >> 8;
IAP_ADDRL = addr & 0xFF;
IAP_DATA = buf[i];
EA = 0; // 关中断
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
EA = 1; // 开中断
addr++;
}
IAP_CONTR = 0; // 关闭IAP
IAP_CMD = 0;
}
6. 常见问题与解决方案
6.1 传感器不响应
可能原因及解决方法:
- 接线错误:
- 检查VDD、DQ、GND连接
- 确保上拉电阻正确
- 时序问题:
- 调整延时函数精度
- 检查晶振频率设置
- 电源问题:
- 测量传感器供电电压
- 尝试寄生供电模式
6.2 温度读数跳动
稳定化措施:
- 软件滤波:
- 移动平均滤波
- 中值滤波
- 一阶滞后滤波
c复制#define FILTER_LEN 5
float Temp_Filter(uint8_t ch) {
static float temp_buf[MAX_SENSORS][FILTER_LEN] = {0};
static uint8_t idx[MAX_SENSORS] = {0};
float sum = 0;
temp_buf[ch][idx[ch]] = temperature[ch];
idx[ch] = (idx[ch] + 1) % FILTER_LEN;
for(uint8_t i=0; i<FILTER_LEN; i++) {
sum += temp_buf[ch][i];
}
return sum / FILTER_LEN;
}
- 硬件改进:
- 加强电源滤波
- 缩短总线长度
- 降低总线电容
6.3 继电器误动作
抗干扰设计:
-
硬件方面:
- 增加光耦隔离
- 继电器线圈加续流二极管
- 触点加RC吸收电路
-
软件方面:
- 增加动作延迟
- 设置回差控制
- 状态变化确认
c复制#define HYSTERESIS 0.5 // 回差温度
void Alarm_Check(float temp, uint8_t ch) {
static uint8_t alarm_state[MAX_SENSORS] = {0};
if(temp > (threshold[ch] + HYSTERESIS)) {
alarm_state[ch] = 1;
} else if(temp < (threshold[ch] - HYSTERESIS)) {
alarm_state[ch] = 0;
}
if(alarm_state[ch]) {
// 触发报警动作
}
}
7. 系统扩展思路
7.1 无线传输模块
可添加的无线方案:
-
HC-12无线模块:
- 433MHz频段
- 1000米传输距离
- 串口透明传输
-
ESP8266 WiFi模块:
- 接入本地网络
- 实现Web监控
- 支持MQTT协议
7.2 数据记录功能
扩展存储方案:
-
SD卡存储:
- 使用SPI接口
- FAT32文件系统
- 按时间戳记录
-
外部EEPROM:
- AT24C256芯片
- I2C接口
- 32KB存储空间
7.3 多级报警系统
增强报警功能:
-
分级报警:
- 预警(接近阈值)
- 一般报警(超过阈值)
- 严重报警(持续超温)
-
报警方式:
- 声光报警
- 短信通知
- 自动拨号
8. 实际应用建议
-
安装注意事项:
- 传感器远离热源
- 避免阳光直射
- 做好防水处理(如需要)
-
定期维护:
- 检查传感器精度
- 清洁继电器触点
- 备份配置参数
-
安全规范:
- 强电部分绝缘处理
- 设置紧急停止开关
- 明显位置张贴警示标志
这个系统经过实验室半年实际运行,稳定监测了四个机柜的温度变化,成功预防了三次过热风险。最关键的体会是:可靠的单总线实现和合理的报警策略是系统稳定的核心。下一步计划加入远程监控功能,通过ESP8266将数据上传到服务器,实现手机随时查看。