基于51单片机的上下限可调的数字温度控制系统
摘要:设计并制作了数字温度显示控制系统,能够实时显示环境温度,并在超温限情况下报警提示和进行相应的温度控制。上下限温度可以人工调节,并能通过串口显示在pc机上。测温范围0~100℃,误差0.1℃以内。系统通过单片机STC89C52、温度传感器DS18B20、液晶1602以及串口模块组成,上机位软件用VB编写。实验测试通过,该系统可用于工业上对温度的监测和控制。
关键词:数字显示;温控;上下限可调;上位机
最近大家一直私信我要proteus的仿真,现在奉上链接:https://download.csdn.net/download/fddnihao/87838133
1.作品功能及总体方案
1.1 功能描述
本设计设计并制作了数字温度显示控制系统。主要应用了STC89C52单片机作为核心,综合应用了单片机中断系统、定时器、计数器等知识。整个系统由单片机最小系统、DS18B20数字温度传感器、1602液晶以及串口模块等部件组成。本数字温度控制系统属于多功能温度计,功能较强,可以设置上下限报警温度,且测量准确、误差小,并能通过串口实时显示在PC机上。当测量温度超过设定的温度上下限时,启动蜂鸣器报警,同时温度控制部分作出相应动作,加热或者降温。本设计采用三个不同颜色LED灯的亮灭来代替实际的温控部分,红灯模拟加热,黄灯模拟正常工作,绿灯模拟制冷。
1.2 系统组成及工作过程
图1 系统组成框图
本系统由STC89C52单片机主控,通过晶振时钟模块、复位电路模块、按键模块、液晶显示模块、报警控制模块、串口通信模块以及传感器模块组成。系统通过DS18B20获取温度经过处理后,显示在液晶上,通过按键调整上下限温度,超限进行相应的报警和控制,通过串口通信模块显示在PC上。
2.硬件设计
2.1 硬件电路总体设计
见附录二
2.2 单片机最小系统设计
图2 STC89C52单片机
图3 晶振电路
图4 复位电路
STC89C52(如图2)是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有 8K在线系统可编程Flash存储器。STC89C52使用经典的MCS-51内核,但做了很多的改进使得芯片具有传统51单片机不具备的功能。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。鉴于STC89C52的价格低廉,方便易用,资料丰富,故选择该单片机作为主控芯片。
晶振电路(如图3),STC89C52的时钟有两种方式,一种是片内时钟振荡方式,但需在18和19脚外接石英晶体(2-12MHz)和振荡电容,振荡电容的值一般取10p-30p。另外一种是外部时钟方式,即将XTAL1接地,外部时钟信号从XTAL2脚输入。 本设计采用片内时钟,用外部晶振产生12MHz的时钟信号。XTAL1和XTAL2分别为反向放大器的输入和输出。该反向放大器可以配置为片内振荡器。石晶振荡和陶瓷振荡均可采用。
复位电路采用简单的上电复位方式(如图4),电容在上接高电平,电阻在下接地,中间为RST。这种复位电路的工作原理是:通电时,电容两端相当于是短路,于是RST引脚上为高电平,然后电源通过电阻对电容充电,RST端电压慢慢下降,降到一定程序,即为低电平,单片机开始正常工作。
2.3 温度检测模块电路设计
温度传感器的种类众多,在应用与高精度、高可靠性的场合时 DALLAS(达拉斯)公司生产的 DS18B20 温度传感器当仁不让。超小的体积,超低的硬件开消,抗干扰能力强,精度高,附加功能强,使得 DS18B20 更受欢迎。DS18B20 的主要特征:全数字温度转换及输出;检测温度范围为–55°C~+125°C;内置 EEPROM,限温报警功能;独特的单线接口仅需要一个端口引脚进行通信;这些特征完全符合我们的设计需求。
DS18B20它有64 位ROM 的结构开始8 位是产品类型的编号,接着是每个器件的惟一的序号,共有48 位,最后8 位是前面56位的CRC 检验码,这也是多个DS18B20 可以采用一线进行通信的原因。温度报警触发器TH 和TL,可通过软件写入户报警上下限。
另外,由于DS18B20 单线通信功能是分时完成的,它有严格的时隙概念,因此读写时序很重要。系统对DS18B20 的各种操作按协议进行。操作协议为:初始化DS18B20(发复位脉冲)→发ROM 功能命令→发存储器操作命令→处理数据。
DS18B20芯片封装结构如图5:
图5 DS18B20芯片封装结构
本设计采用左图直插式的。
2.4 独立键盘模块
独立式按键是指直接用I/O线构成的单个按键电路,每个独立式按键占有一根I/O口线,每根I/O口线上的按键的工作状态不会影响其他I/O口线的工作状态,其结构简单,但I/O口线浪费有些大。由于本设计所控制的电器数目较少,所以不用外接扩充键盘,直接使用单片机上的接口,直接使用3个点触式开关即可。
独立式按键配置灵活,软件结构简单,其电路原理图如下:
图6 独立按键电路
2.5 液晶显示模块
液晶是一种高分子材料,因为其特殊的物理、化学、光学特性,20世纪中叶开始广泛应用在轻薄型显示器上。液晶显示器的主要原理是以电流刺激液晶分子产生点、线、面并配合背光灯管构成画面。液晶体积小,功耗低,显示操作方便。常见的有1602、12232、12864等,本设计采用的是有两行每行显示16个字符的lcd1602(如图7)。
图7 LCD1602液晶显示模块
本实验采用的1602液晶为5V电压驱动,带背光,内置有128个字符的ASCII字符集字库,只有并行接口,无串行接口。
1602LCD主要技术参数:
显示容量:16×2个字符
芯片工作电压:4.5—5.5V
工作电流:2.0mA(5.0V)
模块最佳工作电压:5.0V
字符尺寸:2.95×4.35(W×H)mm
引脚功能说明:
1602LCD的指令说明及时序:
读写操作时序如图8和图9所示:
图8 读操作时序
图9 写操作时序
2.6 报警控制模块
本设计采用三个不同颜色LED灯的亮灭来代替实际的温控部分,红灯模拟加热,黄灯模拟正常工作,绿灯模拟制冷。用蜂鸣器的不同频率的声音来模拟高温报警和低温报警,实现报警部分。报警控制模块(如图10和11)。
图10 温度报警控制模块–蜂鸣器
图11 温度报警控制模块–报警灯
2.7 串口通信模块
在实现单片机与PC机之间通信或单片机与单片机之间远程距离通信时通常采用标准串行总线通讯接口。比如RS-232C、RS-422、RS485等。在这些串行总线接口标准中,是在异步串行通信中应用最广的标准总线,它实用于短距离或带调制解调器的通信场合。本设计采用RS-232标准串行总线接口。 当51单片机与PC机通过RS-232标准总线串行通信时,由于RS-232信号电平与51单片机信号电平不一致,因此,必须进行信号电平转换。其常用的方法有两种,一种是采用运算放大器、晶体管、光电隔离器等器件组成的电路来实现,另一种是采用专门集成芯片来实现。下面以MAX232专门集成芯片为例来介绍接口电路的实现。
图12是由芯片MAX232实现51单片机与PC机串行通信的典型接线图。图中外接电解电容C4,C5,C6,C7用于电源电压变换,提高抗干扰能力,它们可以取相同数值电容0.1uF。选择任一组电平转换电路实行串行通信,如图中选T1IN,R1OUT分别与51单片机的TXD,RXD相连,T1OUT,R1IN分别与PC机中RS232接口的RXD,TXD相连,这种发送与接收的对应关系不能连错,否则不能正常工作。
图12 用MAX232实现串行通信接口电路图
3.软件设计
3.1 软件总体设计
图13 软件总体设计流程图
3.2 温度模块程序设计
先编写初始化复位子函数,然后引用该子函数进行复位,复位→忽略ROM匹配(0xcc)→温度转换(0x44)→延时→复位→忽略ROM匹配→读指令→分别读取温度两个字节。
图14 DS18B20程序流程图
3.3 液晶显示模块程序设计
图15 液晶显示函数流程图
3.4 按键检测流程图
图16 按键检测流程图
3.5 串口通信上机位软件设计
本设计采用VB6.0(企业版)调用MSComm控件接收数据、处理数据,设置串口为7,波特率为2400,调用TextBox控件显示数据,用Label控件显示一些标签文字,用shape控件画三个不同颜色的圆代表不同状态,最后生成exe可执行文件。完成后运行上机位软件界面如下图17所示。
图17 上机位软件界面
4.实验及结果
4.1 温度采集与显示报警
首先接上电源,插上串口,打开开关。温度介于最低和最高之间时,液晶显示如图17所示,黄灯点亮,无蜂鸣器报警。温度低于最低温度时,液晶显示如图18所示,红灯点亮,蜂鸣器以长“嘀”声报警。温度高于最高温度时,液晶显示如图19所示,绿灯点亮,蜂鸣器以短“嘀”声报警,温度低于0度或超出99.9度时,液晶显示如图20所示,无灯亮,无蜂鸣器报警。
图18 温度正常
图19 温度过低
图20 温度过高
图21 温度越界
4.2 温度报警上下限调节
为了便于测试,程序设定温度上限默认值为30℃,温度下限默认值25℃,按一下“设置”键,温度开始设定最高温度,液晶显示如图22所示,此时可以通过按“增加”或“减小”键来设置上限。按两下“设置”键,温度开始设置最低温度,液晶显示如图23所示,此时可以通过按“增加”或“减小”键来设置下限。按三下“设置”键,回到正常显示。
图22 设置温度上限
图23 设置温度下限
4.3 串口通信显示
设置好波特率和串口号,运行上机位软件,打开单片机电源开关,上机位显示界面如图24所示,上机位软件利于操作人员在室内电脑上监控温度变化,可以拓展到多个节点采集温度的情况。
图24 上机位显示界面
附录1 实物照片
附录2 硬件电路图
附录3 试验源程序
主程序,负责主要功能:
/******************************************************************
程序名称:DS18B20温度测量、报警控制系统
简要说明:DS18B20温度计,温度测量范围0~99.9摄氏度
可设置上限报警温度、下限报警温度
即高于上限值或者低于下限值时蜂鸣器报警,相应的led等亮
默认上限报警温度为30℃、默认下限报警温度为25℃
报警值可设置范围:最低上限报警值等于当前下限报警值
最高下限报警值等于当前上限报警值
将下限报警值调为0时为关闭下限报警功能
******************************************************************/
#include <reg52.h>
#include <stdio.h>
#include "ds18b20.h"
#include "lcd1602.h"
#define uchar unsigned char
#define uint unsigned int
sbit beep=P1^3; //蜂鸣器
sbit SET=P3^5; //定义按键--功能键
sbit ADD=P3^2; //定义按键--增加键
sbit DEC=P3^3; //定义按键--减小键
sbit led0=P2^2;
sbit led1=P2^3;
sbit led2=P2^4;
uint warn_l=250;
uint warn_h=300;
uchar SETnum;
//*******************************************
void delay1ms(uint z) //延时程序
{
uint x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
//*******************************************
di() //按键音
{
beep=0;
delay1ms(100);
beep=1;
}
//*******************************************
void warn(uchar s) //报警音
{
beep=0;
delay1ms(s);
beep=1;
}
//*******************************************
void deal(uint t) //温度处理函数
{ if(SETnum==0)
{
if(t>0&&t<1000)
{
write_com(0x80); //液晶显示温度
write_str("temp: ");
write_com(0x80+8);
write_data((temp/100)%10+48);
write_data((temp/10)%10+48);
write_data('.');
write_data(temp%10+48);
write_data(0xdf);
write_data('c');
if(t<=warn_l&&t>=0) //低于最低温度,红灯亮模拟加热,并以短滴声报警
{
led0=1;
led1=1;
write_com(0x80+0x40);
write_str("under low temp! ");
warn(400);
led2=0;
}
else if(t<warn_h&&t>warn_l) //正常温度 ,以黄灯指示
{
led0=1;
led2=1;
write_com(0x80+0x40);
write_str("normal temp! ");
led1=0;
}
else //高于最高温度,绿灯亮模拟降温,并以长嘀声报警
{ led2=1;
led1=1;
write_com(0x80+0x40);
write_str("over high temp! ");
warn(50);
led0=0;
}
}
else //超过100度或低于0度提示错误
{ led0=1;
led1=1;
led2=1;
write_com(0x80);
write_str("out of range! ");
write_com(0x80+0x40);
write_str("error temp! ");
}
}
else if(SETnum==1) //设置最高温度
{
write_com(0x80);
write_str(" Temp-setting ");
write_com(0x80+0x40);
write_str(" warn_h: ");
write_com(0x80+0x40+10);
write_data((warn_h/100)%10+48);
write_data((warn_h/10)%10+48);
write_data('.');
write_data(warn_h%10+48);
write_data(0xdf);
write_data('c');
EX0=1; //开启外部中断0
EX1=1; //开启外部中断1
}
else if(SETnum==2) //设置最低温度
{
write_com(0x80);
write_str(" Temp-setting ");
write_com(0x80+0x40);
write_str(" warn_l:");
write_com(0x80+0x40+10);
write_data((warn_l/100)%10+48);
write_data((warn_l/10)%10+48);
write_data('.');
write_data(warn_l%10+48);
write_data(0xdf);
write_data('c');
EX0=1; //开启外部中断0
EX1=1; //开启外部中断1
}
else
{SETnum=0;
EX0=0; //关闭外部中断0
EX1=0; //关闭外部中断1
}
}
//*******************************************
void init_com(void) //串口初始化函数
{
TMOD = 0x20;
PCON = 0x00;
SCON = 0x50;
TH1 = 0xF3; //波特率2400
TL1 = 0xF3;
TR1 = 1;
}
//*******************************************
void comm(char *parr) //串口数据发送函数
{
do
{
SBUF = *parr++; //发送数据
while(!TI); //等待发送完成标志为1
TI =0; //标志清零
}while(*parr); //保持循环直到字符为'\0'
}
//*******************************************
void main()
{ uchar buff[4];
EA=1; //全局中断开关
IT0=1; //跳变沿触发方式
IT1=1;
init_com();
init_1602();
delay1ms(1000);
while(1)
{
tempchange(); //温度转换函数
temp=get_temp();//获取温度
sprintf(buff,"%f",f_temp);//将浮点型温度格式转化为字符型
deal(temp); //进行温度处理
high=warn_h/10.0;
low=warn_l/10.0;
sprintf(buff0,"%f",f_temp);//将浮点型温度格式转化为字符型
sprintf(buff1,"%f",high);//将浮点型温度格式转化为字符型
sprintf(buff2,"%f",low);//将浮点型温度格式转化为字符型
comm(buff0); //串口发送数据
comm(buff1); //串口发送数据
comm(buff2); //串口发送数据
if(SET==0) //按键检测
{delay1ms(5);
if(SET==0)
{ SETnum++;
while(!SET);
di();
}
}
}
}
//*******************************************
void int0(void) interrupt 0 //外部中断0函数
{
EX0=0; //关外部中断0
if(ADD==0)
{delay1ms(5);
if(ADD==0) //温度加
{
while(!ADD);
di();
if(SETnum==1)
{ warn_h+=10;
if(warn_h>999)
warn_h=999;
}
if(SETnum==2)
{ warn_l+=10;
if(warn_l>warn_h)
warn_l=warn_h;
}
}
}
}
//*******************************************
void int1(void) interrupt 2 //外部中断1函数
{
EX1=0; //关外部中断1
if(DEC==0)
{delay1ms(5);
if(DEC==0)
{
while(!DEC);
di();
if(SETnum==1)
{ warn_h-=10;
if(warn_h<warn_l)
warn_h=warn_l;
}
if(SETnum==2)
{ warn_l-=10;
if(warn_l<0)
warn_l=0;
}
}
}
}
ds18b20子程序,负责温度的获取与转换:
#define uchar unsigned char
#define uint unsigned int
sbit ds=P2^0; //温度传感器信号线
float f_temp; //定义浮点型的温度数据
uint temp; //定义整型的温度数据
void delay1ms(uint z);
void dsreset(void) //18B20复位,初始化函数
{
uint i;
ds=0;
i=103;
while(i>0)i--;
ds=1;
i=4;
while(i>0)i--;
}
bit tempreadbit(void) //读1位函数
{
uint i;
bit dat;
ds=0;i++; //i++ 起延时作用
ds=1;i++;i++;
dat=ds;
i=8;while(i>0)i--;
return (dat);
}
uchar tempread(void) //读1个字节
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在dat里
}
return(dat);
}
void tempwritebyte(uchar dat) //向DS18B20写一个字节数据
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) //写 1
{
ds=0;
i++;i++;
ds=1;
i=8;while(i>0)i--;
}
else
{
ds=0; //写 0
i=8;while(i>0)i--;
ds=1;
i++;i++;
}
}
}
//**********************************
void tempchange(void) //DS18B20 开始获取温度并转换
{
dsreset();
delay1ms(1);
tempwritebyte(0xcc); // 写跳过读ROM指令
tempwritebyte(0x44); // 写温度转换指令
}
uint get_temp() //读取寄存器中存储的温度数据
{
uchar a,b;
dsreset();
delay1ms(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe);
a=tempread(); //读低8位
b=tempread(); //读高8位
temp=b;
temp<<=8; //两个字节组合为1个字
temp=temp|a;
f_temp=temp*0.0625; //温度在寄存器中为12位 分辨率位0.0625°
temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入
f_temp=f_temp+0.05;
return temp; //temp是整型
}
LCD1602子程序,负责温度显示:
#define uchar unsigned char
#define uint unsigned int
sbit lcden=P3^7; //液晶使能端
sbit lcdrs=P3^4; //液晶数据命令选择端
sbit lcdrw=P3^6; //读写选择端
//**********************************
void write_com(uchar com)//写命令操作
{ lcdrs=0;
P0=com;
delay1ms(5);
lcden=1;
delay1ms(5);
lcden=0;
}
void write_data(uchar date)//写数据操作
{
lcdrs=1;
P0=date;
delay1ms(5);
lcden=1;
delay1ms(5);
lcden=0;
}
void write_str(uchar *str)//写字符串
{
while(*str!='\0') //字符串未结束
{
write_data(*str++);
delay1ms(1);
}
}
//**********************************
void init_1602() //液晶初始化
{
uchar table[16]={0};
uchar table1[16]={0};
lcdrw=0;
lcden=0;
write_com(0x38); //设置16x2显示,5x7点阵,八位数据接口
write_com(0x0c); //设置开显示,不显示光标
write_com(0x06); //写一个字符后地址指针加1
write_com(0x01); //显示清0,数据指针清0
}
//**********************************
VB上机位程序,负责上机位显示:
Private Sub Form_Load()
MSComm1.Settings = "2400,N,7,1" '波特率2400bit/s,无校验,8位数据,1位停止位
MSComm1.CommPort = 7 '设定串口,为comm7
MSComm1.InBufferSize = 10 '设置返回接收缓冲区的大小,以字符为单位。
MSComm1.OutBufferSize = 2
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False '关串口
MSComm1.RThreshold = 4 '设置并返回产生oncomm事件的字符数,以字符为单位. Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件。
MSComm1.SThreshold = 1 '
MSComm1.InputLen = 0 '设置从接收缓冲区读取的字数,为0读取整个缓冲区
MSComm1.InputMode = comInputModeText '以文本方度接收
If MSComm1.PortOpen = False Then MSComm1.PortOpen = True
MSComm1.InBufferCount = 0 '清空接收缓冲区
Me.Caption = "温度显示"
Text1.Text = "00.0"
Text2.Text = "00.0"
Text3.Text = "00.0"
Picture = Form1.Picture '背景图片
Me.AutoRedraw = True
End Sub
Private Sub MSComm1_OnComm()
Dim rec As String
Dim temp As String
Dim max As String
Dim min As String
Select Case MSComm1.CommEvent
Case comEvReceive
rec = MSComm1.Input
temp = Mid(rec, 1, 4) '用mid函数将接收到的字符串分开
max = Mid(rec, 5, 4)
min = Mid(rec, 9, 4)
Text1.Text = temp
Text2.Text = max
Text3.Text = min
If temp > max Then '温度处理
Shape1.FillColor = QBColor(10)
Shape2.FillColor = QBColor(7)
Shape3.FillColor = QBColor(7)
End If
If temp <= max And temp >= min Then
Shape1.FillColor = QBColor(7)
Shape2.FillColor = QBColor(14)
Shape3.FillColor = QBColor(7)
End If
If temp < min Then
Shape1.FillColor = QBColor(7)
Shape2.FillColor = QBColor(7)
Shape3.FillColor = QBColor(12)
End If
MSComm1.InBufferCount = 0 '清空接收缓冲区
End Select
End Sub
Private Sub Form_Resize()
Me.PaintPicture Me.Picture, 0, 0, Me.Width, Me.Height
End Sub
更多推荐
所有评论(0)