所有资料51hei提供下载:
ff.rar
(7.29 MB, 下载次数: 95)

内容摘要摘要:本系统利用单片机AT89C52采用程序设计方法来测试温度,还可以通过两个按键设置温度报警上限,当测试温度超过设定的温度上限时,蜂鸣器器就会报警且绿灯关闭,红灯点亮;当温度低于上限时蜂鸣器关闭且红灯关闭,绿灯点亮。并通过液晶屏LCD12864显示其测试温度以及设置的上限温度。
1系统设计2 1.1设计任务 2 1.2基本功能 2 1.3扩展功能 2 2系统方案论证2 2.1主控模块 2 2.2显示模块 3 3 DS18B20的理论分析与计算3 4电路与程序设计6 4.1系统总体框图 6 4.2总体电路 6 4.3程序的设计 总结 附录1 附录2
1系统设计
1.1设计任务设计一数字温度测量系统,能自动实现实际温度的测量与显示。 1.2基本功能(1)测温范围-30℃~+120℃。 (2)测量误差在±0.5℃之内。 (3)能正常显示测量的温度。 (4)能正常显示测量的温度的变换曲线图。 1.3扩展功能(1)增加温控功能,并可修改设置温控的上下限。 (2)增加温控报警功能。 2系统方案论证 本系统主要由主控模块、显示模块、按键模块、蜂鸣器模块、LED模块、传感器模块组成,下面分别论证这几个模块的选择。 2.1主控模块方案:AT89C52单片机是一种高性能8位单片微型计算机。内核本身具有丰富的指令集,足够实现本次作品的全部基本功能和部分拓展功能,相比Atmega16我们对AT89C52更为熟悉,且芯片价格较低,性价比高。
2.2显示模块方案:采用LCD12864显示。LCD12864屏幕显示细腻直观,且可以显示中文,但是相对昂贵。 
3 DS18B20的理论分析与计算DS18B20 通过编程,可以实现最高 12 位的温度存储值,在寄存器中,以补码的格式存储,如图1所示。 图1 DS18B20 温度数据格式 寄存器一共 2 个字节,LSB 是低字节,MSB 是高字节,其中 MSb 是字节的高位,LSb 是字节的低位。大家可以看出来,二进制数字,每一位代表的温度的含义,都表示出来了。其中 S表示的是符号位,低 11 位都是 2 的幂,用来表示最终的温度。DS18B20 的温度测量范围是从-55 度到+125 度,而温度数据的表现形式,有正负温度,寄存器中每个数字如同卡尺的刻度一样分布,如图 2所示。 图2 DS18B20 温度值 二进制数字最低位变化 1,代表温度变化 0.0625 度的映射关系。当 0 度的时候,那就是0x0000,当温度 125 度的时候,对应十六进制是 0x07D0,当温度是零下 55 度的时候,对应的数字是 0xFC90。反过来说,当数字是 0x0001 的时候,那温度就是 0.0625 度了。 DS18B20 简单介绍: DALLAS 最新单线数字温度传感器DS18B20是一种新型的“一线器件”,其体积更小、更适用于多种场合、且适用电压更宽、更经济。DALLAS 半导体公司的数字化温度传感器DS18B20是世界上第一片支持“一线总线”接口的温度传感器。温度测量范围为-55~+125 摄氏度,可编程为9位~12 位转换精度,测温分辨率可达0.0625摄氏度,分辨率设定参数以及用户设定的报警温度存储在EEPROM 中,掉电后依然保存。被测温度用符号扩展的16位数字量方式串行输出;其工作电源既可以在远端引入,也可以采用寄生电源方式产生;多个DS18B20可以并联到3 根或2 根线上,CPU只需一根端口线就能与诸多DS18B20 通信,占用微处理器的端口较少,可节省大量的引线和逻辑电路。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。 DS18B20 的性能特点如下: ●独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯 ●DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温 ●DS18B20在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内 ●适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电 ●测温范围-55℃~+125℃,精度为±0.5℃ ●零待机功耗 ●测量结果直接输出数字信号,以“一线总线”穿行传送给CPU,同时可传送CRC校验位,具有极强的抗干扰纠错能力 ●负电压特性,电源极性接反时,温度计不会因发热而烧毁,但不能正常工作 以上特点使DS18B20非常适用与多点、远距离温度检测系统。 DS18B20内部结构主要由四部分组成:64位光刻ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。DS18B20的管脚排列、各种封装形式如图 4.2 所示,DQ 为数据输入/输出引脚。开漏单总线接口引脚。当被用着在寄生电源下,也可以向器件提供电源;GND为地信号;VDD为可选择的VDD引脚。当工作于寄生电源时,此引脚必须接地。 外部封装形式 传感器电路图 4电路与程序设计4.1系统总体框图系统总体框图如图3所示 图3 系统总体框图 4.2总体电路总体电路图见附录2。 4.3程序的设计4.3.1程序功能描述(1)能够测试-30℃~+120℃的温度。 (2)按下S1能增加温度报警上限,按下S2能减少温度报警上限。 4.3.2试验程序实验程序见附录1。
总结本系统以单片机STC89C52芯片为核心部件,利用LCD12864、独立按键、DS18B20并配合C语言算法实现了简易数字温度计设计,完成此次设计题目中的全部基本功能和部分拓展功能。在系统设计过程中,力求硬件线路简单,充分发挥软件编程方便灵活的特点,来满足系统设计要求。 在本次设计的过程中,遇到了许多突发事件和困难,设计制作曾一度止步不前,但通过仔细分析和调整后解决了一个又一个的问题。在整个过程中我们深刻的体会到团队精神的重要性,并提高了自己解决问题的能力。在课程设计的整个过程中,我遇到了许多意想不到的困难,如自己设计电路,进行软件编译等等。不仅如此,很多从未遇见过的问题和现象困扰着我,比如在调试的过程中,时常出现问题,但每次经过仔细反复查找,终于可以将这些问题针对性的找到并进行合理的改正,确保其正常实现对应的功能,在自己处理难题的过程中,真正学到了很多新的知识。
单片机源程序如下:
- #include<reg51.h>
- #include<stdlib.h>
- #include<stdio.h>//头文件
- #define uchar unsigned char
- #define uint unsigned int
- sbit DQ=P2^2;//ds18b20与单片机连接口
- sbit PWM=P1^0;//控制信号的输出
- sbit TTT=P2^3;//控制信号的输出
- unsigned char code str[]={"my name is lhh "};
- unsigned char code str_[]={"MADE IN NUPT... "};
- unsigned char code str1[]={"temper:"};
- unsigned char code str2[]={" "};
- unsigned char code nul[]={" "};
- unsigned char code str3[]={"target: "};
- unsigned char str4[6];//设定温度的存储
- uchar data disdata[5];
- uchar a[4]={0,0,0,0},j,i,k,num=0; //定义变量
- sbit js=P3^2; //红外接收端
- uchar zhb_flag=0;//保证一次解码,只执行一次代码
- uint tvalue;//温度值
- uchar tflag;//温度正负标志
- uint count=0;//按键次数初始化为0
- uint number=4;//暂时规定输入的温度为xx.x的形式
- uchar j,key;
- uint time_flag=0;
- bit enterflag=0; // 确认键按下与否标志
- uint new_t; //转化后的十进制实时温度
- uint target=0; //转化后的十进制的目标温度---有键盘输入
- //------------定义接口-------------//
- sbit RS=P3^5 ;
- sbit RW=P3^6;
- sbit E=P3^4;
- sbit PSB= P3^7; //H=并口; L="串口";
- #define Lcd_Bus P0
- // P0 接 LCM
- #define uchar unsigned char
- #define FIRST_ADDR 0
- //定义字符/汉字显示起始位置
- /*------------------检查忙位-----------------------------*/
- void chk_busy()
- {
- RS=0 ;
- RW=1 ;
- E=1 ;
- Lcd_Bus=0xff ;
- while((Lcd_Bus&0x80)==0x80);
- E=0 ;
- }
- /*------------------延时子程序-----------------------------*/
- void lcd_delay(unsigned int t)
- {
- unsigned int i,j ;
- for(i=0;i<t;i++)
- for(j=0;j<10;j++);
- }
- /*------------------写命令到LCD------------------------------*/
- void write_com(unsigned char cmdcode)
- {
- chk_busy();
- RS=0 ;
- RW=0 ;
- E=1 ;
- Lcd_Bus=cmdcode ;
- lcd_delay(5);
- //------------------在数据写入的时候加入适当的延时
- E=0 ;
- lcd_delay(5);
- }
- /*-------------------写数据到LCD----------------------------*/
- void write_data(unsigned char Dispdata)
- {
- chk_busy();
- RS=1 ;
- RW=0 ;
- E=1 ;
- Lcd_Bus=Dispdata ;
- lcd_delay(5);
- //------------------在数据写入的时候加入适当的延时
- E=0 ;
- lcd_delay(5);
- }
- /*------------------初始化LCD屏--------------------------*/
- void lcdreset()
- {
- PSB = 1;
- lcd_delay(2000);
- write_com(0x30);
- lcd_delay(10);
- //选择基本指令集
- write_com(0x30);
- //选择8bit数据流
- lcd_delay(5);
- write_com(0x0c);
- //开显示(无游标、不反白)
- lcd_delay(10);
- write_com(0x01);
- //清除显示,并且设定地址指针为00H
- lcd_delay(500);
- write_com(0x06);
- //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
- lcd_delay(0);
- }
- /*------------------显示字符串--------------------------*/
- void hzkdis(unsigned char code*s)
- {
- while(*s>0)
- {
- write_data(*s);
- s++;
- lcd_delay(50);
- }
- }
- /*------------------首屏显示--------------------------*/
- void ceshi()
- {
- write_com(0x01);
- //清除显示,并且设定地址指针为00H
- lcd_delay(5);
- write_com(0x80);
- //第一行(如果是地址是:80H,即LCD的第一行的第一个位置显示)
- hzkdis("通信1503");
- write_com(0x90);
- //第二行(如果是地址是:90H,即LCD的第二行的第一个位置显示)
- hzkdis(str);
- write_com(0x88);
- //第三行(如果是地址是:88H,即LCD的第二行的第一个位置显示)
- hzkdis("李浩浩常凡");
- write_com(0x98);
- //第四行(如果是地址是:98H,即LCD的第二行的第一个位置显示)
- hzkdis("1513024090");
- }
- //------------------清整个GDRAM空间----------------------------
- void clrgdram()
- {
- unsigned char x,y ;
- for(y=0;y<64;y++)
- for(x=0;x<16;x++)
- {
- write_com(0x34);
- write_com(y+0x80);
- //行地址
- write_com(x+0x80);
- //列地址
- write_com(0x30);
- write_data(0x00);
- write_data(0x00);
- }
- }
- //------------------------------------------------------------
- void clrscreen()
- {
- write_com(0x01);
- lcd_delay(10);
- }
- unsigned char ReadByte(void)
- {
- unsigned char byReturnValue ;
- chk_busy();
- Lcd_Bus=0xff ;
- RS=1 ;
- RW=1 ;
- E=0 ;
- E=1 ;
- byReturnValue=Lcd_Bus ;
- E=0 ;
- return byReturnValue ;
- }
- /*增加画点子程序
- 函数功能:在坐标为(x,y)点画一个点
- 参数意义
- X:12864屏幕的横坐标,范围是0到128(从左到右)
- Y:12864的纵坐标,范围是0到64(从上到下)
- Color:为1的时候表示为黑点
- */
- void DrawPoint(unsigned char X,unsigned char Y,unsigned char Color)
- {
- unsigned char Row,Tier,Tier_bit ;
- unsigned char ReadOldH,ReadOldL ;
- write_com(0x34);
- write_com(0x36);
- Tier=X>>4 ;
- Tier_bit=X&0x0f ;
- if(Y<32)
- {
- Row=Y ;
- }
- else
- {
- Row=Y-32 ;
- Tier+=8 ;
- }
- write_com(Row+0x80);
- write_com(Tier+0x80);
- ReadByte();
- ReadOldH=ReadByte();
- ReadOldL=ReadByte();
- write_com(Row+0x80);
- write_com(Tier+0x80);
- if(Tier_bit<8)
- {
- switch(Color)
- {
- case 0 :
- ReadOldH&=(~(0x01<<(7-Tier_bit)));
- break ;
- case 1 :
- ReadOldH|=(0x01<<(7-Tier_bit));
- break ;
- case 2 :
- ReadOldH^=(0x01<<(7-Tier_bit));
- break ;
- default :
- break ;
- }
- write_data(ReadOldH);
- write_data(ReadOldL);
- }
- else
- {
- switch(Color)
- {
- case 0 :
- ReadOldL&=(~(0x01<<(15-Tier_bit)));
- break ;
- case 1 :
- ReadOldL|=(0x01<<(15-Tier_bit));
- break ;
- case 2 :
- ReadOldL^=(0x01<<(15-Tier_bit));
- break ;
- default :
- break ;
- }
- write_data(ReadOldH);
- write_data(ReadOldL);
- }
- write_com(0x30);
- }
- void send_to_pc(void)
- {
- uint pc_flag=0;
- SCON=0x50;//串口方式1,允许接收
- TMOD=0x20;//定时器1,定时方式2
- TCON=0x40;//设定时器1开始计数
- TH1=0xE8;//11.0592MHz, 1200波特率
- TL1=0xE8;
- TI=1;
- TR1=1;
- while(1)
- {
- if(pc_flag==1)
- {
- TMOD=1;
- }
- else
- {
- printf("Now temperture is ");
- printf(disdata);
- printf("*0.1 C");
- pc_flag++;
- }
- }
- }
- void delay_18B20(unsigned int i)//延时1微秒
- {
- while(i--);
- }
- void ds1820rst()/*ds1820复位*/
- {
- unsigned char x=0;
- DQ = 1; //DQ复位
- delay_18B20(4); //延时
- DQ = 0; //DQ拉低
- delay_18B20(100); //精确延时大于480us
- DQ = 1; //拉高
- delay_18B20(40);
- }
- uchar ds1820rd()/*读数据*/
- {
- 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_18B20(10);
- }
- return(dat);
- }
- void ds1820wr(uchar wdata)/*写数据*/
- {
- unsigned char i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(10);
- DQ = 1;
- wdata>>=1;
- }
- }
- read_temp1()/*读取温度值并转换*/
- {
- ds1820rst();
- ds1820wr(0xcc);//*跳过读序列号*/
- ds1820wr(0x44);//*启动温度转换*/
- ds1820rst();
- }
- read_temp2()
- {
- uchar a,b;
- ds1820wr(0xcc);//*跳过读序列号*/
- ds1820wr(0xbe);//*读取温度*/
- a=ds1820rd();
- b=ds1820rd();
- tvalue=b;
- tvalue<<=8;
- tvalue=tvalue|a;
- if(tvalue<0x0fff)
- tflag=0;
- else
- {
- tvalue=~tvalue+1;
- tflag=1;
- }
- tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
- return(tvalue);
- }
- /*******************************************************************/
- void ds1820disp1()//温度值显示
- {
- uchar flagdat;
- if (tvalue>4200)
- {
- TTT=0;
- }
- disdata[0]=tvalue/1000+0x30;//百位数
- disdata[1]=tvalue%1000/100+0x30;//十位数
- disdata[2]=tvalue%100/10+0x30;//个位数
- disdata[3]=tvalue%10+0x30;//小数位
- if(tflag==0)
- flagdat=0x20;//正温度不显示符号
- else
- flagdat=0x2d;//负温度显示负号:-
- if(disdata[0]==0x30)
- {
- disdata[0]=0x20;//如果百位为0,不显示
- if(disdata[1]==0x30)
- {
- disdata[1]=0x20;//如果百位为0,十位为0也不显示
- }
- }
- }
- void ds1820disp2()
- {
- lcd_delay(5);
- write_com(0x80);
- hzkdis("温度为:");
- lcd_delay(50);
- write_com(0x84);
- write_data(disdata[1]);
- write_com(0x85);
- write_data(disdata[2]);
- write_com(0x86);
- write_data(0x2e);
- write_com(0x87);
- write_data(disdata[3]);
- if(disdata[1]>=3+0x30||(disdata[2]>=8+0x30))
- { write_com(0x98);
- hzkdis("sos"); }
- else
- { write_com(0x98);
- hzkdis(" "); }
- lcd_delay(50);
- new_t=disdata[1]*10+disdata[2];
- }
- void delay(uint us) //delay time
- {
- while(us--);
- }
- void HW_key(void)
- {
- if(zhb_flag==1)
- {
- if((a[2]+a[3])==0xff) //判断接收到数据是否正确
- {
- switch(a[2]) //将接受到的数据与所建表一一对应
- {
- case 0x00:
- {
- num=0;
- if (count<number)
- {
- str4[count]='0';
- count++;
- }break;//数字键0
- }
- case 0x01:
- {
- num=1;
- if (count<number)
- {
- str4[count]='1';
- count++;
- }break;//数字键1
- }
- case 0x02:
- {
- num=2;
- if (count<number)
- {
- str4[count]='2';
- count++;
- }break;//数字键2
- }
- case 0x03:
- {
- num=3;
- if (count<number)
- {
- str4[count]='3';
- count++;
- }break;//数字键3
- }
- case 0x04:
- {
- num=4;
- if (count<number)
- {
- str4[count]='4';
- count++;
- }break;//数字键4
- }
- case 0x05:
- {
- num=5;
- if (count<number)
- {
- str4[count]='5';
- count++;
- }break;//数字键5
- }
- case 0x06:
- {
- num=6;
- if (count<number)
- {
- str4[count]='6';
- count++;
- }break;//数字键6
- }
- case 0x07:
- {
- num=7;
- if (count<number)
- {
- str4[count]='7';
- count++;
- }break;//数字键7
- }
- case 0x08:
- {
- num=8;
- if (count<number)
- {
- str4[count]='8';
- count++;
- }break;//数字键8
- }
- case 0x09:
- {
- num=9;
- if (count<number)
- {
- str4[count]='9';
- count++;
- }break;//数字键9
- }
- case 0x0a:
- {
- num=10;
- if (count<number)
- {
- str4[count]='.';
- count++;
- }break;//键"--/-"
- }
- case 0x0b:
- {
- num=11;
- break;//键LG
- }
- case 0x0f:
- {
- num=12; break;//AV键
- }
- case 0x10:
- {
- num=13;
- send_to_pc();break;//静音键
- }
- case 0x15:
- {
- num=14;
- break;//开关键
- }
- case 0x16:
- {
- num=15;break;//选台键
- }
- case 0x17:
- {
- /* num=16; count = 0;//清零
- for (j=0;j<number;j++)
- {
- str4[j]=' ';
- }
- str4[j]='/0';
- PWM=1;
- time_flag=0;
- wr_com(0xcd);
- display(nul);
- target=0;
- enterflag = 0;break;//睡眠键*/
- }
- default:break;
- }
- if (enterflag==1) // 如果按下确认键
- {
- // enterflag = 0; // 标志位置回0
- /* wr_com(0xcd);
- wr_dat(0xdf);
- wr_dat(0x43);
- target=str4[0]*10+str4[1];
- time_flag=1;*/
- }
- /* wr_com(0xc0);
- display(str3);
- wr_com(0xc8);
- display(str4);
- zhb_flag=0;*/
- }
- }
- }
- /*void pitu_wave(void)
- {
- uchar i,a;
- uchar colour=1;
- for(i=0;i<128;i+=2)
- {
- a=64-new_t;
- DrawPoint(i,a,colour);
- }
- }*/
- /********************主程序***********************************/
- void main()
- {
- uchar wave=0;
- uchar i=0,a;
- uchar colour=1;
- RW=0 ;
- lcdreset();
- ceshi();
- clrgdram();
- delay(2000);
- clrscreen();
- EA=1; //初始化
- ET0=1; //开计数中断0
- EX0=1; //开外部中断0
- TMOD=1; //设置工作方式
- IT0=1; //启动计时器
- while(1)
- {
- read_temp1();//读取温度
- read_temp2();//读取温度
- ds1820disp1();//显示
- ds1820disp2();//显示
- wave++;
- if(wave>=10)
- {
- a=64-new_t;
- if(i>=128)
- {
- i=0;
- clrgdram();
- delay(2000);
- clrscreen();
- }
- DrawPoint(i++,a,colour);
- wave=0;
- }
- HW_key();
- }
- }
- void zhb(void) interrupt 0 // 外部中断子程序(译码过程)
- {
- zhb_flag=1;
- TH0=0; //计数器清零
- TL0=0;
- TR0=1; //启动计数器
- while(!js) //等待低电平结束
- {
- delay(5);
- if(TH0>45) //判断低电平是否高于11.52ms如果高于则跳出等待和中断
- return;
- }
- TR0=0;
- if(TH0<30) //判断低电平是否低于7.68ms如果低于跳出中断
- return;
- TH0=0;
- TR0=1;
- while(js) //等待高电平结束
- {
- delay(5);
- if(TH0>28) //判断高电平是否高于7.168ms如果高于则跳出等待和中断
- return;
- }
- //至此为起始信号检测
- TR0=0;
- TH0=0;
- for(i=0;i<4;i++) //一次锁存红外接收的四个十六进制数到a[4]中
- {
- for(j=0;j<8;j++)
- {
- …………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
|