找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6745|回复: 1
打印 上一主题 下一主题
收起左侧

基于单片机的智能温度监测系统设计(电路图+程序)

[复制链接]
跳转到指定楼层
楼主

本次设计的主要思路是利用51系列单片机,数字温度传感器DS18B20和1602LCD液晶显示,构成实现温度检测与显示的单片机控制系统,即数字温度计。通过对单片机编写相应的程序,达到能够实时检测周围温度的目的。 通过对本课题的设计能够熟悉数字温度计的工作原理及过程,了解各功能器件(单片机、DS18B20、LCD)的基本原理与应用,掌握各部分电路的硬件连线与程序编写,最终完成对数字温度计的总体设计。其具体的要求如下: 1、根据设计要求,选用AT89C51单片机为核心器件; 2、温度检测器件采用DS18B20数字式温度传感器,利用单总线式连接方式与单片机的串行接口P3.3引脚相连; 3、显示电路采用1602LCD液晶显示温度值,此类液晶模块不仅可以显示数字、字符,还可以显示各种图形符号以及少量自定义符号,人机界面友好,使用操作也更加灵活、方便,使其日益成为各种仪器仪表等设备的首选。

系统的开发过程

本设计主要介绍了用单片机和数字温度传感器DS18B20相结合的方法来实现温度的采集,以单片机AT89C51芯片为核心,温度传感器DS18B20和1602LCD液晶显示,构成了一个多功能单片机数字温度计。其主要研究内容包括两方面,一是对系统硬件部分的设计,包括温度采集电路和显示电路;二是对系统软件部分的设计,应用C语言实现温度的采集与显示。通过利用数字温度传感器DS18B20进行设计,能够满足实时检测温度的要求,同时通过1602LCD的显示功能,可以实现不间断的温度显示。其总体设计框图一如下:



图一:总体设计框图

第一节AT89C51简介

AT89C51是美国ATMEL公司生产的低功耗,高性能CMOS8位单片机,片内含4kbytes的可编程的Flash只读程序存储器,兼容标准8051指令系统及引脚,并集成了 Flash 程序存储器,既可在线编程(ISP),也可用传统方法进行编程,因此,低价位AT89C51单片机可应用于许多高性价比的场合,可灵活应用于各种控制领域,对于简单的测温系统已经足够。单片机AT89C51具有低电压供电和体积小等特点,四个端口只需要两个口就能满足电路系统的设计需要,很适合便携手持式产品的设计使用系统可用二节电池供电。芯片AT89C51的引脚排列如图二所示:



图二:AT89C51单片机引脚图

第二节晶振电路的设计

单片机晶振电路的设计如图三所示。XTAL1(X1)为反向振荡放大器的输入及内部时钟工作电路的输入。按照理论上AT89C51使用的是12MHz的晶振,但实测使用11.0592MHz。所以设计者通常用的是11.0592MHz。



图三:单片机晶振电路

第三节温度采集电路的设计

DALLAS 最新单线数字温度传感器DS18B20是一种新型的“一线器件”,其体积更小、更适用于多种场合、且适用电压更宽、更经济。DALLAS 半导体公司的数字化温度传感器DS18B20是世界上第一片支持“一线总线”接口的温度传感器。温度测量范围为-55~+125 摄氏度,可编程为9~12 位转换精度,测温分辨率可达0.0625摄氏度,分辨率设定参数以及用户设定的报警温度存储在EEPROM 中,掉电后依然保存。被测温度用符号扩展的16位数字量方式串行输出;其工作电源既可以在远端引入,也可以采用寄生电源方式产生;多个DS18B20可以并联到3 根或2 根线上,CPU只需一根端口线就能与诸多DS18B20 通信,占用微处理器的端口较少,可节省大量的引线和逻辑电路。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。本设计的温度采集电路如图四所示。



图四:温度采集电路图

第五节温度显示电路的设计

