温度控制系统(设计)
题 目: | 基于52单片机的温度控制系统设计 |
姓 名: | |
学 院: | 工学院 |
班 级: | 自动化81班 |
学 号: | |
指导教师: | |
2011 年 5 月 17日 | |
南京农业大学教务处制 |
温度的测量和控制对人类日常生活、工业生产、气象预报、物资仓储等都起着极其重要的作用。在许多场合,及时准确获得目标的温度、湿度信息是十分重要的,近年来,温湿度测控领域发展迅速,并且随着数字技术的发展,温湿度的测控芯片也相应的登上历史的舞台,能够在工业、农业等各领域中广泛使用。
鉴于此,本文对基于单片机的温湿度计系统进行了相关研究。本系统是通过单片机控制来实现对周围环境的温湿度进行测量。本系统是以ATC52单片机为控制单元、温度传感器DS18B20为主要检测器件,实现温度、湿度的测量、显示、控制,并利用单片机之间的通信功能,将所采集到的温度和湿度值在液晶屏中显示出来。温度测量范围为测温范围 -55℃~+125℃,精度为±0.0625℃。
本文旨在通过软、硬件的有机结合,以硬件为基础,进行各功能模块的编写。论文对系统硬件的工作原理进行了简单描述,并附以系统硬件设计框图。并具体描述LED数码管显示、DS18B20及ATC52等器件外接电路接口的软、硬件调试,程序流程和实现过程。
单片机介绍:
单片机介绍
单片微型计算机简称单片机,是典型的嵌入式微控制器(Microcontroller Unit),常用英文字母的缩写MCU表示单片机,它最早是被用在工业控制领域。单片机由芯片内仅有CPU的专用处理器发展而来。最早的设计理念是通过将大量外围设备和CPU集成在一个芯片中,使计算机系统更小,更容易集成进复杂的而对体积要求严格的控制设备当中。
单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。相当于一个微型的计算机,和计算机相比,单片机只缺少了I/O设备。概括的讲:一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、为学习、应用和开发提供了便利条件。同时,学习使用单片机是了解计算机原理与结构的最佳选择。
单片机内部也用和电脑功能类似的模块,比如CPU,内存,并行总线,还有和硬盘作用相同的存储器件,不同的是它的这些部件性能都相对我们的家用电脑弱很多,不过价钱也是低的,一般不超过10元即可......用它来做一些控制电器一类不是很复杂的工作足矣了。我们现在用的全自动滚筒洗衣机、排烟罩、VCD等等的家电里面都可以看到它的身影!......它主要是作为控制部分的核心部件。
单片机自动完成赋予它的任务的过程,也就是单片机执行程序的过程,即一条条执行的指令的过程,所谓指令就是把要求单片机执行的各种操作用的命令的形式写下来,这是在设计人员赋予它的指令系统所决定的,一条指令对应着一种基本操作;单片机所能执行的全部指令,就是该单片机的指令系统,不同种类的单片机,其指令系统亦不同。为使单片机能自动完成某一特定任务,必须把要解决的问题编成一系列指令(这些指令必须是选定单片机能识别和执行的指令),这一系列指令的集合就成为程序,程序需要预先存放在具有存储功能的部件——存储器中。存储器由许多存储单元(最小的存储单位)组成,就像大楼房有许多房间组成一样,指令就存放在这些单元里,单元里的指令取出并执行就像大楼房的每个房间的被分配到了唯一一个房间号一样,每一个存储单元也必须被分配到唯一的地址号,该地址号称为存储单元的地址,这样只要知道了存储单元的地址,就可以找到这个存储单元,其中存储的指令就可以被取出,然后再被执行。
程序通常是顺序执行的,所以程序中的指令也是一条条顺序存放的,单片机在执行程序时要能把这些指令一条条取出并加以执行,必须有一个部件能追踪指令所在的地址,这一部件就是程序计数器PC(包含在CPU中),在开始执行程序时,给PC赋以程序中第一条指令所在的地址,然后取得每一条要执行的命令,PC在中的内容就会自动增加,增加量由本条指令长度决定,可能是1、2或3,以指向下一条指令的起始地址,保证指令顺序执行。
使用软件简介:
一,Keil软件:
Keil软件是目前最流行开发MCS-51系列单片机的软件,这从近年来各仿真机厂商纷纷宣布全面支持Keil即可看出。Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。运行Keil软件需要Pentium或以上的CPU,16MB或更多RAM、20M以上空闲的硬盘空间、WIN98、NT、WIN2000、WINXP等操作系统。掌握这一软件的使用对于使用51系列单片机的爱好者来说是十分必要的,如果你使用C语言编程,那么Keil几乎就是你的不二之选(目前在国内你只能买到该软件、而你买的仿真机也很可能只支持该软件),即使不使用C语言而仅用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。
二,Proteus软件:
Proteus软件是一种低投资的电子设计自动化软件,提供可仿真数字和模拟、交流和直流等数千种元器件和多达30多个元件库。Proteus软件提供多种现实存在的虚拟仪器仪表。此外,Proteus还提供图形显示功能,可以将线路上变化的信号,以图形的方式实时地显示出来。这些虚拟仪器仪表具有理想的参数指标,例如极高的输入阻抗、极低的输出阻抗,尽可能减少仪器对测量结果的影响,Proteus软件提供丰富的测试信号用于电路的测试。这些测试信号包括模拟信号和数字信号。提供Schematic Drawing、SPICE仿真与PCB设计功能,同时可以仿真单片机和周边设备,可以仿真51系列、AVR、PIC等常用的MCU,并提供周边设备的仿真,例如373、led、示波器等。Proteus提供了大量的元件库,有RAM、ROM、键盘、马达、LED、LCD、AD/DA、部分SPI器件、部分IIC器件,编译方面支持Keil和MPLAB等编译器。
一台计算机、一套电子仿真软件,在加上一本虚拟实验教程,就可相当于一个设备先进的实验室。以虚代实、以软代硬,就建立一个完善的虚拟实验室。在计算机上学习电工基础,模拟电路、数字电路、单片机应用系统等课程,并进行电路设计、仿真、调试等。
DS18B20简介:
DS18B20可以程序设定9~12位的分辨率,精度为±0.5°C。可选更小的封装方式,更宽的电压适用范围。分辨率设定,及用户设定的报警温度存储在EEPROM中,掉电后依然保存。DS18B20的性能是新一代产品中最好的!性能价格比也非常出色!
DS1822与 DS18B20软件兼容,是DS18B20的简化版本。省略了存储用户定义报警温度、分辨率参数的EEPROM,精度降低为±2°C,适用于对性能要求不高,成本控制严格的应用,是经济型产品。
继“一线总线”的早期产品后,DS1820开辟了温度传感器技术的新概念。DS18B20和DS1822使电压、特性及封装有更多的选择,让我们可以构建适合自己的经济的测温系统。
项目视图:
项目原理图:
项目数据读取视图:
程序简介:
该程序主要是对DS18B20的数据采集进行设定,我们对每个子函数是分开来编写的,众多子函数构成一体就完成了程序要求的功能。
本程序在重要语句和函数后都有注释,主要是便于程序阅读。在温度比较过程中,我们设置了一段函数如下:
if (tt>=ht)
hh++;
if (hh==20)
{
hightemp() ;
hh=0;
}
if (tt<=lt)
ll++;
if (ll==20)
{
lowtemp() ;
ll=0;
}
从而有效的避开了DS18B20数据采集错误而导致的误报警。当然,这只在有设置温度超过高温限或低于低温限而显烁的程序中才有明显的作用。如果程序不设置不显烁,由于误读次数较少,对数码管的显示影响基本为零。同时,我们的程序在很多方面也有很多可取之处,在程序的注释内容中都能看到,如对读入数据进行四舍五入,提高显示的精度。还有我们程序的具有很好的可读性,当然我们的程序也还有很多待改进之处。
功能介绍:
在程序设计过程中我们预设了高低温度限。在硬件上我们设计了3个按钮,其中key0接P1_0口,key1接P1_1口,key2接P1_2口,其中key0口主要用于复位和高低温设置切换。当单片机上电后,按下key0进入高温设定,按key1就行加一,按key2就进行减一,设定好高温上限后再按key0,数码管显烁两下表示高温设定完成。此后,再按key0进入低温设定,按key1就行加一,按key2就进行减一,设定好高温上限后再按key0,数码管显烁两下表示低温设定完成,此后高低温设定完了程序自动进入温度采集和显示。当在温度采集显示过程中,如果我们想要重新设定高低温限,长按key0达2s即可进入高低温限设置。当温度高于最高温限或低于最低温限是,数码管显示当前温度并且进行显烁。因为我们是第一次实习,程序设计相当比较简单,主要是使我们对单片机有更深的了解。
实习感想:
单片机两周实习,过的很快,我从一开始的迷茫到现在对单片机的软硬件结合有一定的了解,感觉收获挺大的,这也是我第一次进行软硬件的结合。实习两周虽然很辛苦,但感觉很充实。
刚开始拿到老师给的题目,我们就开始分析应该需要用到哪些知识,我们发现首先应该了解Keil和protel软件的使用,其次就是DS18B20的数据采集和编程问题。由于汇编程序是非常晦涩难懂的,所以我们决定采用C语言进行编程,而我们本身学的是汇编,所以我就在网上下载了一个郭天祥的基于C的单片机教学视频,开始前四天我基本就在看视频学习。在学习过程中,我学到了很多编程技巧,对我之后写编程序有很大的帮助。
在对DS18B20的编程过程中,我们遇到了数据不能正确读取的问题,最后发现其实就是延时的问题,因为一开始我们参考网上的相关程序认为Delay(1)是延时1us,而事实上我们忽略了芯片晶振频率,通过keil设置断点的方法,我们最终得到的是Delay(1)延迟时间是8us左右,按照这种设置,最终我们读到了温度的数据。在对按键的设置过程开始我们设置的是六个按钮,主要是因为这样程序会比较简单,因为老师只提供了三个按钮,所以我们把按键设置成了三个,这里面用到了按键复用,主要是程序的嵌套问题,最终我们解决了这个问题,也学会了怎样进行按键复用。另外,标志位flag的灵活使用,不仅仅解决了很多语句判断问题,而且会是我们得程序看起来更加简洁。
程序调试是一件很辛苦的事,当我们的数码管不能正确的显示温度和字符,而对程序进行修改的多次尝试下仍然不正确的时候,我真的感觉自己要崩溃了,好在有我的舍友和我一块进行了将近4小时的调试,最后终于解决了。在成功调试好的时候,真的很有成就感。
分组实习最重要的是队友之间的分工合作问题,因为要掌握的东西太多,所以我们进行了明确的分工。我主要是负责程序设计和编辑报告,而李飞銮则主要负责电路图设计和电路焊接,每个人都各有所职,都把各自这部分任务做到最好,这就是这次实习的最大收获。
最后,感谢我的队友和舍友,此次实习能够顺利完成,离不开我们之间的相互帮助;同时也感谢胡飞老师和学校能给我们这么一次宝贵的实习机会;还要感谢的是郭天祥大哥,你的单片机视频教的很不错。
实习程序代码:
#include #include #include #define uchar unsigned char #define uint unsigned int sbit beeph = P1^4; //高温发光二极管报警端口 sbit beepl = P1^5; //低温发光二极管报警端口 sbit beep = P3^1; //低,高温声音报警端 sbit key0 = P1^0; sbit key1 = P1^1; sbit key2 = P1^2; sbit DQ=P3^0; //数据口define interface void delay1(uint) ; void Delay(uint ) ; void hightemp() ; void lowtemp() ; void keyscan() ; void showhigh() ; void showlow() ; bit Init_DS18B20(void) ; uchar ReadOneChar(void) ; void WriteOneChar(uchar) ; void Read_Temperature(void) ; void Disp_Temperature(uint) ; uint Temperature() ; bit presence ,fg ; uint wd100; uint ht=50,lt=20; unsigned char data temp_data[2] = {0x00,0x00} ; uchar code table[13]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x63,0x39}; /********* 主函数MAIN**************/ main() { uint flag ,hh,ll,tt; while(1) { beep=1; beepl=1; beeph=1; flag = 1; keyscan() ; while(flag) { beep=1; beepl=1; beeph=1; if(!presence) { Read_Temperature(); wd100 = Temperature(); Disp_Temperature(wd100); tt = wd100/100; if (tt>=ht) hh++; if (hh==20) { hightemp() ; hh=0; } if (tt<=lt) ll++; if (ll==20) { lowtemp() ; ll=0; } } else { Init_DS18B20(); } if(key0==0) { delay1(5); if(key0==0) { flag=0; P2=0xff; } while(!key0); delay1(5); while(!key0); } //长按 2S 进入温度上下限设置。 } } } /******* 显示最高温度**************/ void showhigh() { uchar B1,B2; B1=ht/10; B2=ht%10; P2 = 0xfe; P0= table[B1]; Delay(80); P0 = 0; P2 = 0xfd; P0= table[B2]; Delay(80); P0 = 0; P2 = 0xfb; P0 = table[11]; Delay(80); P0=0 ; P2 = 0xf7; P0 = table[12]; Delay(80); P0=0 ; } /******* 显示最低温度**************/ void showlow() { uchar B1,B2; B1=lt/10; B2=lt%10; P2 = 0xfe; P0= table[B1]; Delay(80); P0 = 0; P2 = 0xfd; P0= table[B2]; Delay(80); P0 = 0; P2 = 0xfb; P0 = table[11]; Delay(80); P0=0 ; P2 = 0xf7; P0 = table[12]; Delay(80); P0=0 ; } /************高温报警程序*************/ void hightemp() { uint xs; beeph=0; beep=0; xs=50; while(xs--) { Disp_Temperature(wd100); } P0=0; delay1(500); //超过最高温度,前两个数码管显示高温上限,后四个数码管显示当前温度,并显烁。 } /************低温报警程序*************/ void lowtemp() { uint xs; beepl=0; beep=0; xs=50; while(xs--) { Disp_Temperature(wd100); } P0=0; delay1(700); //低于最低温度,前两个数码管显示高温上限,后四个数码管显示当前温度,并显烁。 } /***********键盘键入程序************/ void keyscan() { uint flag,flag1=2,xs; P1=0xff; while(flag1) { if(key0==0) { delay1(5); if(key0==0) { flag1--; flag=1; } while(!key0); delay1(5); while(!key0); while (flag1==1) { showhigh(); while(flag) { showhigh(); if(key1==0) { delay1(5); if(key1==0) { ht++; while(!key1); delay1(5); while(!key1); } continue; } if(key2==0) { delay1(5); if(key2==0) { ht--; while(!key2); delay1(5); while(!key2); } continue; } if(key0==0) { delay1(5); if(key0==0) { flag=0; while(!key0); delay1(5); while(!key0); } continue; } } xs=500; while(xs--) { showhigh(); } P0=0; delay1(500); xs=500; while(xs--) { showhigh(); } P0=0; delay1(500); xs=500; while(xs--) { showhigh(); } P0=0; //高温键入完成,显烁两下。 break; } while (flag1==0) { showlow(); while (flag) { showlow(); if(key1==0) { delay1(5); if(key1==0) { lt++; while(!key1); delay1(5); while(!key1); } } if(key2==0) { delay1(5); if(key2==0) { lt--; while(!key2); delay1(5); while(!key2); } } if(key0==0) { delay1(5); if(key0==0) { flag=0; while(!key0); delay1(5); while(!key0); } } } xs=500; while(xs--) { showlow(); } P0 = 0; delay1(500); xs=500; while(xs--) { showlow(); } P0 = 0; delay1(500); xs=500; while(xs--) { showlow(); } P0=0;//低温键入完成,显烁两下。 break; } } } } /*************延时ms函数*****************/ void delay1(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } /***************************us级延时函数*******************************************/ void Delay(unsigned int num) { while( --num ) ; } /******************************初始化ds1820*************************************/ bit Init_DS18B20(void) { DQ = 1 ; //DQ复位 Delay(8) ; //稍做延时 DQ = 0 ; //单片机将DQ拉低 Delay(75) ; //精确延时大于480us DQ = 1 ; //拉高总线 Delay(4) ; presence = DQ ; //如果=0则初始化成功=1则初始化失败 Delay(30) ; DQ = 1 ; return(presence) ; //返回信号,=presence,1= no presence } /******************************读一个字节**************************************/ uchar 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(8) ; } return (dat) ; } /*******************************写一个字节*********************************************/ void WriteOneChar(uchar dat) { unsigned char i = 0 ; for (i = 8 ; i > 0 ; i--) { DQ = 0 ; DQ = dat&0x01 ; Delay(8) ; DQ = 1 ; dat>>=1 ; } } /****************************读取温度******************************************/ void Read_Temperature(void) { Init_DS18B20() ; WriteOneChar(0xCC) ; // 跳过读序号列号的操作 WriteOneChar(0x44) ; // 启动温度转换 Init_DS18B20() ; WriteOneChar(0xCC) ; //跳过读序号列号的操作 WriteOneChar(0xBE) ; //读取温度寄存器 temp_data[0] = ReadOneChar() ; //温度低位 temp_data[1] = ReadOneChar() ; //温度高位 } /****************************温度转换*********************************/ uint Temperature() { unsigned int sdata; unsigned int a; unsigned int b; fg = 1; a=temp_data[0]; b=temp_data[1]; if(b>0x7f) //最高位为时温度是负 { a=~a; b=~b+1; //补码转换,取反加一 fg=0; //读取温度为负时fg=0 } b&=0x07; sdata = b*256+a; //整数部分 sdata = sdata*0.0625*100+0.5; return (sdata) ; } /****************************LED温度显示**********************************/ void Disp_Temperature(uint sdata) { unsigned int xiaoshu1;//小数第一位 unsigned int xiaoshu2;//小数第二位 xiaoshu1 = sdata%100/10; //小数第一位 xiaoshu2 = sdata%10;//小数第二位 if(fg==1) //温度为正时显示的数据 { P2=0xfe; P0=table[sdata/1000]; //输出十位数 Delay(800); P0=0; P2=0xfd; P0=table[sdata%1000/100]|0x80 ; //输出个位和小数点 Delay(800); P0=0; P2=0xfb; P0=table[xiaoshu1]; //输出小数点后第一位 Delay(800); P0=0; P2=0xf7; P0=table[xiaoshu2]; //输出小数点后第二位 Delay(800); P0=0; } if(fg==0) //温度为负时显示的数据 { P2=0xfe; P0=table[10]; //负号 Delay(800); P0=0; P2=0xfd; P0=table[sdata/1000]; //输出十位数 Delay(800); P0=0; P2=0xfb; P0=table[sdata%1000/100]|0X80; //输出个位和小数点 Delay(800); P0=0; P2=0xf7; P0=table[xiaoshu1]; //输出小数点后第一位 Delay(800); P0=0; } }下载本文