2024年2月21日发(作者:)

单片机实时温度监控报警系统

摘要:本着熟悉单片机编程,系统设计的目的,增强动手合作能力,选择了做单片机实时温度监控报警系统这个实验项目。本开放性实验主要由AT89S52芯片、1602液晶显示器、DS18B20数字式温度传感器、HK4100继电器、蜂鸣器等组成。通过编程,利用单片机芯片自身的定时器和中断做一个实时时钟,可以记下发生事故时间,通过温度传感器实时采集环境温度显示在液晶屏上,并经过单片机处理,设置两个上限温度报警值,经过继电器控制外围线路。本系统可用于智能家居温控报警,车间温控等,具有一定推广价值。

关键字:温度报警 温度上下限 AT89S52单片机 液晶LCD1602

温度传感器DS18B20

1 课程设计任务书

一、设计任务:

制作一个基于单片机的温度监控报警系统

二、设计要求:

基本要求:

(1)温度测量范围:-20~90摄氏度,误差≤0.1摄氏度;

(2)可通过键盘设定温度值并在数码管上显示设定值,数码管显示精确度≤0.1摄氏度;

(3)数码管实时显示测量温度值并可以用语音播报测量温度值,其中数码管显示精确度≤0.1摄氏度;

(4)设定温度值与实际温度值保持一致,误差≤1摄氏度;

(5)当温度超出测量范围时,能实现报警;

发挥部分:

(6)能实现GSM短信发送或通过射频模块无线发送(发射距离﹥100米);

(7)可以有其它功能改进和实现特色创新

系统框架:

二 整体设计方案

2.1整体框架及各模块功能

本系统共分为七个模块。

1、单片机模块,这部分主要实现数据的处理,输出执行,报警设置功能(主要模块)

2、液晶显示模块可以分别显示实时温度值,温度上下限。(主要模块)

3、温度传感模块的主要功能是通过DS18B20的强大功能实现对温度的采集。(主要模块)

4、继电器模块可以控制外围其他线路,如家居电线总开关。

5、蜂鸣器模块可以发出报警声。

6、LED灯模块可以显示报警信号

7、按键可以设置时间和上限的两个温度值

温度读取

液晶显示

AT89S52继电器控制

控制器

键盘扫描

并设置

蜂鸣器

LED灯

图1 整体框图

图2 温度报警器总电路图

1

开始

液晶、定时器、变量初始化

键盘扫描、按键处理

时钟显示、温度转化并显示

Yes

温度小于较低温度值

No

Yes

温度大于较低且小于温度值

No

Yes

温度大于较高温度值

No

红绿灯亮,有短报警声,继电器控制开关断开,停止时钟

绿灯亮,有长报警声

正常工作

结束

单片机温度实时监控报警系统流程图

2

三 硬件电路设计

(由于继电器、蜂鸣器、LED灯、按键模块结果和线路较为简单,下面主要以单片机控制、液晶显示、温度采集模块为主来分析)

3.1各模块设计

3.1.1传感器的选择

采用DALLAS最新单线数字温度传感器DS18B20。新的“一线器件”体积更小、适用电压更宽、更经济。一线总线独特而且经济的特点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。DS18B20“一线总线”数字化温度传感器也支持“一线总线”接口,测量温度范围为 -55°C~+125°C,在-10~+85°C范围内,精度为±0.5°C。现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。适合于恶劣环境的现场温度测量,如:环境控制、设备或过程控制、测温类消费电子产品等。DS18B20的特性:DS18B20可以程序设定9~12位的分辨率,精度为±0.5°C。可选更小的封装方式,更宽的电压适用范围。分辨率设定,及用户设定的报警温度存储在EEPROM中,掉电后依然保存。DS18B20的性能是新一代产品中最好的!性能价格比也非常出色!继“一线总线”的早期产品后,DS1820开辟了温度传感器技术的新概念。DS18B20使电压、特性及封装有更多的选择,让我们可以构建适合自己的经济的测温系统。

3.1.2单片机的选择

AT89S52 是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。使用Atmel 公司高密度非易失性存储器技术制造,与工业80C51

产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。在单芯片上,拥有灵巧的8位CPU和在系统可编程Flash,使得AT89S52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。

3.1.3液晶的选择

采用LCD1602液晶显示模块,有体积小、功耗低、显示内容丰富、超薄轻巧等优点,在袖珍式仪表和低功耗应用系统中得到广泛的应用。目前字符型液晶显示模块已经是单片机应用设计中最常用的信息显示器件。它可以显示两行,每行16个字符,采用单+5V电源供电,外围电路配置简单,价格便宜,具有很高的性价比。

