1. 项目概述
这个基于51单片机的温度报警系统是我最近完成的一个嵌入式开发实战项目。核心功能是通过DS18B20温度传感器采集环境温度,在数码管上实时显示当前温度值,并允许用户设置高温和低温报警阈值。当温度超出设定范围时,系统会触发声光报警(蜂鸣器鸣响+LED闪烁)。
这个看似简单的项目实际上涉及了多个嵌入式开发的关键技术点:
- 单片机外设驱动(数码管、温度传感器、蜂鸣器等)
- 状态机编程实现多模式切换
- 按键消抖与中断处理
- EEPROM数据存储
- 抗干扰设计
2. 硬件设计详解
2.1 核心器件选型
主控芯片:STC89C52RC
- 选择理由:经典的51内核单片机,资源丰富(8K Flash、512B RAM、32个I/O口),价格低廉,开发资料齐全
- 工作电压:5V±10%
- 时钟频率:11.0592MHz(精确的波特率计算)
温度传感器:DS18B20
- 单总线数字输出,无需ADC转换
- 测量范围:-55°C ~ +125°C
- 精度:±0.5°C(0°C ~ +70°C)
- 独特优势:每个器件有唯一64位序列号,支持多设备并联
显示器件:四位共阳数码管
- 型号:3461BS(0.36英寸)
- 驱动方式:动态扫描(节省I/O资源)
- 段电流:5-10mA(需加限流电阻)
2.2 电路设计要点
温度传感器电路:
code复制DS18B20
├── VCC → 5V(通过4.7K上拉电阻)
├── DQ → P2.2(单总线数据线)
└── GND → 地
关键提示:DQ线必须接4.7K上拉电阻,否则无法稳定通信。这是DS18B20的硬性要求。
数码管驱动电路:
- 段选:P0口通过74HC245驱动(增强驱动能力)
- 位选:P2.4~P2.7控制四个数码管的公共端
- 限流电阻:220Ω(保证亮度适中且不超限流)
报警输出电路:
- 蜂鸣器:P2.3通过S8050三极管驱动(有源蜂鸣器)
- LED指示灯:
- 红灯(高温报警):P1.0
- 绿灯(低温报警):P1.1
- 均需串联220Ω限流电阻
按键电路:
- KEY1(模式切换):P3.0
- KEY2(加):P3.1
- KEY3(减):P3.2
- 均采用10K上拉电阻,低电平有效
3. 软件设计实现
3.1 主程序架构
程序采用前后台系统架构:
c复制void main() {
Init_All(); // 初始化所有外设
while(1) {
KeyProcess(); // 按键扫描处理
TempProcess(); // 温度采集处理
AlarmProcess(); // 报警逻辑处理
DisplayProcess(); // 显示处理
}
}
3.2 温度采集实现
DS18B20的驱动是项目难点之一,需要严格按照时序操作:
c复制float Read_Temperature() {
u8 tempL, tempH;
Init_DS18B20(); // 复位
Write_DS18B20(0xCC); // 跳过ROM
Write_DS18B20(0x44); // 启动转换
DelayMs(750); // 等待转换完成
Init_DS18B20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE); // 读取暂存器
tempL = Read_DS18B20();
tempH = Read_DS18B20();
return (tempH<<8 | tempL) * 0.0625; // 转换为实际温度
}
实测经验:DS18B20的转换时间与分辨率有关,12位分辨率时最大需750ms。如果读取太快会得到前一次的值。
3.3 数码管显示优化
动态扫描容易出现闪烁和残影,优化方案:
- 使用定时器中断保证扫描频率稳定(建议1ms中断一次)
- 显示前先关闭所有段选(消隐处理)
- 采用查表法提高效率
c复制// 数码管段码表(共阳)
u8 code ledtab[] = {
0xC0, 0xF9, 0xA4, 0xB0, 0x99, // 0-4
0x92, 0x82, 0xF8, 0x80, 0x90 // 5-9
};
void Timer0_ISR() interrupt 1 {
static u8 pos = 0;
TH0 = 0xFC; TL0 = 0x66; // 1ms定时
P0 = 0xFF; // 消隐
switch(pos) {
case 0: P0=ledtab[temp/10]; P2_4=0; break; // 十位
case 1: P0=ledtab[temp%10]&0x7F; P2_5=0; break; // 个位+小数点
case 2: P0=ledtab[HighTemp/10]; P2_6=0; break; // 高温阈值十位
case 3: P0=ledtab[LowTemp/10]; P2_7=0; break; // 低温阈值十位
}
if(++pos ==4) pos=0;
}
3.4 按键状态机设计
采用状态机模式实现三种状态切换:
- 正常显示模式
- 高温设置模式
- 低温设置模式
c复制void KeyProcess() {
static u8 mode=0; // 0-正常 1-高温设置 2-低温设置
if(!KEY1) { // 模式切换键
DelayMs(15);
if(!KEY1) {
mode = (mode+1)%3;
if(mode==0) Save_To_EEPROM(); // 退出设置时保存
while(!KEY1); // 等待释放
}
}
if(mode==1) { // 高温设置
if(!KEY2) HighTemp = (HighTemp<95)? HighTemp+1 : 99;
if(!KEY3) HighTemp = (HighTemp>LowTemp+5)? HighTemp-1 : LowTemp+5;
LowTemp = HighTemp-5; // 保持5度温差
}
// 低温设置类似...
}
4. 关键问题与解决方案
4.1 温度数据跳变问题
现象:温度显示偶尔出现大幅跳变
原因分析:
- DS18B20通信受干扰
- 读取时序不严格
- 电源不稳定
解决方案:
- 在DQ线加104滤波电容
- 严格遵循器件手册的时序要求
- 增加数据校验机制(连续读取三次取中间值)
c复制float Get_Valid_Temp() {
float temp[3];
for(u8 i=0; i<3; i++) {
temp[i] = Read_Temperature();
DelayMs(200);
}
// 排序取中值
if(temp[0]>temp[1]) swap(&temp[0],&temp[1]);
if(temp[1]>temp[2]) swap(&temp[1],&temp[2]);
if(temp[0]>temp[1]) swap(&temp[0],&temp[1]);
return temp[1];
}
4.2 数码管残影问题
现象:切换显示内容时有残留影像
解决方法:
- 显示前先关闭所有段选
- 增加消隐时间(20us足够)
- 优化扫描频率(1ms/位)
4.3 EEPROM写入导致系统卡顿
现象:设置参数时系统响应变慢
原因:STC89C52的EEPROM实际上是Flash模拟的,写入需要5-10ms
优化方案:
- 只在退出设置模式时保存一次
- 使用RAM缓存设置值
- 写入前关闭中断,写入后恢复
c复制void Save_To_EEPROM() {
EA = 0; // 关闭中断
IAP_Erase(0x2000); // 擦除扇区
IAP_Write(0x2000, HighTemp);
IAP_Write(0x2001, LowTemp);
EA = 1; // 恢复中断
}
5. 系统优化与扩展
5.1 报警延时触发机制
为避免温度临界波动导致误报警,采用延时触发策略:
- 连续5秒超限才触发报警
- 报警后温度回到正常范围立即停止
c复制void AlarmProcess() {
static u16 alarm_cnt = 0;
if(temp > HighTemp || temp < LowTemp) {
if(++alarm_cnt >= 500) { // 5秒
BEEP = ~BEEP; // 蜂鸣器鸣响
ALARM_LED = ~ALARM_LED; // LED闪烁
}
} else {
alarm_cnt = 0;
BEEP = 1; // 关闭报警
ALARM_LED = 1;
}
}
5.2 扩展思路
- 无线通信模块:添加HC-05蓝牙模块,通过手机APP设置参数
- 数据记录功能:使用SD卡模块记录温度历史数据
- 多路温度监测:利用DS18B20的单总线特性,并联多个传感器
- LCD显示升级:改用12864液晶显示更丰富信息
c复制// 蓝牙通信示例代码
void UART_Init() {
SCON = 0x50; // 模式1
TMOD |= 0x20; // 定时器1模式2
TH1 = 0xFD; // 9600bps@11.0592MHz
TR1 = 1;
ES = 1; // 开启串口中断
EA = 1;
}
void UART_ISR() interrupt 4 {
if(RI) {
u8 cmd = SBUF;
RI = 0;
// 解析手机APP指令...
}
}
6. 项目总结与心得
通过这个项目,我深刻体会到几个嵌入式开发的重要原则:
- 时序就是生命:DS18B20的严格时序要求让我明白,外设驱动必须精确到微秒级
- 中断要精简:最初把太多逻辑放在中断中导致系统不稳定,后来只保留最必要的数码管扫描
- 硬件设计要预留调试手段:比如在关键信号线留出测试点,大大提高了排查效率
- 抗干扰设计必不可少:简单的滤波电容就能解决很多玄学问题
一个建议给想复现这个项目的朋友:在焊接DS18B20时,尽量使用插座而不是直接焊接,因为高温容易损坏传感器。另外,调试时先用固定电阻模拟温度值,可以快速验证系统逻辑是否正确。