显示器常用作单片机最简单的输出设备,用以显示单片机的运行结果和运行状态等。常用的显示器主要有LED和LCD,它们都具有耗电少、成本低、线路简单、寿命长等优点,广泛应用于单片机显示数字量的场合。设计中采用LCD显示器。液晶显示器(LCD)具有功耗低、体积小、质量轻、功耗小的特点。点阵字符型液晶显示器把LCD控制器、点阵驱动器、字符存储器集成在一块印刷电路板上,构成便于应用的液晶模块。此类液晶模块不仅可以显示数字、字符,还可以显示各种图形符号以及少量自定义符号,并且可以实现屏幕的上下左右滚动、文字的闪烁等功能,人机界面友好,使用操作也更加灵活、方便,使其日益成为各种仪器仪表等设备的首选。图五为本设计的显示电路图。



图五:显示电路图

第六节应用软件介绍

本设计主要用Proteus仿真软件和Keil编译软件。

本设计主要用Proteus仿真软件和Keil编译软件 4.1.1 Proteus的介绍

Proteus软件是英国Labcenter electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件,它是目前最好的仿真单片机及外围器件的工具,虽然目前国内推广刚起步,但已受到单片机爱好者、从事单片机教学教师、致力于单片机开发应用的科技工作者的青睐。Proteus是世界上著名的EDA工具(仿真软件),从原理布图、代码调试到单片机与外围电路协同仿真,一键切换发到PCB设计,真正实现了从 概念到产品的完整设计。是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086HE MSP430等,2010年即将增加Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,它也支持IAR、Keil和MPLAB等多种编译器。

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。运行Keil软件需要WIN98、NT、WIN2000、WINXP等操作系统。如果你使用C语言编程,那么Keil几乎就是你的不二之选,即使不使用C语言而仅用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。

系统测试情况

进入测试,开关不闭合,系统默认显示1602LCD显示当前采集的温度,当温度变化时,系统实时采集DS18B20的温度并显示出来,当采集的温度超过系统所设置的上限或者下限的时候,系统自动报警,开关闭合,显示报警温度的上限值和下限值。综合仿真图如图六所示:



系统的优点与不足

优点:软件可以实时检测温度值,并显示,当温度超出预设范围时及时报警,并且还可以检测并显示零下温度。

缺点:只是做到了仿真程序,没有具体的硬件实现,系统运行时预设温度不能改动。




