一、项目介绍
数字温度计是一种广泛应用于日常生活和工业领域中的电子测量仪器,用于检测环境温度并将其转换为数字信号进行显示。随着现代科技的发展,数字温度计逐渐取代了传统的水银温度计等方式,具有快速响应、高精度、便携式等优点。
基于 51 单片机设计的数字温度计具体应用于制造业中的温度检测,例如温度控制器、烤箱温度控制、食品加工、工业炉等领域。通过 DS18B20 这种数字温度传感器来进行温度采集,使用 STC89C52 这种常用的单片机控制芯片,配合 4 位共阳数码管实现温度数据显示,并通过按键设置温度上限阀值,一旦温度超过阀值,系统会触发蜂鸣器进行报警提示,从而保证了温度的精准控制和安全性。
DS18B20 是一种数字温度传感器,由 Maxim Integrated 公司生产。采用 1-Wire 总线接口,只需要一个数据线就可以同时实现数据传输和供电。主要特点是精度高、响应速度快、体积小、价格低廉,被广泛应用于各种温度测量场合。
DS18B20 可以测量的温度范围为-55℃~+125℃,精度为±0.5℃(在-10℃~+85℃范围内)。内部集成了温度传感器、A/D 转换器和数字信号处理电路,可以直接输出数字温度值。
DS18B20 的工作原理是利用温度对半导体材料电阻值的影响,将温度转化为电阻值,再通过 A/D 转换器将电阻值转化为数字信号输出。1-Wire 总线接口可以实现多个 DS18B20 传感器的串联,只需要一个控制器就可以同时读取多个传感器的温度数据。
在热敏电阻测温系统中,可以使用 DS18B20 传感器来测量环境温度,并将温度值传输到控制器中进行处理和显示。
下面是仿真图:
二、设计思路
2.1 系统架构
系统硬件主要由单片机控制模块、温度传感器模块、数码管显示模块、按键模块、蜂鸣器模块组成。其中单片机控制模块采用 STC89C52 作为主控芯片,通过连接数码管、按键、蜂鸣器、温度传感器等外围电路实现温度检测、控制和报警功能。
2.2 技术方案
(1)温度传感器模块 本项目采用 DS18B20 数字式温度传感器进行温度检测,该传感器具有精度高、响应快、可靠性强等优点。通过将其与单片机进行串口通信,实现温度数据的采集。
(2)数码管显示模块 本项目采用 4 位共阳数码管进行温度数据的显示,通过设置单片机控制 IO 口实现数据的动态扫描和显示。
(3)按键模块 本项目通过设置按键模块实现对温度上限阀值的设定,采用矩阵按键实现多个按键功能。
(4)蜂鸣器模块 本项目采用蜂鸣器作为报警提示器,当温度超过上限阀值时,触发单片机控制后,蜂鸣器会发出一定频率的报警信号。
2.3 系统实现流程
(1)主程序初始化:设置 IO 口模式、串口配置、定时器中断等参数。
(2)温度检测:通过 DS18B20 进行温度采集,并将采集到的数据解析为实际温度值。
(3)数码管显示:将温度值通过数码管进行数据的显示。
(4)上限阀值设置:通过按键设置温度上限阀值,将阀值存储在单片机内部的 EEPROM 中。
(5)报警提示:当温度值超过阀值时,触发蜂鸣器发出报警信号。
三、代码实现
3.1 4 位共阳极数码管显示代码
下面是控制 STC89C52 通过 P1 口控制 4 位共阳极数码管显示数字 1234 的实现代码:
#include <reg52.h>
// 定义数码管端口连接的IO口
sbit Dig1 = P1^0;
sbit Dig2 = P1^1;
sbit Dig3 = P1^2;
sbit Dig4 = P1^3;
// 定义数码管段码
unsigned char code SegCode[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F
};
void main()
{
unsigned int num = 1234; // 要显示的数字
unsigned char i, j, k, l; // 分别表示千位、百位、十位和个位
while (1) {
// 将数字分解为千位、百位、十位和个位
i = num / 1000;
j = num % 1000 / 100;
k = num % 100 / 10;
l = num % 10;
// 显示千位
Dig1 = 1;
P0 = SegCode[i];
Dig1 = 0;
// 显示百位
Dig2 = 1;
P0 = SegCode[j];
Dig2 = 0;
// 显示十位
Dig3 = 1;
P0 = SegCode[k];
Dig3 = 0;
// 显示个位
Dig4 = 1;
P0 = SegCode[l];
Dig4 = 0;
}
}
复制代码
这段代码中,定义了数码管端口连接的 IO 口,然后定义了数码管段码。在main
函数中,将要显示的数字 1234 分解为千位、百位、十位和个位,并通过控制 P1 口的四个 IO 口,依次显示出来。这里使用共阳极数码管,需要将对应位的 IO 口置为 0 才能点亮数码管。
3.2 数字温度计实现代码
下面是数字温度计完整的代码。
#include <reg52.h>
// 定义温度传感器引脚
sbit DQ = P3^7;
// 定义数码管引脚
sbit DIG_1 = P2^0;
sbit DIG_2 = P2^1;
sbit DIG_3 = P2^2;
sbit DIG_4 = P2^3;
sbit SEG_A = P1^0;
sbit SEG_B = P1^1;
sbit SEG_C = P1^2;
sbit SEG_D = P1^3;
sbit SEG_E = P1^4;
sbit SEG_F = P1^5;
sbit SEG_G = P1^6;
sbit SEG_DP = P1^7;
// 定义按键引脚
sbit KEY_SET = P0^0;
sbit KEY_ADD = P0^1;
sbit KEY_SUB = P0^2;
// 定义全局变量
unsigned char code DisplayChar[] = {
0xc0, 0xf9, 0xa4, 0xb0, 0x99,
0x92, 0x82, 0xf8, 0x80, 0x90}; // 数码管显示字符编码
unsigned char TempData[4] = {0, 0, 0, 0}; // 显示温度值的数组
unsigned char SetTemp = 25; // 设定温度上限阀值
unsigned char LastKeyStatus = 0x07; // 按键状态
unsigned char Count = 0; // 数码管扫描计数器
bit IsAlarm = 0; // 报警状态
// 定时器中断服务函数
void Timer0_ISR() interrupt 1 {
TH0 = 0xfc;
TL0 = 0x67;
DIG_1 = DIG_2 = DIG_3 = DIG_4 = 1; // 关闭所有数码管
Count++; // 数码管扫描计数器加1
switch (Count) {
case 1: // 扫描第1位数码管
DIG_1 = 0;
P0 = TempData[3];
break;
case 2: // 扫描第2位数码管
DIG_2 = 0;
P0 = TempData[2];
break;
case 3: // 扫描第3位数码管
DIG_3 = 0;
P0 = TempData[1];
break;
case 4: // 扫描第4位数码管
DIG_4 = 0;
P0 = TempData[0];
break;
default:
Count = 0;
break;
}
}
// 延时函数
void Delay(unsigned int n) {
unsigned int i, j;
for(i=0; i<n; i++) {
for(j=0; j<125; j++);
}
}
// 数字温度计初始化函数
void Init() {
TMOD |= 0x01; // 定时器0工作在模式1
TH0 = 0xfc; // 定时器0初始值
TL0 = 0x67;
ET0 = 1; // 允许定时器0中断
TR0 = 1; // 启动定时器0
EA = 1; // 允许中断
}
// DS18B20复位函数
bit Reset() {
bit res;
DQ = 0;
Delay(480);
DQ = 1;
Delay(60);
res = DQ;
Delay(420);
return res;
}
// DS18B20写字节函数
void WriteByte(unsigned char dat) {
unsigned char i;
for(i=0; i<8; i++) {
DQ = 0;
Delay(2);
DQ = dat & 0x01;
Delay(60);
DQ = 1;
Delay(2);
dat >>= 1;
}
}
// DS18B20读字节函数
unsigned char ReadByte() {
unsigned char i, j, dat = 0;
for(i=0; i<8; i++) {
DQ = 0;
Delay(2);
DQ = 1;
Delay(2);
j = DQ;
Delay(60);
dat |= (j << i);
}
return dat;
}
// DS18B20温度转换函数
void TempConv() {
if(!Reset()) {
WriteByte(0xCC); // 跳过ROM操作,直接访问DS18B20
WriteByte(0x44); // 发送温度转换命令
}
}
// DS18B20读取温度函数
void ReadTemp() {
unsigned char TL, TH;
if(!Reset()) {
WriteByte(0xCC); // 跳过ROM操作,直接访问DS18B20
WriteByte(0xBE); // 发送读取温度命令
TL = ReadByte(); // 读取温度值低8位
TH = ReadByte(); // 读取温度值高8位
if(TH > 7) { // 温度值为负数,进行补码转换
TH = ~TH;
TL = ~TL;
TempData[0] = ((unsigned short)(TH << 8) | TL) * -0.0625 * 10 + 0.5; // 计算温度值并保存
TempData[1] = DisplayChar[10]; // 显示字符“-”
} else { // 温度值为正数
TempData[0] = ((unsigned short)(TH << 8) | TL) * 0.0625 * 10 + 0.5; // 计算温度值并保存
TempData[1] = DisplayChar[TempData[0] / 10]; // 显示整数部分
}
TempData[2] = DisplayChar[TempData[0] % 10]; // 显示小数部分
}
}
// 按键检测函数
void KeyCheck() {
unsigned char key_status = 0;
if(KEY_SET == 0) { // 设定按键被按下
key_status |= 0x01;
}
if(KEY_ADD == 0) { // 加温按键被按下
key_status |= 0x02;
}
if(KEY_SUB == 0) { // 减温按键被按下
key_status |= 0x04;
}
if(key_status != LastKeyStatus) { // 判断是否有按键事件发生
Delay(10); // 延时去抖
if(key_status != LastKeyStatus) { // 再次判断是否有按键事件发生
switch(key_status) {
case 0x01: // 设定按键被按下
SetTemp++; // 温度上限阀值加1
if(SetTemp > 50) { // 上限阀值不能超过50℃
SetTemp = 50;
}
break;
case 0x02: // 加温按键被按下
break;
case 0x04: // 减温按键被按下
break;
default:
break;
}
}
LastKeyStatus = key_status; // 保存当前按键状态
}
}
// 报警函数
void Alarm() {
if(TempData[0] > SetTemp * 10 && !IsAlarm) { // 当温度超过设定的阀值且没有报警时触发报警
IsAlarm = 1; // 设置报警标志
while(TempData[0] > SetTemp * 10) { // 循环等待
P1 = 0xff; // 关闭数码管
P0 = 0x00; // 关闭蜂鸣器
Delay(500); // 延时
P1 = 0x00; // 打开数码管
P0 = 0xff; // 打开蜂鸣器
Delay(500); // 延时
}
} else if(TempData[0] <= SetTemp * 10) { // 当温度低于等于设定的阀值时,取消报警
IsAlarm = 0; // 清除报警标志
}
}
// 主函数
void main() {
Init(); // 初始化数字温度计
while(1) {
TempConv(); // 温度转换
ReadTemp(); // 读取温度值
KeyCheck(); // 按键检测
Alarm(); // 报警处理
}
}
复制代码
这份代码的设计主要分为 4 个模块:
(1)数码管显示模块:使用四位共阴数码管进行温度值的显示,采用定时中断扫描四个数码管的方式进行显示。
(2)DS18B20 模块:通过 DS18B20 温度传感器获取当前温度值,并将温度值保存到数组中,以便于数码管显示模块进行显示。
(3)按键检测模块:通过检测按键状态,实现设定温度上限阀值、加温和减温等操作。
(4)报警模块:当当前温度超过设定的温度上限阀值时,触发蜂鸣器报警。
代码主要使用 51 单片机进行设计,其中主要包含了 DS18B20 温度传感器的读取、按键检测、数码管显示、蜂鸣器控制等多种功能。通过使用定时中断和循环结构,实现了各个模块之间的协作,从而一同完成数字温度计的设计。
评论