3

3.2各模块分析

3.2.1单片机89S52管脚图

注:引脚说明:

①电源引脚

Vcc(40脚):典型值+5V。

Vss(20脚):接低电平。

②外部晶振

X1、X2分别与晶体两端相连接。当采用外部时钟信号时,X2接振荡信号,X1接地。

③输入输出口引脚:

P0口:I/O双向口。作输入口时,应先软件置“ 1”。

P1口:I/O双向口。作输入口时,应先软件置“ 1”。

P2口:I/O双向口。作输入口时,应先软件置“ 1”。

P3口:I/O双向口。作输入口时,应先软件置“ 1”。

④控制引脚:

RST/Vpd、ALE/-PROG、-PSEN、-EA/Vpp组成了MSC-51的控制总线。

RST/Vpd(9脚):复位信号输入端(高电平有效)。

第二功能:加+5V备用电源,可以实现掉电保护RAM信息不丢失。

ALE/-PROG(30脚):地址锁存信号输出端。

第二功能:编程脉冲输入。

-PSEN(29脚):外部程序存储器读选通信号。

-EA/Vpp(31脚):外部程序存储器使能端。

第二功能:编程电压输入端(+21V)。

3.2.2 DS18B20引脚及管脚功能介绍

DQ:数字信号输入/输出端。

4

GND:电源地端。

VDD:外接供电电源输入端(在寄生电源接线时此脚应接地)。

3.2.3 LCD1602液晶显示介绍

管脚功能

1602采用标准的16脚接口

第1脚:VSS为电源地

第2脚:VDD接5V电源正极

第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高。第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。

第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。

第6脚:E(或EN)端为使能(enable)端。

第7~14脚:D0~D7为8位双向数据端。

第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。四 控制软件主要模块设计及电路图

4.1单片机模块电路图及分析

图3 单片机接线图

5

P0接液晶数据口,P2.2和P2.3接2个发光二极管,P3接8个按钮,P2.4接蜂鸣器,P2.5接继电器,P2.6接液晶的RS,P2.7接液晶的EN,P1.2接温度传感器,其他按单片机最小系统连接。

4.2液晶显示模块电路图及分析

图3 液晶接线图

液晶显示模块的子程序:

void write_com(uchar com)

