注:本设计资源可在微信公众号:“Kevin的学习站” 中获取!
主要实现:实时温度测量及显示,超出温度范围声光报警,上下限温度可通过按键设定等功能。
本数字温度报警器是基于51单片机及温度传感器DS18B20来设计的,温度测量范围0到99.9摄氏度,精度为0.1摄氏度,可见测量温度的范围广,精度高的特点。可设置上下限报警温度,默认上限报警温度为38℃、默认下限报警温度为5℃(通过程序可以更改默认上下限值)。报警值可设置范围:最低上限报警值等于当前下限报警值,最高下限报警值等于当前上限报警值。将下限报警值调为0时为关闭下限报警功能。
基本范围0℃-99℃ ;
精度误差小于 0.1℃ ;
数码管直读显示;
扩展功能:可以任意设定温度的上下限报警功能。
由于单片机具有以下的很多优点,被我们选定为制作该作品的首选芯片
单片机特点:
(1)高集成度,体积小,高可靠性
单片机将各功能部件集成在一块晶体芯片上,集成度很高,体积自然也是最小的。芯片本身是按工业测控环境要求设计的,内部布线很短,其抗工业噪音性能优于一般通用的CPU。单片机程序指令,常数及表格等固化在ROM中不易破坏,许多信号通道均在一个芯片内,故可靠性高。
(2)控制功能强
为了满足对对象的控制要求,单片机的指令系统均有极丰富的条件:分支转移能力,I/O口的逻辑操作及位处理能力,非常适用于专门的控制功能。
(3)低电压,低功耗,便于生产便携式产品
为了满足广泛使用于便携式系统,许多单片机内的工作电压仅为1.8V~3.6V,而工作电流仅为数百微安。
(4)易扩展
片内具有计算机正常运行所必需的部件。芯片外部有许多供扩展用的三总线及并行、串行输入/输出管脚,很容易构成各种规模的计算机应用系统。
(5)优异的性能价格比
单片机的性能极高。为了提高速度和运行效率,单片机已开始使用RISC流水线和DSP等技术。单片机的寻址能力也已突破64KB的限制,有的已可达到1MB和16MB,片内的ROM容量可达62MB,RAM容量则可达2MB。由于单片机的广泛使用,因而销量极大,各大公司的商业竞争更使其价格十分低廉,其性能价格比极高。
方案一:
采用STC89C51芯片作为硬件核心。STC89C51内部具有8KB ROM 存储空间,512字节数据存储空间,带有2K字节的EEPROM存储空间,与MCS-51系列单片机完全兼容,STC89C51可以通过串口下载。
方案二:
采用AT89S51。AT89S51片内具有8K字节程序存储空间,256字节的数据存储空间没有EEPROM存储空间,也与MCS-51系列单片机完全兼容,具有在线编程可擦除技术。
两种单片机都完全能够满足设计需要,STC89C51相对ATS89C52价格便宜,且抗干扰能力强。考虑到成本因素,因此选用STC89C51。
方案一:
由于本设计是测温电路,可以使用热敏电阻之类的器件利用其感温效应,在将随被测温度变化 的电压或电流采集过来,进行 A/D 转换后,就可以用单片机进行数据的处理,在显示电路上,就可以将被测温度显示出来,这种设计需要用到 A/D 转换电路,感温电路比较麻烦。
方案二:
进而考虑到用温度传感器,在单片机电路设计中,大多都是使用传感器,所以这是非常容易想到的,所以可以采用一只温度传感器 DS18B20,此传感器,可以很容易直接读取被测温度值,进行转换,就可以满足设计要求。
从以上两种方案,两种都完全能够满足设计需要,很容易看出,采用方案二,电路比较简单,软件设计也比较简单,故采用了方案二。
综上各方案所述,对此次作品的方案选定: 采用STC89C51单片机作为主控制系统;采用DS18B20为传感器;采用数码管作为显示器件。
STC89C51是由深圳宏晶科技公司生产的与工业标准MCS-51指令集和输出管脚相兼容的单片机。
STC89C51主要功能如表1所示,其PDIP封装如图1所示
主要功能特性
兼容MCS51指令系统 8K可反复擦写Flash ROM
32个双向I/O口 256x8bit内部RAM
3个16位可编程定时/计数器中断 时钟频率0-24MHz
2个串行中断 可编程UART串行通道
2个外部中断源 共6个中断源
2个读写中断口线 3级加密位
低功耗空闲和掉电模式 软件设置睡眠和唤醒功能
表1:STC89C51主要功能
① 主电源引脚(2根)
VCC(Pin40):电源输入,接+5V电源
GND(Pin20):接地线
②外接晶振引脚(2根)
XTAL1(Pin19):片内振荡电路的输入端
XTAL2(Pin20):片内振荡电路的输出端
③控制引脚(4根)
RST/VPP(Pin9):复位引脚,引脚上出现2个机器周期的高电平将使单片机复位。
ALE/PROG(Pin30):地址锁存允许信号
PSEN(Pin29):外部存储器读选通信号
EA/VPP(Pin31):程序存储器的内外部选通,接低电平从外部程序存储器读指令,如果接高电平则从内部程序存储器读指令。
④可编程输入/输出引脚(32根)
STC89C51单片机有4组8位的可编程I/O口,分别位P0、P1、P2、P3口,每个口有8位(8根引脚),共32根。
P0口(Pin39~Pin32):8位双向I/O口线,名称为P0.0~P0.7
P1口(Pin1~Pin8):8位准双向I/O口线,名称为P1.0~P1.7
P2口(Pin21~Pin28):8位准双向I/O口线,名称为P2.0~P2.7
P3口(Pin10~Pin17):8位准双向I/O口线,名称为P3.0~P3.7
当在STC89C51单片机的RST引脚引入高电平并保持2个机器周期时,单片机内部就执行复位操作,按键手动复位有电平方式和脉冲方式两种。其中电平复位是通过RST端经过电阻与电源VCC接通而实现的。最小系统如图2所示。
电路以STC89C51单片机最小系统为控制核心,测温电路由DS18B20提供,输入部分采用三个独立式按键S1、S2、S3。数码管显示部分。具体电路连接,详见附录1。
DS18B20的性能特点如下:
(1) 采用DALLAS公司独特的单线接口方式:DS18B20与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯;
(2)在使用中不需要任何外围元件;
(3)可用数据线供电,供电电压范围:+3.0V~+5.5V;
(4)测温范围:-55~+125℃。固有测温分辨率为0.5℃。当在-10℃~+85℃范围内,可确保测量误差不超过0.5℃,在-55~+125℃范围内,测量误差也不超过2℃;
(5)通过编程可实现9~12位的数字读数方式;
(6)用户可自设定非易失性的报警上下限值;
(7)支持多点的组网功能,多个DS18B20可以并联在唯一的三线上,实现多点测温
(8)负压特性,即具有电源反接保护电路。当电源电压的极性反接时,能保护DS18B20不会因发热而烧毁,但此时芯片无法正常工作;
(9)DS18B20的转换速率比较高,进行9位的温度值转换只需93.75ms;
(10)适配各种单片机或系统;
(11)内含64位激光修正的只读存储ROM,扣除8位产品系列号和8位循环冗余校验码(CRC)之后,产品序号占48位。出厂前产品序号存入其ROM中。在构成大型温控系统时,允许在单线总线上挂接多片DS18B20。
3.2.2 DS18B20引脚介绍
图3:DS18B20引脚
各引脚功能为:I/O为数据输入/输出端(即单线总线),它属于漏极开路输出,外接上拉电阻后,常态下呈高电平。UDD是可供选用的外部电源端,不用时接地,GND为地,NC空脚。
3.2.3 DS18B20的内部结构
DS18B20的内部结构主要包括7部分:寄生电源、温度传感器、64位激光(loser)ROM与单线接口、高速暂存器(即便筏式RAM,用于存放中间数据)、TH触发寄存器和TL触发寄存器,分别用来存储用户设定的温度上下限值、存储和控制逻辑、位循环冗余校验码(CRC)发生器。
图4:DS18B20内部结构
通过上述原理,已对密码锁整体运行环境有了充分认识,绘制主程序和子程序流程图,利用Keil软件,对单片机进行编程,如图4-1为主程序功能流程图:
4-1主程序功能流程图
如图4-2为温度采集的软件设计,主要功能是完成DS18B20的初始化工作,并进行读温度,将温度转化成为压缩BCD码 并在显示器上显示传感器所测得的实际温度。读出温度子程序的主要功能是读出RAM中的9字节,在读出时需要进行CRC校验,校验有错时不进行温度数据的改写。
如下图为温度采集算法流程图,计算温度子程序将RAM中读取值进行BCD码的转换运算,并进行温度值正负的判定,其程序流程图。
如下图为温度转换命令子程序流程图,温度转换命令子程序主要是发温度转换开始命令,当采用12位分辩率时转换时间约为750ms,在本程序设计中采用1s显示程序延时法等待转换的完成。
图5-1为正常温度界面图,图5-2为报警温度界面,实现实时显示和温度报警。
#include
#define uint unsigned int
#define uchar unsigned char //宏定义
#define SET P3_1 //定义调整键
#define DEC P3_2 //定义减少键
#define ADD P3_3 //定义增加键
#define BEEP P3_6 //定义蜂鸣器
#define ALAM P1_2 //定义灯光报警
#define DQ P3_7 //定义DS18B20总线I/O
bit shanshuo_st; //闪烁间隔标志
bit beep_st; //蜂鸣器间隔标志
sbit DIAN = P0^5; //小数点
uchar x=0; //计数器
signed char m; //温度值全局变量
uchar n; //温度值全局变量
uchar set_st=0; //状态标志
signed char shangxian=38; //上限报警温度,默认值为38
signed char xiaxian=5; //下限报警温度,默认值为38
//uchar code LEDData[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};
uchar code LEDData[]={0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7,0xCF,0xDA,0x9B,0xDC,0x9B,0x8B};
//============================================================================================
//====================================DS18B20=================================================
//============================================================================================
/*****延时子程序*****/
void Delay_DS18B20(int num)
{
while(num--) ;
}
/*****初始化DS18B20*****/
void Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ复位
Delay_DS18B20(8); //稍做延时
DQ = 0; //单片机将DQ拉低
Delay_DS18B20(80); //精确延时,大于480us
DQ = 1; //拉高总线
Delay_DS18B20(14);
x = DQ; //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
Delay_DS18B20(20);
}
/*****读一个字节*****/
unsigned char ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; // 给脉冲信号
dat>>=1;
DQ = 1; // 给脉冲信号
if(DQ)
dat|=0x80;
Delay_DS18B20(4);
}
return(dat);
}
/*****写一个字节*****/
void WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
Delay_DS18B20(5);
DQ = 1;
dat>>=1;
}
}
/*****读取温度*****/
unsigned int ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
unsigned int t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0x44); //启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
a=ReadOneChar(); //读低8位
b=ReadOneChar(); //读高8位
t=b; //高8位转移到t
t<<=8; //t数据左移8位
t=t|a; //将t和a按位或,得到一个16位的数
tt=t*0.0625; //将t乘以0.0625得到实际温度值(温度传感器设置12位精度,最小分辨率是0.0625)
t= tt*10+0.5; //放大10倍(将小数点后一位显示出来)输出并四舍五入
return(t); //返回温度值
}
//=====================================================================================
//=====================================================================================
//=====================================================================================
/*****延时子程序*****/
void Delay(uint num)
{
while( --num );
}
/*****初始化定时器0*****/
void InitTimer(void)
{
TMOD=0x1;
TH0=0x3c;
TL0=0xb0; //50ms(晶振12M)
}
/*****读取温度*****/
void check_wendu(void)
{
uint a,b,c;
c=ReadTemperature(); //获取温度值
a=c/100; //计算得到十位数字
b=c/10-a*10; //计算得到个位数字
m=c/10; //计算得到整数位
n=c-a*100-b*10; //计算得到小数位
if(m<0){m=0;n=0;} //设置温度显示上限
if(m>99){m=99;n=9;} //设置温度显示上限
}
/*****显示开机初始化等待画面*****/
void Disp_init(void)
{
P0 = ~0x80; //显示----
P2 = 0x7F;
Delay(200);
P2 = 0xDF;
Delay(200);
P2 = 0xF7;
Delay(200);
P2 = 0xFD;
Delay(200);
P2 = 0xFF; //关闭显示
}
/*****显示温度子程序*****/
void Disp_Temperature(void) //显示温度
{
P0 = ~0x98; //显示C
P2 = 0x7F;
Delay(100);
P2=0xff;
P0=~LEDData[n]; //显示个位
P2 = 0xDF;
Delay(100);
P2=0xff;
P0 =~LEDData[m%10]; //显示十位
DIAN = 0; //显示小数点
P2 = 0xF7;
Delay(100);
P2=0xff;
P0 =~LEDData[m/10]; //显示百位
P2 = 0xFD;
Delay(100);
P2 = 0xff; //关闭显示
}
/*****显示报警温度子程序*****/
void Disp_alarm(uchar baojing)
{
P0 =~0x98; //显示C
P2 = 0x7F;
Delay(100);
P2=0xff;
P0 =~LEDData[baojing%10]; //显示十位
P2 = 0xDF;
Delay(100);
P2=0xff;
P0 =~LEDData[baojing/10]; //显示百位
P2 = 0xF7;
Delay(100);
P2=0xff;
if(set_st==1)P0 =~0xCE;
else if(set_st==2)P0 =~0x1A; //上限H、下限L标示
P2 = 0xFD;
Delay(100);
P2 = 0xff; //关闭显示
}
/*****报警子程序*****/
void Alarm()
{
if(x>=10){beep_st=~beep_st;x=0;}
if((m>=shangxian&&beep_st==1)||(m<xiaxian&&beep_st==1))
{
BEEP=0;
ALAM=0;
}
else
{
BEEP=1;
ALAM=1;
}
}
/*****主函数*****/
void main(void)
{
uint z;
InitTimer(); //初始化定时器
EA=1; //全局中断开关
TR0=1;
ET0=1; //开启定时器0
IT0=1;
IT1=1;
check_wendu();
check_wendu();
for(z=0;z<300;z++)
{
Disp_init();
}
while(1)
{
if(SET==0)
{
Delay(2000);
do{}while(SET==0);
set_st++;x=0;shanshuo_st=1;
if(set_st>2)set_st=0;
}
if(set_st==0)
{
EX0=0; //关闭外部中断0
EX1=0; //关闭外部中断1
check_wendu();
Disp_Temperature();
Alarm(); //报警检测
}
else if(set_st==1)
{
BEEP=1; //关闭蜂鸣器
ALAM=1;
EX0=1; //开启外部中断0
EX1=1; //开启外部中断1
if(x>=10){shanshuo_st=~shanshuo_st;x=0;}
if(shanshuo_st) {Disp_alarm(shangxian);}
}
else if(set_st==2)
{
BEEP=1; //关闭蜂鸣器
ALAM=1;
EX0=1; //开启外部中断0
EX1=1; //开启外部中断1
if(x>=10){shanshuo_st=~shanshuo_st;x=0;}
if(shanshuo_st) {Disp_alarm(xiaxian);}
}
}
}
/*****定时器0中断服务程序*****/
void timer0(void) interrupt 1
{
TH0=0x3c;
TL0=0xb0;
x++;
}
/*****外部中断0服务程序*****/
void int0(void) interrupt 0
{
EX0=0; //关外部中断0
if(DEC==0&&set_st==1)
{
do{
Disp_alarm(shangxian);
}
while(DEC==0);
shangxian--;
if(shangxian<xiaxian)shangxian=xiaxian;
}
else if(DEC==0&&set_st==2)
{
do{
Disp_alarm(xiaxian);
}
while(DEC==0);
xiaxian--;
if(xiaxian<0)xiaxian=0;
}
}
/*****外部中断1服务程序*****/
void int1(void) interrupt 2
{
EX1=0; //关外部中断1
if(ADD==0&&set_st==1)
{
do{
Disp_alarm(shangxian);
}
while(ADD==0);
shangxian++;
if(shangxian>99)shangxian=99;
}
else if(ADD==0&&set_st==2)
{
do{
Disp_alarm(xiaxian);
}
while(ADD==0);
xiaxian++;
if(xiaxian>shangxian)xiaxian=shangxian;
}
}
项目的仿真和PCB工程已经放在下面公众号里面,可以关注公众号:Kevin的学习站,输入关键字:“51单片机温度报警器”,就可以免费获取啦!创作不易,但您的点赞、关注、收藏就是对我最大的鼓励!