附录代码


  1. #include<reg51.h>
  2. #include<intrins.h>
  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. sbit DQ=P3^3;//DS18B20数据线
  6. sbit BEEP=P3^7;//报警器
  7. sbit LCD_RS=P2^0;
  8. sbit LCD_RW=P2^1;
  9. sbit LCD_EN=P2^2;
  10. sbit K1=P1^7;
  11. uchar code Temp_Disp_Title[]={" Current Temp : "};
  12. uchar Current_Temp_Display_Buffer[]={"TEMP:            "};
  13. uchar code Alarm_Temp[]={"ALARM TEMP Hi Lo"};
  14. uchar Alarm_HI_LO_STR[]={"Hi:     Lo:      "};
  15. uchar code df_Table[]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};//温度小数位对照表
  16. char Alarm_Temp_HL[2]={100,0};
  17. uchar CurrentT=0;//当前读取的温度整数部分
  18. uchar Temp_Value[]={0x00,0x00};//从DS18B20读取的温度值
  19. uchar Display_Digit[]={0,0,0,0};//待显示的各温度数位
  20. bit HI_Alarm=0,LO_Alarm=0;//高温低温报警标志
  21. bit DS18B20_IS_OK=1;//传感器正常标志
  22. uint Time0_Count=0;//定时器延时累加
  23. //延时
  24. void DelayMS(uint x){
  25.         uchar i;
  26.         while(x--)for(i=0;i<120;i++);
  27. }
  28. //读LCD状态
  29. uchar Read_LCD_State(){
  30.         uchar state;
  31.         LCD_RS=0;LCD_RW=1;LCD_EN=1;DelayMS(1);state=P0;LCD_EN=0;DelayMS(1);
  32.         return state;
  33. }
  34. //忙等待
  35. void LCD_Busy_Wait(){
  36.         while((Read_LCD_State()&0x80)==0x80);
  37.         DelayMS(5);
  38. }
  39. //写LCD指令
  40. void Write_LCD_Command(uchar cmd){
  41.         LCD_Busy_Wait();
  42.         LCD_RS=0;LCD_RW=0;LCD_EN=0;P0=cmd;LCD_EN=1;DelayMS(1);LCD_EN=0;
  43. }
  44. //向LCD写数据
  45. void Write_LCD_Data(uchar dat){
  46.         LCD_Busy_Wait();
  47.         LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;LCD_EN=1;DelayMS(1);LCD_EN=0;
  48. }
  49. //延时
  50. void DelayXus(int x){
  51.         uchar i;
  52.         while(x--)for(i=0;i<200;i++);
  53. }
  54. //延时
  55. void Delay(uint num){
  56.         while(--num);
  57. }
  58. //初始化DS18B20
  59. uchar Init_DS18B20(){
  60.         uchar status;
  61.         DQ=1;Delay(8);
  62.         DQ=0;Delay(90);
  63.         DQ=1;Delay(8);
  64.         status=DQ;
  65.         Delay(100);
  66.         DQ=1;
  67.         return status;//初始化成功返回0
  68. }
  69. //读一字节
  70. uchar ReadOneByte(){
  71.         uchar i,dat=0;
  72.         DQ=1;_nop_();
  73.         for(i=0;i<8;i++){
  74.                 DQ=0;dat>>=1;DQ=1;_nop_();_nop_();
  75.                 if(DQ)dat|=0x80;Delay(30);DQ=1;
  76.         }
  77.         return dat;
  78. }
  79. //写一个字节
  80. void WriteOneByte(uchar dat){
  81.         uchar i;
  82.         for(i=0;i<8;i++){
  83.                 DQ=0;DQ=dat&0x01;Delay(5);DQ=1;dat>>=1;
  84.         }
  85. }
  86. //读取温度值
  87. void Read_Temperature(){
  88.         if(Init_DS18B20()==1)//DS18B20故障
  89.                 DS18B20_IS_OK=0;
  90.         else{
  91.                 WriteOneByte(0xcc);//跳过序列号
  92.                 WriteOneByte(0x44);//启动温度转换
  93.                 Init_DS18B20();
  94.                 WriteOneByte(0xcc);//跳过序列号
  95.                 WriteOneByte(0xbe);//读取温度寄存器
  96.                 Temp_Value[0]=ReadOneByte();//读取低8位
  97.                 Temp_Value[1]=ReadOneByte();//温度高8位
  98.                 Alarm_Temp_HL[0]=ReadOneByte();//报警TH
  99.                 Alarm_Temp_HL[1]=ReadOneByte();//报警TL
  100.                 DS18B20_IS_OK=1;
  101.         }
  102. }        
  103. //设置DS18B20温度报警值
  104. void Set_Alarm_Temp_Value(){
  105.         Init_DS18B20();
  106.         WriteOneByte(0xcc);//跳过序列号
  107.         WriteOneByte(0x4e);//将设定的温度报警值写入DS18B20
  108.         WriteOneByte(Alarm_Temp_HL[0]);//写TH
  109.         WriteOneByte(Alarm_Temp_HL[1]);//写TL
  110.         WriteOneByte(0x7f);//12位精度
  111.         Init_DS18B20();
  112.         WriteOneByte(0xcc);//跳过序列号
  113.         WriteOneByte(0x48);//将设定的温度报警值写入DS18B20
  114. }
  115. //设置液晶显示位置
  116. void Set_LCD_POS(uchar p){
  117.         Write_LCD_Command(p|0x80);
  118. }
  119. //在LCD上显示当前温度
  120. void Display_Temperature(){
  121.         uchar i;
  122.         uchar t=150;//延时值
  123.         uchar ng=0;//负数标志
  124.         char Signed_Current_Temp;//如果为负数则取反加1,并设置负数标识
  125.         if((Temp_Value[1]&0xf8)==0xf8){
  126.                 Temp_Value[1]=~Temp_Value[1];
  127.                 Temp_Value[0]=~Temp_Value[0]+1;
  128.                 if(Temp_Value[0]==0x00)Temp_Value[1]++;
  129.                 ng=1;//设负数标识
  130.         }
  131. //查表得到温度小数部分
  132.         Display_Digit[0]=df_Table[Temp_Value[0]&0x0f];
  133. //获取温度整数部分(无符号)
  134.         CurrentT=((Temp_Value[0]&0xf0)>>4)|((Temp_Value[1]&0x07)<<4);
  135. //有符号的当前温度值,注意此处定义为char,其值可为-128~+127
  136.         Signed_Current_Temp=ng?-CurrentT:CurrentT;
  137. //高低温报警标志设置(与定义为char类型的Alarm_Temp_HL比较,这样可区分正负比较)
  138.         HI_Alarm=Signed_Current_Temp>=Alarm_Temp_HL[0]?1:0;
  139.         LO_Alarm=Signed_Current_Temp<=Alarm_Temp_HL[1]?1:0;
  140. //将整数部分分解为三位待显示数字
  141.         Display_Digit[3]=CurrentT/100;
  142.         Display_Digit[2]=CurrentT%100/10;
  143.         Display_Digit[1]=CurrentT%10;
  144. //刷新LCD显示缓冲
  145.         Current_Temp_Display_Buffer[11]=Display_Digit[0]+'0';
  146.         Current_Temp_Display_Buffer[10]='.';
  147.         Current_Temp_Display_Buffer[9]=Display_Digit[1]+'0';
  148.         Current_Temp_Display_Buffer[8]=Display_Digit[2]+'0';
  149.         Current_Temp_Display_Buffer[7]=Display_Digit[3]+'0';
  150. //高位为0时不显示
  151.         if(Display_Digit[3]==0)Current_Temp_Display_Buffer[7]=' ';
  152. //高位为0且次高位为0时,次高位不显示
  153.         if(Display_Digit[2]==0&&Display_Digit[3]==0)
  154.                 Current_Temp_Display_Buffer[8]=' ';
  155.         //负数符号显示在恰当位置
  156.         if(ng)
  157.         {
  158.                 if(Current_Temp_Display_Buffer[8]==' ')
  159.                         Current_Temp_Display_Buffer[8]='-';
  160.                 else if(Current_Temp_Display_Buffer[7]==' ')
  161.                         Current_Temp_Display_Buffer[7]='-';
  162.                 else Current_Temp_Display_Buffer[6]='-';
  163.         }
  164.         //在第一行显示标题
  165.         Set_LCD_POS(0x00);
  166.         for(i=0;i<16;i++)Write_LCD_Data(Temp_Disp_Title[ i]);
  167.         //在第二行显示当前温度
  168.         Set_LCD_POS(0x40);
  169.         for(i=0;i<16;i++)Write_LCD_Data(Current_Temp_Display_Buffer[ i]);
  170.         //显示温度符号
  171.         Set_LCD_POS(0x4d);Write_LCD_Data(0x00);
  172.         Set_LCD_POS(0x4e);Write_LCD_Data('C');
  173. }
  174. //定时器中断,控制警报声音
  175. void T0_INT()interrupt 1{
  176.         TH0=-1000/256;
  177.         TL0=-1000%256;
  178.         BEEP=!BEEP;
  179.         if(++Time0_Count==400){
  180.                 Time0_Count=0;
  181.                 TR0=0;
  182.         }
  183. }
  184. //显示报警温度
  185. void Disp_Alarm_Temperature(){
  186.         uchar i,ng;
  187.         //显示Alarm_Temp_HL数组中的报警温度值
  188.         //由于Alarm_Temp_HL类型为char,故可以直接进行正负比较
  189.         //高温报警值
  190.         ng=0;
  191.         if(Alarm_Temp_HL[0]<0)//如果为负数则取反加1
  192.         {
  193.                 Alarm_Temp_HL[0]=~Alarm_Temp_HL[0]+1;
  194.                 ng=1;
  195.         }
  196.         //分解高温各数位到待显示串中
  197.         Alarm_HI_LO_STR[4]=Alarm_Temp_HL[0]/100+'0';
  198.         Alarm_HI_LO_STR[5]=Alarm_Temp_HL[0]/10%10+'0';
  199.         Alarm_HI_LO_STR[6]=Alarm_Temp_HL[0]%10+'0';
  200.         //屏蔽高位不显示
  201.         if(Alarm_HI_LO_STR[4]=='0')Alarm_HI_LO_STR[4]=' ';
  202.         if(Alarm_HI_LO_STR[4]==' '&&Alarm_HI_LO_STR[5]=='0')
  203.                 Alarm_HI_LO_STR[5]=' ';
  204.         //"-"符号显示
  205.         if(ng){
  206.                 if(Alarm_HI_LO_STR[5]==' ')Alarm_HI_LO_STR[5]='-';
  207.                 else if(Alarm_HI_LO_STR[4]==' ')Alarm_HI_LO_STR[4]='-';
  208.                 else Alarm_HI_LO_STR[3]='-';
  209.         }
  210.         //低温报警值
  211.         ng=0;
  212.         if(Alarm_Temp_HL[1]<0)//如果为负数则取反加1
  213.         {
  214.                 Alarm_Temp_HL[1]=~Alarm_Temp_HL[1]+1;
  215.                 ng=1;
  216.         }
  217.         //分解高温各数位到待显示串中
  218.         Alarm_HI_LO_STR[12]=Alarm_Temp_HL[1]/100+'0';
  219.         Alarm_HI_LO_STR[13]=Alarm_Temp_HL[1]/10%10+'0';
  220.         Alarm_HI_LO_STR[14]=Alarm_Temp_HL[1]%10+'0';
  221.         //屏蔽高位不显示
  222.         if(Alarm_HI_LO_STR[12]=='0')Alarm_HI_LO_STR[12]=' ';
  223.         if(Alarm_HI_LO_STR[12]==' '&&Alarm_HI_LO_STR[13]=='0')
  224.                 Alarm_HI_LO_STR[13]=' ';
  225.         //"-"符号显示
  226.         if(ng){
  227.                 if(Alarm_HI_LO_STR[13]==' ')Alarm_HI_LO_STR[13]='-';
  228.                 else if(Alarm_HI_LO_STR[12]==' ')Alarm_HI_LO_STR[12]='-';
  229.                 else Alarm_HI_LO_STR[11]='-';
  230.         }
  231.         //显示高低温报警温度值
  232.         Set_LCD_POS(0x00);//显示标题
  233.         for(i=0;i<16;i++)Write_LCD_Data(Alarm_Temp[ i]);
  234.         Set_LCD_POS(0x40);//显示高低温
  235.         for(i=0;i<16;i++)Write_LCD_Data(Alarm_HI_LO_STR[ i]);
  236. }
  237. void LCD_Initialise(){
  238.         Write_LCD_Command(0x38);DelayXus(5);
  239.         Write_LCD_Command(0x01);DelayXus(5);
  240.         Write_LCD_Command(0x06);DelayXus(5);
  241.         Write_LCD_Command(0x0c);DelayXus(5);
  242. }
  243. void main(){
  244.         LCD_Initialise();
  245.         IE=0x82;
  246.         TMOD=0x01;
  247.         TH0=-1000/256;
  248.         TL0=-1000%256;
  249.         TR0=0;
  250.         K1=1;
  251.         Set_Alarm_Temp_Value();
  252.         Read_Temperature();
  253.         Delay(50000);
  254.         Delay(50000);
  255.         while(1){
  256.                 if(K1==0)
  257.                 {
  258.                         //显示报警温度上下限
  259.                         Read_Temperature();
  260.                         Disp_Alarm_Temperature();
  261.                         DelayXus(100);
  262.                 }else
  263.                 {
  264.                 //正常显示当前温度,越界时报警
  265.                                 Read_Temperature();
  266.                                 if(DS18B20_IS_OK){
  267.                                         if(HI_Alarm==1||LO_Alarm==1)TR0=1;
  268.                                                 else TR0=0;
  269.                                         Display_Temperature();
  270.                                 }
  271.                                 DelayXus(100);
  272.                 }
  273.         }
  274. }

复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:440028 发表于 2022-1-11 14:50 | 只看该作者
程序有错误吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表