{//写液晶命令函数

rs=0;

lcden=0;

P0=com;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void write_date(uchar date)

{//写液晶数据函数

rs=1;

lcden=0;

P0=date;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void write_sfm(uchar add,char date)

6

//1602液晶刷新时分秒函数1

为时,4为分,7为秒

{

char shiwei,gewei;

shiwei=date/10;

gewei=date%10;

write_com(0x80+add);

write_date(0x30+shiwei);

write_date(0x30+gewei);

}

void write_nyr(uchar add,char date)

{char shiwei,gewei;

shiwei=date/10;

gewei=date%10;

write_com(0xc0+add);

write_date(0x30+shiwei);

write_date(0x30+gewei);

}

4.3温度传感器模块电路图及分析

图4温度传感器接线图

温度传感器读取温度以及显示温度的子程序:

7

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) //向18B20写一个字节数据

{

uint i;

uchar j;

bit testb;

for(j=1;j<=8;j++)

{

testb=dat&0x01;

dat=dat>>1;

if(testb) //写 1

{

ds=0;

8

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();

delay(1);

tempwritebyte(0xcc); // 写跳过读ROM指令

tempwritebyte(0x44); // 写温度转换指令

}

uint get_temp() //读取寄存器中存储的温度数据

{

uchar a,b;

dsreset();

delay(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+0.5; //加0.5是四舍五入

return temp; //temp是浮点型

}

5总程序

9

#define uchar unsigned char

#define uint unsigned int

sbit rs=P2^6;

sbit lcden=P2^7;

sbit jidianqi=P2^5;

sbit s1=P3^0;//功能键

sbit s2=P3^1;//增加键

sbit s3=P3^3;//减小键

sbit beep=P2^3;//蜂鸣器

sbit led1=P2^1;

sbit led2=P2^2;

sbit ds=P1^2; //温度传感器

uint warnl=35; //下限温度

uint warnh=40; //上限温度

uint temp; //整形温度数据

float f_temp; //浮点型温度数据

uchar count,stop,s1num,s2num;//其它变量定义

char miao,shi,fen;

uchar code table[]=" : : T: ";//液晶固定显示内容

uchar code table1[]=" L: H: ";

#include

#include

void delay(uint z)//延时函数

{

uint x,y;

for(x=z;x>0;x--)

for(y=124;y>0;y--)

;

}

void di() //蜂鸣器报警声音

{

beep=0;

delay(100);

beep=1;

}

/*================液晶操作============*/

void write_com(uchar com)

{//写液晶命令函数

rs=0;

lcden=0;

P0=com;

delay(3);

lcden=1;

delay(3);

10

lcden=0;

}

void write_date(uchar date)

{//写液晶数据函数

rs=1;

lcden=0;

P0=date;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void write_sfm(uchar add,char date) //1602液晶刷新时分秒函数1为时,4为分,7为秒

{

char shiwei,gewei;

shiwei=date/10;

gewei=date%10;

write_com(0x80+add);

write_date(0x30+shiwei);

write_date(0x30+gewei);

}

void write_nyr(uchar add,char date)

{//1602液晶刷新年月日函数3为年,6为分,9为秒

char shiwei,gewei;

shiwei=date/10;

gewei=date%10;

write_com(0xc0+add);

write_date(0x30+shiwei);

write_date(0x30+gewei);

}

/*==================================================*/

/*==============ds18B20程序=========================*/

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位函数

11

{

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) //向18B20写一个字节数据

{

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++;

}

12

}

}

void tempchange(void) //DS18B20 开始获取温度并转换

{

dsreset();

delay(1);

tempwritebyte(0xcc); // 写跳过读ROM指令

tempwritebyte(0x44); // 写温度转换指令

}

uint get_temp() //读取寄存器中存储的温度数据

{

uchar a,b;

dsreset();

delay(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+0.5; //加0.5是四舍五入

return temp; //temp是浮点型

}

/*=========================================================================*/

/*========================温度处理========================*/

void deal(uint t)

{

if (t>warnh)

{

jidianqi=0;

TR0=0;

led1=0;

di();

delay(200);

di();

delay(100);

}

if (t>warnl&&t<=warnh)

{

led2=0;

di();

13

delay(400);

di();

delay(100);

}

}

/*=========================液晶处理=============*/

void init()

{//初始化函数

uchar num;

s1num=0;

count=0;

fen=0;

miao=0;

shi=0;

lcden=0;

jidianqi=1;

led1=1;

led2=1;

write_com(0x38);//1602液晶初始化

write_com(0x0c);

write_com(0x06);

write_com(0x01);

write_com(0x80);

for(num=0;num<15;num++)//写入液晶固定部分显示

{

write_date(table[num]);

delay(1);

}

write_sfm(7,miao);//分别送去液晶显示

write_sfm(4,fen);

write_sfm(1,shi);

write_com(0x8e);

write_date(0xdf);

write_date(0x43);

write_com(0x80+0x40);

for(num=0;num<15;num++)

{

write_date(table1[num]);

delay(1);

}

write_com(0xc5);

write_date(0xdf);

write_date(0x43);

write_com(0xcd);

14

write_date(0xdf);

write_date(0x43);

TMOD=0x01;//设置定时器0工作模式1

TH0=(65536-50000)/256;//定时器装初值

TL0=(65536-50000)%256;

EA=1; //开总中断

ET0=1; //开定时器0中断

TR0=1; //启动定时器0

}

/*==================按键处理=============*/

void keyscan()//按键扫描函数

{

if(s1==0)

{

delay(5);

if(s1==0)//确认功能键被按下

{ s1num++;//功能键按下次数记录

while(!s1);//释放确认

di();//每当有按键释放蜂鸣器发出滴声

if(s1num==1)//第一次被按下时

{

TR0=0; //关闭定时器

write_com(0x80+7);//光标定位到秒位置

write_com(0x0f); //光标开始闪烁

}

if(s1num==2)//第二次按下光标闪烁定位到分钟位置

{

write_com(0x80+4);

}

if(s1num==3)//第三次按下光标闪烁定位到小时位置

{

write_com(0x80+1);

}

if(s1num==4)

{

write_com(0xc0+3);

}

if(s1num==5)

{

write_com(0xc0+11);

}

if(s1num==6)//第四次按下

15

{

s1num=0;//记录按键数清零

write_com(0x0c);//取消光标闪烁

TR0=1; //启动定时器使时钟开始走

}

}

}

if(s1num!=0)//只有功能键被按下后,增加和减小键才有效

{

if(s2==0)

{

delay(5);

if(s2==0)//增加键确认被按下

{

while(!s2);//按键释放

di();//每当有按键释放蜂鸣器发出滴声

if(s1num==1)//若功能键第一次按下

{

miao++; //则调整秒加1

if(miao==60)//若满60后将清零

miao=0;

write_sfm(7,miao);//每调节一次送液晶显示一下

write_com(0x80+7);//显示位置重新回到调节处

}

if(s1num==2)//若功能键第二次按下

{

fen++;//则调整分钟加1

if(fen==60)//若满60后将清零

fen=0;

write_sfm(4,fen);//每调节一次送液晶显示一下

write_com(0x80+4);//显示位置重新回到调节处

}

if(s1num==3)//若功能键第三次按下

{

shi++;//则调整小时加1

if(shi==24)//若满24后将清零

shi=0;

write_sfm(1,shi);;//每调节一次送液晶显示一下

write_com(0x80+1);//显示位置重新回到调节处

}

if(s1num==4)

{

warnl++;

write_nyr(3,warnl);

16

write_com(0xc0+3);

}

if(s1num==5)

{

warnh++;

write_nyr(11,warnh);

write_com(0xc0+11);

}

}

}

if(s3==0)

{

delay(5);

if(s3==0)//确认减小键被按下

{

while(!s3);//按键释放

di();//每当有按键释放蜂鸣器发出滴声

if(s1num==1)//若功能键第一次按下

{

miao--;//则调整秒减1

if(miao==-1)//若减到负数则将其重新设置为59

miao=59;

write_sfm(7,miao);//每调节一次送液晶显示一下

write_com(0x80+7);//显示位置重新回到调节处

}

if(s1num==2)//若功能键第二次按下

{

fen--;//则调整分钟减1

if(fen==-1)//若减到负数则将其重新设置为59

fen=59;

write_sfm(4,fen);//每调节一次送液晶显示一下

write_com(0x80+4);//显示位置重新回到调节处

}

if(s1num==3)//若功能键第二次按下

{

shi--;//则调整小时减1

if(shi==-1)//若减到负数则将其重新设置为23

shi=23;

write_sfm(1,shi);//每调节一次送液晶显示一下

write_com(0x80+1);//显示位置重新回到调节处

}

if(s1num==4)

{

warnl--;

17

write_nyr(3,warnl);

write_com(0xc0+3);

}

if(s1num==5)

{

warnh--;

write_nyr(11,warnh);

write_com(0xc0+11);

}

}

}

}

}

/*=====================主函数=================*/

void main()

{

init();//调用初始化函数

while(1)

{

if (stop>=60)

deal(temp);

keyscan();//按键扫描

}

}

void timer0() interrupt 1//定时器0中断服务程序

{

TH0=(65536-50000)/256;//再次装定时器初值

TL0=(65536-50000)%256;

stop++;

if(stop>=100)

stop--;

count++; //中断次数累加

if(count==20) //20次50毫秒为1秒

{

count=0;

miao++;

if(miao==60)//秒加到60则进位分钟

{

miao=0;//同时秒数清零

fen++;

if(fen==60)//分钟加到60则进位小时

{

fen=0;//同时分钟数清零

shi++;

18

if(shi==24)//小时加到24则小时清零

{

shi=0;

}

write_sfm(1,shi);//小时若变化则重新写入

}

write_sfm(4,fen);//分钟若变化则重新写入

}

write_sfm(7,miao);//秒若变化则重新写入

tempchange();

write_sfm(12,get_temp());

write_nyr(3,warnl);

write_nyr(11,warnh);

}

}

七 参考文献

1.单片机C语言程序设计实训100例

编著] 彭 伟 [19

2.流行单片机实用子程序及应用实例

[编著] 杨振江 杜铁军 李 群

3.C51基础与应用实例

[编著] 常喜茂 孔英会 付小宁

4.单片机原理与接口技术 [编著] 刘 军

5.单片机原理与C51编程

[编著] 宋彩利 孙友仓 吴宏岐

6.51单片机开发入门与经典实例 [编著] 王守中

7.51单片机C语言教程 [编著] 郭天祥

8.单片机程序设计及应用

[编著] 杨将新 李华军 刘东骏

9.51单片机应用实例详解

[编著] 杨 欣 王玉凤 刘湘黔 张延强

10. 百度文库

八 附录

实物图和PCB图

20