课程名称: 电子系统课程设计 题 目: 数字温度计
学 院: 信息工程 系: 电子信息工程 专 业: 电子信息工程 班 级: 电子113 学 号: 61002111869 学生姓名: 周 游 起讫日期: 2014.12.8--2014.12.19 指导教师: 王艳庆 职称: 副教授 系分管主任: 王玉皞 审核日期:
一.绪论
随着时代的发展,控制智能化,仪器小型化,功耗微量化得到广泛关注。单片机控制系统无疑在这些忙面起到了举足轻重的作用。单片机的应用系统设计业已成为新的技术热点,其中数字温度计就是一个典型的例子。随着人们生活水平的提高,人们对各种测量器具的智能化、多功能化提出了更高的要求,而电子技术的飞速发展使得单片机在各种测量产品领域中的应用越来越广泛。把以单片机为核心,开发出来的各种测量及控制系统作为测量产品的主要部分,使各种测量产品更具智能化、拥有更多功能、便于人们操作和使用,更具时代感,这是测量产品的发展方向和趋势所在。这就要求我们的生产具有自动控制系统,自动控制主要是由计算机的离线控制和在线控制来实现的,离线应用包括利用计算机实现对控制系统总体的分析、设计、仿真及建模等工作;在线应用就是以计算机代替常规的模拟或数字控制电路使控制系统“软化”,使计算机位于其中,并成为控制系统、测试系统及信号处理系统的一个组成部分,这类控制由于计算机要身处其中,因此对计算机有体积小、功耗低、价格低廉以及控制功能强有很高的要求,为满足这些要求,应当使用单片机。单片机在电子产品中应用的广泛,在很多的电子产品中也用到了温度检测和温度控制,但那些温度检测与控制电路通常较复杂,成本也高,本设计提供了一种低成本的利用单片机多余I/O口实现的温度检测电路,该电路非常简单,且易于实现,并且适用于几乎所有类型的单片机。
温度作为一个重要的物理量,是工业生产过程中最普遍、最重要的工艺参数之一,所以温度测量技术和测量仪器的研究是一个重要的课题。随着时代的进步和发展,单片机技术已经伸入到各个领域,基于单片机数字温度计与传统的温度计相比,具有读数方便,测温范围广,其输出温度采用数字显示。
本次设计目是利用51单片机及温度传感器设计一个温度采集系统,通过学过的单片机和数字电路及面向对象编程等课程的知识设计。要求的功能是能通过温度传感器采集的数据在液晶屏显示,采集的温度达一定的精度。
二.设计目的
1.理解掌握MCS-51系列单片机的功能和实际应用。
2.掌握仿真开发软件的使用。
3.掌握数字式温度计电路的设计、组装与调试方法。
三.设计要求
1.以MCS-51系列单片机为核心器件,组成一个数字式温度计。
2.采用数字式温度传感器为检测器件,进行单点温度检测,检测精度为0.5C
3.温度显示采用4位LED数码管显示,三位整数,一位小数。 4.具有键盘输入上下限功能,超过上下限温度时,进行声音报警。
四.设计思路
1.根据设计要求,选择AT89C52单片机为核心器件。
2.温度检测器件采用DS18B20数字式温度传感器。与单片机的接口为P3.6引脚。
3.键盘采用独立式按键,由三个按键组成,分别是:设置键(SET),加一建(+1),确认键(RET)。
SET键(上下限温度设置键):当该键按下时,进入上下限温度设置功能。通过P3.1引脚接入。
+1键(加一调整键):在输入上下限温度时,该键按下一次,被调整位加一。通过P3.2引脚接入。
RET键(确认键):当该键按下时,指向下一个要调整的位。通过P3.3引脚接入。
4.声音报警蜂鸣器通过P1.7引脚接入。
硬件电路设计总体框图为图4.1:
按键输入电 路 LED显示器驱动电路 3位LED显示器 时钟电路复单片机 位电路 温度检测 蜂鸣器电路 图4.1
五、系统的硬件构成及功能 1.主控制器
单片机AT89S52具有低电压供电和体积小等特点,四个端口只需要两个口就能满足电路系统的设计需要,使用Atmel公司高密度非易失性存储器技术制造,与工业80C51产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。很适合便携手持式产品的设计使用。
AT89S52在仿真软件中的图像如下
2.显示电路
显示电路采用四位共阳LED数码管,从P3口RXD,TXD串口输出段码。 LED数码管在仿真软件中如图
3.温度传感器
DS18B20是美国DALLAS半导体公司最新推出的一种改进型智能温度传感器,与传统的热敏电阻等测温元件相比,它能直接读出被测温度,并且可根据实际要求通过简单的编程实现9~12位的数字值读数方式。DS18B20的性能特点如下:
• 独特的单线接口仅需一个端口引脚进行通讯 • 简单的多点分布应用 • 无需外部器件 • 可通过数据线供电 • 零待机功耗
• 测温范围-55~+125℃,以0.5℃递增。华氏器件-67~+2570F,以0.90F 递增 • 温度以9 位数字量读出
• 温度数字量转换时间200ms(典型值) • 用户可定义的非易失性温度报警设置
• 报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件。 DS18B20内部结构主要由四部分组成:64位光刻ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。DS18B20的管脚排列、各种封装形式如图 3.3.1所示,DQ 为数据输入/输出引脚。开漏单总线接口引脚。当被用着在寄生电源下,也可以向器件提供电源;GND为地信号;VDD为可选择的VDD引脚。当工作于寄生电源时,此引脚必须接地。
DS18B20的测温原理如图所示,图中低温度系数晶振的振荡频率受温度的影响很小用于产生固定频率的脉冲信号送给减法计数器1,高温度系数晶振随温度变化其震荡频率明显改变,所产生的信号作为减法计数器2的脉冲输入,图中还隐含着计数门,当计数门打开时,DS18B20就对低温度系数振荡器产生的时钟脉冲后进行计数,进而完成温度测量.计数门的开启时间由高温度系数振荡器来决定,每次测量前,首先将-55 ℃所对应的基数分别置入减法计数器1和温度寄存器中,减法计数器1和温度寄存器被预置在-55 ℃所对应的一个基数值。
减法计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当减法计数器1的预置值减到0时温度寄存器的值将加1,减法计数器 1的预置将重新被装入,减法计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到减法计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温图5.3.3中的斜率累加器用于补偿和修正测温过程中的非线性其输出用,于修正减法计数器的预置值,只要计数门仍未关闭就重复上述过程,直至温度寄存器值达到被测温度值,这就是DS18B20的测温原理。
另外,由于DS18B20单线通信功能是分时完成的,有严格的时隙概念,因此读写时序很重要。系统对DS18B20的各种操作必须按协议进行。操作协议为:初始化DS18B20(发复位脉冲)→发ROM功能命令→发存储器操作命令→处理数据。
斜率增加器预置τ1比较低温度系数振荡器计数器 1加 1预置Txτ2= 0高温度系数振荡器计数器 2温度寄存器= 0图5.3.3
停止 在正常测温情况下,DS1820的测温分辨力为0.5℃,可采用下述方法获得高分辨率的温度测量结果:首先用DS1820提供的读暂存器指令(BEH)读出以0.5℃为分辨率的温度测量结果,然后切去测量结果中的最低有效位(LSB),得到所测实际温度的整数部分Tz,然后再用BEH指令取计数器1的计数剩余值Cs和每度计数值CD。考虑到DS1820测量温度的整数部分以0.25℃、0.75℃为进位界限的关系,实际温度Ts可用下式计算:
(Tz0.25℃)(CD-Cs)/CD Ts 表1.部分温度值对应的二进制温度数据。 温度/℃ +125 +85 +25.0625 +10.125 +0.5 0 -0.5 -10.125 -25.0625 -55 二进制表示 0000 0111 1101 0000 0000 0101 0101 0000 0000 0001 1001 0000 0000 0000 1010 0001 0000 0000 0000 0010 0000 0000 0000 1000 1111 1111 1111 0000 1111 1111 0101 1110 1111 1110 0110 1111 1111 1100 1001 0000 十六进制表示 07D0H 0550H 0191H 00A2H 0008H 0000H FFF8H FF5EH FE6FH FC90H 六.系统整体硬件电路
根据设计要求与设计思路,硬件电路设计框图如图6.1所示,在仿真软件
Proteus上完成。其中LED数码管以动态扫描法实现温度显示,由四个PNP型晶体管Q2,Q3,Q4,Q5和八个电阻组成,基极与单片机的P1.0,P1.1,P1.2连接。DS18B20的数据I/O端与单片机P3.6引脚连接。外部晶振为12MHz。蜂鸣器通过Q1放大后与引脚P1.7相连。如图
七.系统程序设计
数字式温度计的应用程序主要包括主程序,温度检测程序,温度转换程序, LED显示程序等。
系统的主程序主要用来初始化一些系统参数,对DS18B20的配置数据进行一
系列的设定。温度检测程序是对DS18B20的状态不断地查询,读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写,读取当前的温度值后,进行温度转化程序,对温度符号处理和温度值的BCD码处理,进行温度值正负的判定,将其段码送至显示缓冲区,以备定时扫描服务程序处理。LED显示程序主要对显示缓冲器中的显示数据进行刷新操作,当最高显示位为0时,将符号显示位移入下一位。总程序程序代码见附录一
开始
显示缓冲区初始化
复位DS18B20
发跳过ROM命令 发温度转换命令 延时 复位DS18B20 发跳过ROM命令 发读存储器命令 读温度数据 温度符号判定
八.仿真
1.Proteus仿真结果
软件方面,在Proteus编译下进行,源程序编译及仿真调试。
将温度转换为BCD码 更新显示缓冲区
九.设计心得体会
本次课设对我来说是一次难得的经历,首先是第一次接触了仿真软件Proteus,在使用时经历了很多次失败,因为这款软件与以前使用的各种软件有很多不同,使用时不停出错,接线时由于元件放置不合理而接的杂乱无章;输入源程序时还较为顺利,显示结果比较满意。其次是程序设计,我们在参考别人成功先例的基础上根据自己设计的需要编制程序,其中历经不少曲折,最后我的收获是,编程一定要细心,针对每一个细节,稍有疏忽,程序就不能正常工作。
在这次的实践与学习中,尽管期间困难重重,但我还是从中学习了不少新的知识与技能和解决困难的方法,也终于体验到了经历困难到最终获得成功的那种无以言表的喜悦之情,总之,本次课设是我收获最多的一次,也希望自己在以后的各项研究活动中能坚持这种精神。
附录一 源程序
#include #include \"intrins.h\" //_nop_();延时函数用 #define dm P0 //段码输出口 #define uchar unsigned char #define uint unsigned int sbit DQ=P2^7; //温度输入口 sbit w0=P2^0; //数码管4 sbit w1=P2^1; //数码管3 sbit w2=P2^2; //数码管2 sbit w3=P2^3; //数码管1 sbit beep=P1^7; //蜂鸣器和指示灯 sbit set=P2^6; //温度设置切换键 sbit add=P2^4; //温度加 sbit dec=P2^5; //温度减 int temp1=0; //显示当前温度和设置温度的标志位为0 时显示当前温度 uint h; uint temp; uchar r; uchar high=35,low=20; uchar sign; uchar q=0; uchar tt=0; uchar scale; //**************温度小数部分用查表法***********// uchar code ditab[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09}; //小数断码表 uchar code table_dm[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40}; //共阴LED 段码表\"0\" \"1\" \"2\" \"3\" \"4\" \"5\" \"6\" \"7\" \"8\" \"9\" \"不亮\" \"-\" uchar table_dm1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; //个位带小数点的断码表 uchar data temp_data[2]={0x00,0x00}; //读出温度暂放 uchar data display[5]={0x00,0x00,0x00,0x00,0x00}; //显示单元数据,共4 个数据和一个运算暂用 /*****************11us 延时函数*************************/ void delay(uint t) { for (;t>0;t--); } void scan() { int j; for(j=0;j<4;j++) { switch (j) { case 0: dm=table_dm[display[0]];w0=0;delay(50);w0=1;//xiaoshu case 1: dm=table_dm1[display[1]];w1=0;delay(50);w1=1;//gewei case 2: dm=table_dm[display[2]];w2=0;delay(50);w2=1;//shiwei case 3: dm=table_dm[display[3]];w3=0;delay(50);w3=1;//baiwei // else{dm=table_dm[b3];w3=0;delay(50);w3=1;} } } } //***************DS18B20 复位函数************************/ ow_reset(void) { char presence=1; while(presence) { while(presence) { DQ=1;_nop_();_nop_();//从高拉倒低 DQ=0; delay(50); //550 us DQ=1; delay(6); //66 us presence=DQ; //presence=0 复位成功,继续下一步 } delay(45); //延时500 us presence=~DQ; } DQ=1; //拉高电平 } /****************DS18B20 写命令函数************************/ //向1-WIRE 总线上写1 个字节 void write_byte(uchar val) { uchar i; for(i=8;i>0;i--) { DQ=1;_nop_();_nop_(); //从高拉倒低 DQ=0;_nop_();_nop_();_nop_();_nop_(); //5 us DQ=val&0x01; //最低位移出 delay(6); //66 us val=val/2; //右移1 位 } DQ=1; delay(1); } /****************DS18B20 读1 字节函数************************/ //从总线上取1 个字节 uchar read_byte(void) { uchar i; uchar value=0; for(i=8;i>0;i--) { DQ=1;_nop_();_nop_(); value>>=1; DQ=0;_nop_();_nop_();_nop_();_nop_(); //4 us DQ=1;_nop_();_nop_();_nop_();_nop_(); //4 us if(DQ)value|=0x80; delay(6); //66 us } DQ=1; return(value); } /*****************读出温度函数************************/ read_temp() { ow_reset(); //总线复位 delay(200); write_byte(0xcc); //发命令 write_byte(0x44); //发转换命令 ow_reset(); delay(1); write_byte(0xcc); //发命令 write_byte(0xbe); temp_data[0]=read_byte(); //读温度值的第字节 temp_data[1]=read_byte(); //读温度值的高字节 temp=temp_data[1]; temp<<=8; temp=temp|temp_data[0]; // 两字节合成一个整型变量。 return temp; //返回温度值 } /****************温度数据处理函数************************/ //二进制高字节的低半字节和低字节的高半字节组成一字节,这个 //字节的二进制转换为十进制后,就是温度值的百、十、个位值,而剩 //下的低字节的低半字节转化成十进制后,就是温度值的小数部分 /********************************************************/ work_temp(uint tem) { uchar n=0; if(tem>6348) // 温度值正负判断 {tem=65536-tem;n=1;} // 负温度求补码,标志位置1 display[4]=tem&0x0f; // 取小数部分的值 display[0]=ditab[display[4]]; // 存入小数部分显示值 display[4]=tem>>4; // 取中间八位,即整数部分的值 display[3]=display[4]/100; // 取百位数据暂存 display[1]=display[4]%100; // 取后两位数据暂存 display[2]=display[1]/10; // 取十位数据暂存 display[1]=display[1]%10; //个位数据 r=display[1]+display[2]*10+display[3]*100; /////符号位显示判断///// if(!display[3]) { display[3]=0x0a; //最高位为0 时不显示 if(!display[2]) { display[2]=0x0a; //次高位为0 时不显示 } } if(n){display[3]=0x0b;} //负温度时最高位显示\"-\" } void BEEP() { if((r>=high&&r<129)||r beep=0; } } //*********设置温度显示转换************// void xianshi(int horl) { int n=0; if(horl>128) { horl=256-horl;n=1; } display[3]=horl/100; display[3]=display[3]&0x0f; display[2]=horl%100/10; display[1]=horl%10; display[0]=0; if(!display[3]) { display[3]=0x0a; //最高位为0 时不显示 if(!display[2]) { display[2]=0x0a; //次高位为0 时不显示 } } if(n) { display[3]=0x0b; //负温度时最高位显示\"-\" } } //*********按键查询程序**************// void keyscan() { int temp1; //最高温度和最低温度标志位 if(set==0) { while(1) { delay(500);//消抖 if(set==0) { temp1++; while(!set) scan(); } if(temp1==1) { xianshi(high); scan(); if(add==0) { while(!add) scan(); high+=1; } if(dec==0) { while(!dec) scan(); high-=1; } } if(temp1==2) { xianshi(low); if(add==0) { while(!add) scan(); low+=1; } if(dec==0) { while(!dec) scan(); low-=1; } scan(); } if(temp1>=3) { temp1=0; break; } } } } /****************主函数************************/ void main() { dm=0x00; //初始化端口 w0=0; w1=0; w2=0; w3=0; for(h=0;h<4;h++) //开机显示\"0000\" { display[h]=0; } ow_reset(); //开机先转换一次 write_byte(0xcc); //Skip ROM write_byte(0x44); //发转换命令 for(h=0;h<100;h++) //开机显示\"0000\" { scan(); } while(1) { 附录二 原理图 if (temp1==0) { work_temp(read_temp()); //处理温度数据 BEEP(); scan(); //显示温度值 keyscan(); } else keyscan(); } } //***********************结束**************************// 因篇幅问题不能全部显示,请点此查看更多更全内容