课 程 设 计
题 目 上下限可调的温度报警器设计
专 业 电子**********
学 号 ************
姓 名 周*****
指导教师 ********
2014年11月14日
摘 要:单片机技术已经普及到我们生活,工作,科研,各个领域,已经成为一种比较成熟的技术, 本文将介绍一种基于单片机控制的数字温度器,本温度计属于多功能温度计,可以设置上下报警温度,当温度不在设置范围内时,可以报警。
随着现代工农业技术的发展及人们对生活环境要求的提高,人们也迫切需要检测与控制温度。本文通过采用蜂鸣器作为电声元件的温度报警器的设计,阐明了该装置进行设计与制作的具体过程及方法。这种温度报警器结构简单,可操作性强,应用广泛。工作时,温度测量范围为18—23ºC。当前环境温度若超过设定的高温临界温度,由单片机发出报警信号,从而防止带来的不必要的损失。
造成高温火灾有:电气线路短路、过载、接触电阻过大等引发高温或火灾;静电产生高温或或火灾;雷电等强电侵入导致高温或火灾;最主要是机房内电脑、空调等用电设备长时间工作,导致设备老化,空调发生故障,而不能降温;因此机房内所属的电子产品发热快,在短时间内机房温度升高超出设备正常温度,导致系统瘫痪或产生火灾,这时温度报警系统就会发挥应有的功能。
关键词STC89C51单片机,数字控制,温度计,DS18B20
1 设计方案选择
1.1 系统基本方案选择 1.1.1 单片机芯片的选择方案
方案一:
采用STC89C51芯片作为硬件核心。STC89C51内部具有8KB ROM 存储空间,512字节数据存储空间,带有2K 字节的EEPROM 存储空间,与MCS-51系列单片机完全兼容,STC89C51可以通过串口下载。
方案二:
采用AT89S51。AT89S51片内具有8K 字节程序存储空间,256字节的数据存储空间没有EEPROM 存储空间,也与MCS-51系列单片机完全兼容,具有在线编程可擦除技术。
两种单片机都完全能够满足设计需要,STC89C51相对ATS89C52价格便宜,且抗干扰能力强。考虑到成本因素,因此选用STC89C51。 1.1.2 温度传感器设计方案
方案一:
由于本设计是测温电路,可以使用热敏电阻之类的器件利用其感温效应,在将随被测温度变化 的电压或电流采集过来,进行 A/D 转换后,就可以用单片机进行数据的处理,在显示电路上,就可以将被测温度显示出来,这种设计需要用到 A/D 转换电路,感温电路比较麻烦。
方案二:
进而考虑到用温度传感器,在单片机电路设计中,大多都是使用传感器,所以这是非常容易想到的,所以可以采用一只温度传感器 DS18B20,此传感器,可以很容易直接读取被测温度值,进行转换,就可以满足设计要求。
从以上两种方案,两种都完全能够满足设计需要,很容易看出,采用方案二,电路比较简单,软件设计也比较简单,故采用了方案二。
综上各方案所述, 对此次作品的方案选定: 采用STC89C51单片机作为主控制系统; 采用DS18B20为传感器; 1.1.3显示电路设计
方案一:使用数码管显示,数码管是由多个发光二极管封在在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。有共阴,共阳两种。
方案二:使用液晶显示屏lcd1602,1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。
比较两种方案将选用方案二,lcd1602操作简单,可以直接对1602的引脚直接操作。
2 主要元件介绍
2.1.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
STC89C52
图1:STC89C51封装图
2.1.2 单片机最小系统:
当在STC89C51单片机的RST 引脚引入高电平并保持2个机器周期时,单片机内部就执行复位操作,按键手动复位有电平方式和脉冲方式两种。其中电平复位是通过RST
端经过电阻与电源VCC 接通而实现的。最小系统如图2
图2 单片机最小系统电路
电路以STC89C51单片机最小系统为控制核心,测温电路由DS18B20提供,输入部分采用三个独立式按键s0、s1、s2。具体电路连接,详见附录1。 2.2 DS18B20传感器介绍 2.2.1 DS18B20概述
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。 2.3 LCD1602介绍
引脚功能介绍
第1脚:VSS 为地电源。 第2脚:VDD 接5V 正电源。
第3脚:VL 为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K 的电位器调整对比度。
第4脚:RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS 和R/W共同为低电平时可以写入指令或者显示地址,当RS 为低电平R/W为高电平时可以读忙信号,当RS 为高电平R/W为低电平时可以写入数据。
第6脚:E 端为使能端,当E 端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。 指令介绍
1602液晶模块的读写操作,屏幕和光标的操作都是通过指令编程来实现的。(说明1为高电平,0为低电平)
指令1:清显示,指令码01H ,光标复位到地址00H 位置 指令2:光标复位,光标返回到地址00H
指令3:光标和显示位置设置I/D,光标移动方向,高电平右移,低电平左移,S :屏幕上所有文字是否左移或右移,高电平表示有效,低电平表示无效。
指令4:显示开关控制。D :控制整体的显示开与关,高电平表示开显示,低电平表示关显示。C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C :高电平时显示移动的文字,低电平时移动光标 指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时为双行显示,F :低电平时显示5X7的点阵字符,高电平时显示5X10的显示字符。
指令7:字符发生器RAM 地址设置。 指令8:DDRAM 地址设置。
指令9:读忙信号和光标地址 BF:忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平表示不忙。
使用lcd 先根据液晶的使用手册写出液晶屏的驱动程序,后使用把信息显示到液晶上时直接调用液晶子程序即可。
3. 程序流程图
图6:程序流程图
4. 设计总结
本次设计功能基本实现,当温度低于下限温度或者高于上限温度时蜂鸣器发出报警。设计电路有温度上下限可调功能,按键按下由于不能再1602显示光标只能使用led 的亮灭和蜂鸣器来确定按键是否按下,并且最终能实现了该功能。获取的温度值通过1602显示出来。软件调适通过使用protues 进行仿真,开始只是让1602显示出数据,慢慢的加入按键,led 指示灯和蜂鸣器。
过程中遇到了很多问题,硬件方面:原理图设计好51单片机最小系统再根据仿真软件电路接入温度采集电路,报警电路,显示电路,指示电路,按键和电源接口。画好原理图导出PCB 布线,由于对PCB 布线规则不是很了解,粗略步好线打印印板、腐蚀、
打孔、焊接,由于经过电子相关的实习,这些步骤还是完成得比较好。焊接好后第一步就是坚持电路是否短路或者是否有虚焊,多次对照PCB 后没有问题就将下载好程序的单片机插入电路开始调试。设计电路时预留了两个IO 口即增加了两个扩展口,所以可以通过之前自己设计的STC 串口下载器对单片机程序的下载调试。实际软件件调试也是和仿真一样,先让1602能够显示东西,再把整个程序下载到单片机中,由于仿真时电路要设计的功能基本都能实现了,所以程序下载成功后电路基本实现了功能。只是蜂鸣器在温度没有超出限制范围内还是有小小的声音产生,找蜂鸣器相关资料发现是因为蜂鸣器在不使用时要给它一个低电平或高电平(看电路,这里电路是给低电平),因为不限制蜂鸣器的初始值时电路会出现漏电现象,程序改动后漏电现象消除了。
通过本次设计,我学到了很多我们在课堂上学不到的实践能力,动手能力也得到了很大的提升,在书本所学到的知识得到了很大的实践,让我对书本上的知识有了更加深刻的理解。同时也感谢同学的帮助,在我对电路相关知识不理解时给了我指点,让我能清楚得理解,也通过这次的设计让我电子电路设计有了很大兴趣。
参考文献
[1] 郭天祥.51单片机C 语言教程. 北京:电子工业出版,2009. [2] 谭浩强.C 语言程序设计[M].北京:清华大学出版社,1991. [3] 阎石. 数字电子技术基础[M].北京:高等教育出版社,2006. [4] 童诗白. 模拟电子技术基础[M].北京:高等教育出版社,2006. [5] 杨欣.电子设计从零开始[M].北京:清华大学出版社,2005.
附录1 系统原理图
PCB 图
附录2 C语言程序
#include #include"1602.h" #include"DS18B20.h" #define uchar unsigned char #define uint unsigned int
sbit BEEP=P1^4;
sbit led=P1^0; sbit led0=P1^1; sbit led1=P1^2; sbit s0=P3^0; sbit s1=P3^1; sbit s2=P3^2;
uchar code tab_0[]="Temp: "; uchar code tab_1[]="TH:23 TL:18 "; uchar TH,TL; // 定义高低温度变量
uchar num; //全局变量
/********ms延时(非精确)**********/ void delay(uint z)
{ uint i,j; for(i=z;i>0;i--)
for(j=120;j>0;j--);
}
/*******TH、TL 的温度符号**********/ void fuhao() { write_com(0x80+5); write_dat(0xdf); write_dat(0x43); write_com(0x80+14); write_dat(0xdf); write_dat(0x43);
}
/*************初始化**************/ void init() {
/***********上电显示初始化**********/ uchar i; TH=23;TL=18; write_com(0x80); for(i=0;i
delay(5);
}
write_com(0x80+0x40); for(i=0;i
}
fuhao();
/********定时器初始化*************/ TMOD=0x01; //开定时器T0,方式1 TH0=(65536-50000)/256; //装入初值 TL0=(65536-50000)%256; // EA=1; //开全局中断 ET0=1;
TR0=1; //打开定时器
}
/**********报警函数**************/ void bi(uint t) { int i,j; for(i=0;i
BEEP=~BEEP; //按位取反BEEP }
}
/*******TH、TL 取十位个位送人显示***********/
void writeT_HL(uchar add,uchar dat) { uchar shi,ge; shi=dat/10; //十位 ge=dat%10;
//个位
write_com(0x80+add); write_dat(shi+0x30);
write_dat(ge+0x30);
}
/*******按键函数********/ void keyscan() {
/**********功能选择**********/ if(s0==0) { num++; delay(2); if(s0==0) { led=0;
while(!s0);{bi(300);led=1;}
//按一下灯亮一下声音响一声
if(num==1)
{TR0=0;write_com(0x80+12);delay(10);} //write_com(0x0f);
if(num==2)
{write_com(0x80+4);}
if(num==3) {num=0;TR0=1;}
} }
/*********功能加*********/ if(num!=0) { if(s1==0) { delay(2);
if(s1==0)
{
led0=0;
while(!s1);{bi(300);led0=1;} //按一下
灯亮一下声音响一声
if(num==1)
{TH++;if(TH==100)
TH=0;writeT_HL(3,TH);write_com(0x80+4);}
if(num==2)
{TL++;if(TL==100)
TL=0;writeT_HL(12,TL);write_com(0x80+10);}
}
} }
/**********功能减************/ if(num!=0) { if(s2==0) { delay(2); if(s2==0) { led1=0;
while(!s2);
{bi(300);led1=1;} //按一下灯亮一下声音响一声
if(num==1)
{TH--;if(TH==-1)
TH=99;writeT_HL(3,TH);write_com(0x80+4);}
if(num==2)
{TL--;if(TL==-1)
TL=99;writeT_HL(12,TL);write_com(0x80+10);}
}
} }
}
/*****温度报警函数*******/ void beep() {
uchar tem;
tem=temp/10; //返回的温度值temp 放
大了十倍,得除十还原 if(TH=tem) { bi(500);}
}
/***************主函数***************/ void main(void) { Init_1602(); init(); while(1) { BEEP=0;
keyscan();
ds1820disp(); beep();
}
}
/***********定时器中断函数************/ void time() interrupt 1 { TH0=(65536-50000)/256; //重装初值 TL0=(65536-50000)%256;
}
DS1802驱动程序 #ifndef __DS18B20_H__ #define __DS18B20_H__
#define uchar unsigned char #define uint unsigned int sbit DQ = P1^3; uchar tab[5]; uint temp;//温度值 bit tflag;
/**************** 延时1微秒**********/
void delay_18B20(uint i) { while(i--); }
/******************* ds1820复位************/ void ds1820rst() { uchar x=0;
DQ=1; //DQ复位
delay_18B20(8); //延时 DQ=0; //DQ拉低
delay_18B20(80); //精确延时大于
480us DQ=1; //拉高 delay_18B20(14);
x=DQ; //稍做延时后 如果
x=0则初始化成功 x=1则初始化失败 while(!DQ); delay_18B20(20);
}
/********************
读一个字节********************/ uchar ds1820rd() { uchar i=0; uchar dat=0; for (i=8;i>0;i--) { DQ=0; //给脉冲信号 dat>>=1;
DQ=1; //给脉冲信号 if(DQ) dat|=0x80; delay_18B20(4); }
return(dat);
}
/***************
写一个字节***************/
void ds1820wr(uchar dat) { uchar i=0; for (i=8;i>0;i--) { DQ=0; DQ=dat&0x01; delay_18B20(5); DQ=1; dat>>=1;
}
}
/****************读取温度 值并转换***************/ read_temp() {
uchar a,b; ds1820rst();
ds1820wr(0xcc);//跳过读序列号 ds1820wr(0x44);//启动温度转换
delay_18B20(100);
ds1820rst();
ds1820wr(0xcc);//跳过读序列号 ds1820wr(0xbe);//读取温度
delay_18B20(100);
a=ds1820rd(); b=ds1820rd(); temp=b; temp
if(temp
tflag=0;
else { temp=~temp+1;
tflag=1;
}
temp=temp*(0.625);//温度值扩大10倍,精确到1位小数 return(temp);
}
/*****************
温度值显示****************/ void ds1820disp() { uchar flagdat; read_temp();
tab[0]=temp%1000/100+0x30; //
十位数
tab[1]=temp%100/10+0x30; //
个位数
tab[2]=temp%10+0x30; //
小数位
if(tflag==0)
flagdat=0x20;//正温度不显示符号
else flagdat=0x2d;//负温度显示负号:-
if(tab[0]==0x30) { tab[0]=0x20; }//如
果十位为0,不显示
write_com(0x80+0x40+6);
write_dat(flagdat); //显示正负 write_dat(tab[0]); //显示十位 write_dat(tab[1]); //显示个位 write_dat(0x2e); //显示小数
}
int i,j; for(i=z;i>0;i--)
for(j=120;j>0;j--);
点 /********************
1cd1602初始化******************/ write_dat(tab[2]); //显示小数位 write_dat(0xdf); write_dat(0x43);
} #endif
LCD1602驱动程序 #ifndef __1602_H__ #define __1602_H__
#define uint unsigned int #define uchar unsigned char #define LCD P0 sbit RS=P2^4; sbit RW=P2^5; sbit EN=P2^6; void delayms(uint z); void Init_1602(void); void check_busy(void); void write_com(uchar com); void write_dat(uchar dat);
/********************延时****************/ void delayms(uint z) {
z
毫秒
void Init_1602(void) { delayms(15); write_com(0x38); delayms(5); write_com(0x0c); delayms(5); write_com(0x06); delayms(5); write_com(0x01); delayms(5); write_com(0x80); delayms(5);
}
/************************** 将数据二进制高地位对换 (为了连线方便但片机P0口 与lcd1602数据口反接) ****************************/ uchar HL_exchange(uchar dat)
{
uchar i,temp; temp = 0x00; for(i=0;i
{
temp >>= 1; if((dat
temp |= 0x80; } else {
temp &= 0x7F; } }
return temp; }
/**********读忙*****************/ void check_busy(void) { uchar x;
x=HL_exchange(0x80); while(x&HL_exchange(0x80)) { RS=0; RW=1; EN=1; x=LCD; EN=0; delayms(10);
}
}
/**************写指令**************/ void write_com(uchar com)
{ check_busy(); RS=0; RW=0; EN=1; LCD=0XFF;
LCD=HL_exchange(com); EN=0; delayms(10);
}
/**************写数据**************/ void write_dat(uchar dat) { check_busy(); RS=1;
RW=0; EN=1; LCD=0XFF;
LCD=HL_exchange(dat); EN=0; delayms(10); }
#endif
课 程 设 计
题 目 上下限可调的温度报警器设计
专 业 电子**********
学 号 ************
姓 名 周*****
指导教师 ********
2014年11月14日
摘 要:单片机技术已经普及到我们生活,工作,科研,各个领域,已经成为一种比较成熟的技术, 本文将介绍一种基于单片机控制的数字温度器,本温度计属于多功能温度计,可以设置上下报警温度,当温度不在设置范围内时,可以报警。
随着现代工农业技术的发展及人们对生活环境要求的提高,人们也迫切需要检测与控制温度。本文通过采用蜂鸣器作为电声元件的温度报警器的设计,阐明了该装置进行设计与制作的具体过程及方法。这种温度报警器结构简单,可操作性强,应用广泛。工作时,温度测量范围为18—23ºC。当前环境温度若超过设定的高温临界温度,由单片机发出报警信号,从而防止带来的不必要的损失。
造成高温火灾有:电气线路短路、过载、接触电阻过大等引发高温或火灾;静电产生高温或或火灾;雷电等强电侵入导致高温或火灾;最主要是机房内电脑、空调等用电设备长时间工作,导致设备老化,空调发生故障,而不能降温;因此机房内所属的电子产品发热快,在短时间内机房温度升高超出设备正常温度,导致系统瘫痪或产生火灾,这时温度报警系统就会发挥应有的功能。
关键词STC89C51单片机,数字控制,温度计,DS18B20
1 设计方案选择
1.1 系统基本方案选择 1.1.1 单片机芯片的选择方案
方案一:
采用STC89C51芯片作为硬件核心。STC89C51内部具有8KB ROM 存储空间,512字节数据存储空间,带有2K 字节的EEPROM 存储空间,与MCS-51系列单片机完全兼容,STC89C51可以通过串口下载。
方案二:
采用AT89S51。AT89S51片内具有8K 字节程序存储空间,256字节的数据存储空间没有EEPROM 存储空间,也与MCS-51系列单片机完全兼容,具有在线编程可擦除技术。
两种单片机都完全能够满足设计需要,STC89C51相对ATS89C52价格便宜,且抗干扰能力强。考虑到成本因素,因此选用STC89C51。 1.1.2 温度传感器设计方案
方案一:
由于本设计是测温电路,可以使用热敏电阻之类的器件利用其感温效应,在将随被测温度变化 的电压或电流采集过来,进行 A/D 转换后,就可以用单片机进行数据的处理,在显示电路上,就可以将被测温度显示出来,这种设计需要用到 A/D 转换电路,感温电路比较麻烦。
方案二:
进而考虑到用温度传感器,在单片机电路设计中,大多都是使用传感器,所以这是非常容易想到的,所以可以采用一只温度传感器 DS18B20,此传感器,可以很容易直接读取被测温度值,进行转换,就可以满足设计要求。
从以上两种方案,两种都完全能够满足设计需要,很容易看出,采用方案二,电路比较简单,软件设计也比较简单,故采用了方案二。
综上各方案所述, 对此次作品的方案选定: 采用STC89C51单片机作为主控制系统; 采用DS18B20为传感器; 1.1.3显示电路设计
方案一:使用数码管显示,数码管是由多个发光二极管封在在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。有共阴,共阳两种。
方案二:使用液晶显示屏lcd1602,1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。
比较两种方案将选用方案二,lcd1602操作简单,可以直接对1602的引脚直接操作。
2 主要元件介绍
2.1.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
STC89C52
图1:STC89C51封装图
2.1.2 单片机最小系统:
当在STC89C51单片机的RST 引脚引入高电平并保持2个机器周期时,单片机内部就执行复位操作,按键手动复位有电平方式和脉冲方式两种。其中电平复位是通过RST
端经过电阻与电源VCC 接通而实现的。最小系统如图2
图2 单片机最小系统电路
电路以STC89C51单片机最小系统为控制核心,测温电路由DS18B20提供,输入部分采用三个独立式按键s0、s1、s2。具体电路连接,详见附录1。 2.2 DS18B20传感器介绍 2.2.1 DS18B20概述
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。 2.3 LCD1602介绍
引脚功能介绍
第1脚:VSS 为地电源。 第2脚:VDD 接5V 正电源。
第3脚:VL 为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K 的电位器调整对比度。
第4脚:RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS 和R/W共同为低电平时可以写入指令或者显示地址,当RS 为低电平R/W为高电平时可以读忙信号,当RS 为高电平R/W为低电平时可以写入数据。
第6脚:E 端为使能端,当E 端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。 指令介绍
1602液晶模块的读写操作,屏幕和光标的操作都是通过指令编程来实现的。(说明1为高电平,0为低电平)
指令1:清显示,指令码01H ,光标复位到地址00H 位置 指令2:光标复位,光标返回到地址00H
指令3:光标和显示位置设置I/D,光标移动方向,高电平右移,低电平左移,S :屏幕上所有文字是否左移或右移,高电平表示有效,低电平表示无效。
指令4:显示开关控制。D :控制整体的显示开与关,高电平表示开显示,低电平表示关显示。C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C :高电平时显示移动的文字,低电平时移动光标 指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时为双行显示,F :低电平时显示5X7的点阵字符,高电平时显示5X10的显示字符。
指令7:字符发生器RAM 地址设置。 指令8:DDRAM 地址设置。
指令9:读忙信号和光标地址 BF:忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平表示不忙。
使用lcd 先根据液晶的使用手册写出液晶屏的驱动程序,后使用把信息显示到液晶上时直接调用液晶子程序即可。
3. 程序流程图
图6:程序流程图
4. 设计总结
本次设计功能基本实现,当温度低于下限温度或者高于上限温度时蜂鸣器发出报警。设计电路有温度上下限可调功能,按键按下由于不能再1602显示光标只能使用led 的亮灭和蜂鸣器来确定按键是否按下,并且最终能实现了该功能。获取的温度值通过1602显示出来。软件调适通过使用protues 进行仿真,开始只是让1602显示出数据,慢慢的加入按键,led 指示灯和蜂鸣器。
过程中遇到了很多问题,硬件方面:原理图设计好51单片机最小系统再根据仿真软件电路接入温度采集电路,报警电路,显示电路,指示电路,按键和电源接口。画好原理图导出PCB 布线,由于对PCB 布线规则不是很了解,粗略步好线打印印板、腐蚀、
打孔、焊接,由于经过电子相关的实习,这些步骤还是完成得比较好。焊接好后第一步就是坚持电路是否短路或者是否有虚焊,多次对照PCB 后没有问题就将下载好程序的单片机插入电路开始调试。设计电路时预留了两个IO 口即增加了两个扩展口,所以可以通过之前自己设计的STC 串口下载器对单片机程序的下载调试。实际软件件调试也是和仿真一样,先让1602能够显示东西,再把整个程序下载到单片机中,由于仿真时电路要设计的功能基本都能实现了,所以程序下载成功后电路基本实现了功能。只是蜂鸣器在温度没有超出限制范围内还是有小小的声音产生,找蜂鸣器相关资料发现是因为蜂鸣器在不使用时要给它一个低电平或高电平(看电路,这里电路是给低电平),因为不限制蜂鸣器的初始值时电路会出现漏电现象,程序改动后漏电现象消除了。
通过本次设计,我学到了很多我们在课堂上学不到的实践能力,动手能力也得到了很大的提升,在书本所学到的知识得到了很大的实践,让我对书本上的知识有了更加深刻的理解。同时也感谢同学的帮助,在我对电路相关知识不理解时给了我指点,让我能清楚得理解,也通过这次的设计让我电子电路设计有了很大兴趣。
参考文献
[1] 郭天祥.51单片机C 语言教程. 北京:电子工业出版,2009. [2] 谭浩强.C 语言程序设计[M].北京:清华大学出版社,1991. [3] 阎石. 数字电子技术基础[M].北京:高等教育出版社,2006. [4] 童诗白. 模拟电子技术基础[M].北京:高等教育出版社,2006. [5] 杨欣.电子设计从零开始[M].北京:清华大学出版社,2005.
附录1 系统原理图
PCB 图
附录2 C语言程序
#include #include"1602.h" #include"DS18B20.h" #define uchar unsigned char #define uint unsigned int
sbit BEEP=P1^4;
sbit led=P1^0; sbit led0=P1^1; sbit led1=P1^2; sbit s0=P3^0; sbit s1=P3^1; sbit s2=P3^2;
uchar code tab_0[]="Temp: "; uchar code tab_1[]="TH:23 TL:18 "; uchar TH,TL; // 定义高低温度变量
uchar num; //全局变量
/********ms延时(非精确)**********/ void delay(uint z)
{ uint i,j; for(i=z;i>0;i--)
for(j=120;j>0;j--);
}
/*******TH、TL 的温度符号**********/ void fuhao() { write_com(0x80+5); write_dat(0xdf); write_dat(0x43); write_com(0x80+14); write_dat(0xdf); write_dat(0x43);
}
/*************初始化**************/ void init() {
/***********上电显示初始化**********/ uchar i; TH=23;TL=18; write_com(0x80); for(i=0;i
delay(5);
}
write_com(0x80+0x40); for(i=0;i
}
fuhao();
/********定时器初始化*************/ TMOD=0x01; //开定时器T0,方式1 TH0=(65536-50000)/256; //装入初值 TL0=(65536-50000)%256; // EA=1; //开全局中断 ET0=1;
TR0=1; //打开定时器
}
/**********报警函数**************/ void bi(uint t) { int i,j; for(i=0;i
BEEP=~BEEP; //按位取反BEEP }
}
/*******TH、TL 取十位个位送人显示***********/
void writeT_HL(uchar add,uchar dat) { uchar shi,ge; shi=dat/10; //十位 ge=dat%10;
//个位
write_com(0x80+add); write_dat(shi+0x30);
write_dat(ge+0x30);
}
/*******按键函数********/ void keyscan() {
/**********功能选择**********/ if(s0==0) { num++; delay(2); if(s0==0) { led=0;
while(!s0);{bi(300);led=1;}
//按一下灯亮一下声音响一声
if(num==1)
{TR0=0;write_com(0x80+12);delay(10);} //write_com(0x0f);
if(num==2)
{write_com(0x80+4);}
if(num==3) {num=0;TR0=1;}
} }
/*********功能加*********/ if(num!=0) { if(s1==0) { delay(2);
if(s1==0)
{
led0=0;
while(!s1);{bi(300);led0=1;} //按一下
灯亮一下声音响一声
if(num==1)
{TH++;if(TH==100)
TH=0;writeT_HL(3,TH);write_com(0x80+4);}
if(num==2)
{TL++;if(TL==100)
TL=0;writeT_HL(12,TL);write_com(0x80+10);}
}
} }
/**********功能减************/ if(num!=0) { if(s2==0) { delay(2); if(s2==0) { led1=0;
while(!s2);
{bi(300);led1=1;} //按一下灯亮一下声音响一声
if(num==1)
{TH--;if(TH==-1)
TH=99;writeT_HL(3,TH);write_com(0x80+4);}
if(num==2)
{TL--;if(TL==-1)
TL=99;writeT_HL(12,TL);write_com(0x80+10);}
}
} }
}
/*****温度报警函数*******/ void beep() {
uchar tem;
tem=temp/10; //返回的温度值temp 放
大了十倍,得除十还原 if(TH=tem) { bi(500);}
}
/***************主函数***************/ void main(void) { Init_1602(); init(); while(1) { BEEP=0;
keyscan();
ds1820disp(); beep();
}
}
/***********定时器中断函数************/ void time() interrupt 1 { TH0=(65536-50000)/256; //重装初值 TL0=(65536-50000)%256;
}
DS1802驱动程序 #ifndef __DS18B20_H__ #define __DS18B20_H__
#define uchar unsigned char #define uint unsigned int sbit DQ = P1^3; uchar tab[5]; uint temp;//温度值 bit tflag;
/**************** 延时1微秒**********/
void delay_18B20(uint i) { while(i--); }
/******************* ds1820复位************/ void ds1820rst() { uchar x=0;
DQ=1; //DQ复位
delay_18B20(8); //延时 DQ=0; //DQ拉低
delay_18B20(80); //精确延时大于
480us DQ=1; //拉高 delay_18B20(14);
x=DQ; //稍做延时后 如果
x=0则初始化成功 x=1则初始化失败 while(!DQ); delay_18B20(20);
}
/********************
读一个字节********************/ uchar ds1820rd() { uchar i=0; uchar dat=0; for (i=8;i>0;i--) { DQ=0; //给脉冲信号 dat>>=1;
DQ=1; //给脉冲信号 if(DQ) dat|=0x80; delay_18B20(4); }
return(dat);
}
/***************
写一个字节***************/
void ds1820wr(uchar dat) { uchar i=0; for (i=8;i>0;i--) { DQ=0; DQ=dat&0x01; delay_18B20(5); DQ=1; dat>>=1;
}
}
/****************读取温度 值并转换***************/ read_temp() {
uchar a,b; ds1820rst();
ds1820wr(0xcc);//跳过读序列号 ds1820wr(0x44);//启动温度转换
delay_18B20(100);
ds1820rst();
ds1820wr(0xcc);//跳过读序列号 ds1820wr(0xbe);//读取温度
delay_18B20(100);
a=ds1820rd(); b=ds1820rd(); temp=b; temp
if(temp
tflag=0;
else { temp=~temp+1;
tflag=1;
}
temp=temp*(0.625);//温度值扩大10倍,精确到1位小数 return(temp);
}
/*****************
温度值显示****************/ void ds1820disp() { uchar flagdat; read_temp();
tab[0]=temp%1000/100+0x30; //
十位数
tab[1]=temp%100/10+0x30; //
个位数
tab[2]=temp%10+0x30; //
小数位
if(tflag==0)
flagdat=0x20;//正温度不显示符号
else flagdat=0x2d;//负温度显示负号:-
if(tab[0]==0x30) { tab[0]=0x20; }//如
果十位为0,不显示
write_com(0x80+0x40+6);
write_dat(flagdat); //显示正负 write_dat(tab[0]); //显示十位 write_dat(tab[1]); //显示个位 write_dat(0x2e); //显示小数
}
int i,j; for(i=z;i>0;i--)
for(j=120;j>0;j--);
点 /********************
1cd1602初始化******************/ write_dat(tab[2]); //显示小数位 write_dat(0xdf); write_dat(0x43);
} #endif
LCD1602驱动程序 #ifndef __1602_H__ #define __1602_H__
#define uint unsigned int #define uchar unsigned char #define LCD P0 sbit RS=P2^4; sbit RW=P2^5; sbit EN=P2^6; void delayms(uint z); void Init_1602(void); void check_busy(void); void write_com(uchar com); void write_dat(uchar dat);
/********************延时****************/ void delayms(uint z) {
z
毫秒
void Init_1602(void) { delayms(15); write_com(0x38); delayms(5); write_com(0x0c); delayms(5); write_com(0x06); delayms(5); write_com(0x01); delayms(5); write_com(0x80); delayms(5);
}
/************************** 将数据二进制高地位对换 (为了连线方便但片机P0口 与lcd1602数据口反接) ****************************/ uchar HL_exchange(uchar dat)
{
uchar i,temp; temp = 0x00; for(i=0;i
{
temp >>= 1; if((dat
temp |= 0x80; } else {
temp &= 0x7F; } }
return temp; }
/**********读忙*****************/ void check_busy(void) { uchar x;
x=HL_exchange(0x80); while(x&HL_exchange(0x80)) { RS=0; RW=1; EN=1; x=LCD; EN=0; delayms(10);
}
}
/**************写指令**************/ void write_com(uchar com)
{ check_busy(); RS=0; RW=0; EN=1; LCD=0XFF;
LCD=HL_exchange(com); EN=0; delayms(10);
}
/**************写数据**************/ void write_dat(uchar dat) { check_busy(); RS=1;
RW=0; EN=1; LCD=0XFF;
LCD=HL_exchange(dat); EN=0; delayms(10); }
#endif