1、基于51单片机的温湿度与时钟显示器 1、 背景知识 随着电子技术的发展和人们生活水平的不断提高。人类对科学技术的不断研究,不断创新纪录。单片机控制无疑是人们追求的目标之一,它所给人带来的方便也是不可否定的,其中温度传感器就是一个典型的例子,但人们对它的要求越来越高,要为现代人工作、科研、生活、提供更好的更方便的设施就需要从数单片机技术入手,一切向着数字化控制,智能化控制方向发展。本设计所介绍的温度传感器与传统的温度计相比,具有读数方便,测温范围广,测温准确,其输出温度采用数字显示,该设计控制器使用单片机STC89C52RC增强型芯片,测温传感器使用DHT11,用LCD1602A实现温度
2、显示,能准确达到以上要求。 2、 课程设计目的 通过基于MCS-51系列单片机STC89C52RC增强型和DHT11温湿度传感器检测温度和湿度,熟悉对DHT11传感器的使用,温度传感器的功能,LCD1602A液晶显示,C语言的设计;并且把我们这两年所学的数字和模拟电子技术、检测技术、以及这个学期学的单片机应用等知识,通过理论联系实际,从题目分析、电路设计调试、程序编制调试到传感器的选定等这一完整的实验过程,培养了学生正确的设计思想,使学生充分发挥主观能动性,去独立解决实际问题,以达到提升学生的综合能力、动手能力、文献资料查阅能力的作用,为毕业设计和以后工作打下一个良好的基础 3、
3、 工具/准备工作 准备工具材料如表1所示: 表1 1 单片机STC89C52RC 1片 2 发光二极管 1只 3 12M晶振 1个 4 电阻、电容 若干 5 排针 若干 6 按钮及开关 若干 7 电烙铁 1个 8 焊锡 若干 9 蜂鸣器 1个 10 LCD1602液晶显示器 1个 11 DHT11温湿度传感器 1个 12 电位器 1个 13 PNP三极管 1个 14 电源线 1条 4、 设计步骤及原理 步骤1:原理图分析与设计 单片机最小系统原理图如图4-1-1所示: 图4-1-1
4、51单片机最小系统包括了主要由电源、复位、振荡电路以及扩展部分等部分组成。对于电源供电模块可以通过USB电源线连接电脑供给,另外也可以用外部稳定的5V电源供电模块供给。对于复位电路,本设计中采用按键复位方法。按键复位就是在复位电容上并联一个开关,当开关按下时电容被放电、RST也被拉到高电平,而且由于电容的充电,会保持一段时间的高电平来使单片机复位。 对于时钟震荡电路,所以外部只要连接一个晶振和两个电容即可,电容容量一般在15pF至50pF之间。而本次设计采用了12MHz的晶体振荡器作为震荡源。 温湿度传感器温湿度数据采集模块如图4-1-2所示,DHT11是一款有已校准数字信号输出的温湿
5、度传感器。 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%R温度0~50℃。DHT11数 图4-1-2 字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数
6、单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。本设计中采用DHT11传感器将采集的温度传送给单片机,然后内部进行BCD码转换,最后通过LCD1602液晶显示器显示出来。 LCD1602液晶显示器模块如图4-1-3所示,602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样。本次设计中将多出来的15脚接上VCC,然后GND(16脚)接到单片机的P24口,然后通过按键K5 图4-
7、1-3 来控制P24口输出电平的状态从而 控制LCD1602液晶显示器的背光的开关。仿真中由于无法仿真背光效果,只能通过LED状态 图4-1-4 确定,如图4-1-4所示。通过网上查阅LCD1602液晶显示器的芯片手册可以知道,将D0-D7八个数据口连接P0,然后通过RS、RW以及使能端E控制LCD的读写操作。 步骤2:流程设计 通过对课本的学习以及课外学习的知识,然后根据自己的构想来设计实现怎么样的效果,通过对软件设计思路的分析,得到该设计的系统主程序流程图如图4-2-1所示: 开始 定时器初始化 显示器初始化 系统初始化 Flag=1
8、
定时器中断
写入框架显示
调用键盘扫描
刷新温度数据
对时分秒位进行运算
调用温湿度函数
图4-2-1
系统开始后,先对定时器以及显示器进行初始化,然后写入框架显示时间和温度。当定时器中断时,内部对秒进行自加,加到60s后自动归零且分自加,其它时间标志位也是一样。当然,每1s满时显示会刷新一次从新显示新的数据,温度函数也是按照指定时间进行测量刷新。
步骤3:软件编程
1. 建立LCD.H文件
#ifndef __LCD_H_
#define __LCD_H_
#include
9、unsigned char #define uint unsigned int #define LCD1602_DATAPINS P0 sbit LCD1602_E=P2^7; sbit LCD1602_RW=P2^5; sbit LCD1602_RS=P2^6; void Lcd1602_Delay1ms(uint c); void LcdWriteCom(uchar com); void LcdWriteData(uchar dat) ; void LcdInit(); #endif 2. 建立LCD.C函数 #include"LCD.h"
10、//包含自建立库文件 void Lcd1602_Delay1ms(uint c) //延时函数 { uchar a,b; for (; c>0; c--) { for (b=199;b>0;b--) { for(a=1;a>0;a--); } } } void LcdWriteCom(uchar com) { LCD1602_E = 0; LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_DATAPINS = com; Lcd160
11、2_Delay1ms(1); LCD1602_E = 1; Lcd1602_Delay1ms(5); LCD1602_E = 0; LCD1602_DATAPINS = com << 4; Lcd1602_Delay1ms(1); LCD1602_E = 1; Lcd1602_Delay1ms(5); LCD1602_E = 0; } void LcdWriteData(uchar dat) { LCD1602_E = 0; LCD1602_RS = 1; LCD1602_RW = 0; LCD
12、1602_DATAPINS = dat; Lcd1602_Delay1ms(1); LCD1602_E = 1; Lcd1602_Delay1ms(5); LCD1602_E = 0; LCD1602_DATAPINS = dat << 4; Lcd1602_Delay1ms(1); LCD1602_E = 1; Lcd1602_Delay1ms(5); LCD1602_E = 0; } void LcdInit() //初始化 { LcdWriteCom(0x32); LcdWriteCo
13、m(0x28);
LcdWriteCom(0x0c);
LcdWriteCom(0x06);
LcdWriteCom(0x01);
LcdWriteCom(0x80);
}
3. 建立DHT11.H库文件
#ifndef __DHT11_H__
#define __DHT11_H__
#include
14、Start(); bit DHT_ByteRead(unsigned char *dat); #endif 4. 建立DHT11.C文件 #include"DHT11.h" void delay_ms(unsigned char x) { unsigned char a; while(x--) for(a=0;a<114;a++); } void delay_30us(void) { unsigned char a; for(a=12;a>0;a--); } void delay_40us(void) {
15、 unsigned char a,b; for(b=3;b>0;b--) for(a=4;a>0;a--); } bit DHT_Start() { unsigned char m=0; DHT_DATA=1; DHT_DATA=0; delay_ms(20); DHT_DATA=1; delay_40us(); if(DHT_DATA==1) return 0; else while((DHT_DATA==0)&&(m<200))m++; delay_40us(); delay_40us(); re
16、turn 1; } bit DHT_ByteRead(unsigned char *dat) { unsigned char temp=0; unsigned char x,y; unsigned char m=0; unsigned char n=0; unsigned char mask=0x01; unsigned char sum=0; for(y=0;y<5;y++) { for(mask=0x80;mask!=0;mask>>=1) { while(DHT_DATA==0&&m<200)m++; delay_3
17、0us();
if(DHT_DATA)
temp|=mask;
else
temp&=(~mask);
while(DHT_DATA==1&&n<200)n++;
}
*(dat+y)=temp;
temp=0;
}
for(x=0;x<4;x++)
sum+=*(dat+x);
if((sum&=0xff)==*(dat+4))
return 1;
else
return 0;
}
5. 建立主函数main.c文件
#include
18、include"DHT11.h" #define uchar unsigned char #define uint unsigned int sbit beep=P1^0;// sbit BG=P2^4;// sbit K1=P1^1;// sbit K2=P1^2;// sbit K3=P1^3;// sbit K4=P1^4;// sbit K5=P1^5;// //sbit beep=P2^0; uchar code table0[]="H:"; uchar code table1[]="T:"; uchar code table2[]="%"; uchar
19、 code table3[]="C"; uchar code table_1[]="2016-06-03"; uchar code table_2[]="16:00:00 5"; uchar DHT[5]; uchar tmp,i,j,k; uchar count,shi,fen,miao,month,day,week,year; uchar K1num,K2num,K3num; bit flag_1s=1; void Delay10ms(unsigned int x); void Keyscan(); void Keyscan2(); void Wtimer(uch
20、ar ad,uchar dat); void main() { LcdInit(); BG = 1; beep; TMOD = 0X01; TH0 = (65536 - 50000)/256; /*11.0592MHz 46080*/ TL0 = (65536 - 50000)%256; EA = 1; ET0 = 1; TR0 = 1; LcdWriteCom(0X86); for (j = 0;j < 10;j++) { LcdWriteData(table_1[j]); } LcdWrit
21、eCom(0Xc6); for (j = 0;j < 10;j++) { LcdWriteData(table_2[j]); } while(1) { Keyscan(); Keyscan2(); if(flag_1s) { flag_1s=0; DHT_Start(); tmp=DHT_ByteRead(&DHT); //****************** LcdWriteCom(0x80); for(i=0;i<2;i++) LcdWriteData(table0[i]
22、); LcdWriteData(DHT[0]/10+'0'); LcdWriteData(DHT[0]%10+'0'); LcdWriteData(table2[0]); //****************** LcdWriteCom(0xC0); for(i=0;i<2;i++) LcdWriteData(table1[i]); LcdWriteData(DHT[2]/10+'0'); LcdWriteData(DHT[2]%10+'0'); LcdWriteData(table3[0]);
23、//LcdWriteCom(0x07); //ÒÆÆÁ } } } void Delay10ms(unsigned int x) { unsigned int t; while(x--) for(t=0;t<114;t++); } void Timer0() interrupt 1 { unsigned char t; TH0=(65536 - 50000)/256; /*11.0592MHz*/ TL0=(65536 - 50000)%256; t++; if(t%40==0) { flag_1s=1; }
24、 count++; if (20 == count) { count = 0; miao++; if (60 == miao) { miao = 0; fen++; if (60 == fen) { fen = 0; shi++; if (24 == shi) { shi = 0; day++; week++; if(week>7) week=1; if
25、 (31 == day) { day = 1; month++; if (12 == month) { month = 1; year++; Wtimer(6-0x40+2,year); } Wtimer(6-0x40+5,month); } Wtimer(6-0x40+8,day); } Wti
26、mer(6,shi); } Wtimer(9,fen); } Wtimer(12,miao); } } void Keyscan() { K1 = 1; K2 = 1; K3 = 1; if (0 == K1) { Delay10ms(5); if (0 == K1) { K1num++; while (!K1); if (1 == K1num) {
27、 TR0 = 0; LcdWriteCom(0XC0+13); LcdWriteCom(0X0F); } if (2 == K1num) { LcdWriteCom(0XC0+10); } if (3 == K1num) { LcdWriteCom(0XC0+7); } if (4 == K1num) { LcdW
28、riteCom(0x89); } if (5 == K1num) { LcdWriteCom(0x8C); } if (6 == K1num) { LcdWriteCom(0x8F); } if (7 == K1num) { TR0 = 1; K1num = 0; LcdWriteCom(0x0c); } } } if (0
29、 != K1num) { if (0 == K2) { Delay10ms(5); while (!K2); if(1 == K1num) { miao++; if(60 == miao) miao = 0; LcdWriteCom(0xc0+12); Wtimer(12,miao); LcdWriteCom(0xc0+13); } if(2 == K1num) { fen++; if(60 ==
30、fen) fen = 0; LcdWriteCom(0xc0+9); Wtimer(9,fen); LcdWriteCom(0xc0+10); } if(3 == K1num) { shi++; if(24 == shi) shi = 0; LcdWriteCom(0xc0+6); Wtimer(6,shi); LcdWriteCom(0xc0+7); } if(4 == K1num) { year++; i
31、f(30 == year) year = 16; LcdWriteCom(0x88); Wtimer(0x08-0x40,year); LcdWriteCom(0x89); } if(5 == K1num) { month++; if(13 == month) month = 1; LcdWriteCom(0x8B); Wtimer(0x0B-0x40,month); LcdWriteCom(0x8C); } if(6 == K1num)
32、 { day++; if(day>31) day = 1; LcdWriteCom(0x8E); Wtimer(0x0E-0x40,day); LcdWriteCom(0x8F); } } } if (0 != K1num) { if (0 == K3) { Delay10ms(5); while (!K3); if(1 == K1num) {
33、 miao--; if(255 == miao) miao = 59; LcdWriteCom(0xc0+10+2); Wtimer(12,miao); LcdWriteCom(0xc0+11+2); } if(2 == K1num) { fen--; if(255 == fen) fen = 59; LcdWriteCom(0xc0+9); Wtimer(9,fen); LcdWriteCom(0xc0+10); } if(3
34、 K1num) { shi--; if(255 == shi) shi = 23; LcdWriteCom(0xc0+6); Wtimer(6,shi); LcdWriteCom(0xc0+7); } if(4 == K1num) { year--; if(255 == year) year = 16; LcdWriteCom(0x88); Wtimer(0x08-0x40,year); LcdWriteCom(0x89); }
35、 if(5 == K1num) { month--; if(255 == month) month = 12; LcdWriteCom(0x8B); Wtimer(0x0B-0x40,month); LcdWriteCom(0x8C); } if(6 == K1num) { day--; if(day<1) day = 31; LcdWriteCom(0x8E); Wtimer(0x0E-0x40,day); LcdWrite
36、Com(0x8F); } } } } void Wtimer(uchar ad,uchar dat) { uchar sw,gw; sw = dat/10; gw = dat%10; LcdWriteCom(0x80+0x40+ad); LcdWriteData(0x30+sw); LcdWriteData(0x30+gw); } void Keyscan2() { K4 = 1; K5 = 1; if(K4
37、 0) { Delay10ms(10); beep=!beep; while (!K4); } //******************** if(K5 == 0) { Delay10ms(10); BG=!BG; while (!K5); } } 5、 设计结果及分析 按照设计进行软件仿真,仿真结果如图5-1: 图5-1 结果分析,由于protues中并没有DHT11这个芯片,因此仿真的时候无法仿真温度,若用其它芯片则要更改函数以及重新学习新的芯片资料,因此并没有进行仿真。按照仿真电路以及
38、程序设计电路焊接电路板如图5-2及5-3所示图5-2 图5-3 实物仿真结果中温度显示是正常的,达到实际效果,而湿度不知道是硬件问题还是环境问题,显示结果有点不如人意,经过多次调试依然如此。而时钟由于没有DS1302实时时钟芯片,无法达到精准计时,经过分析,每24小时误差3s左右。 6、 总结及心得体会 通过一周的时间从无到有完成了温湿度时钟显示的设计,本次设计以DHT11温湿度传感器和LCD1602为实际应用背景,充分让我认识到了51单片机与其它硬件结合应用的强大。也通过网上查阅资料及图书馆查阅有关书籍掌握了DHT11和LCD1602的基本原理和设计方法。 经过这次课程设计,我
39、感觉自己的能力得到了极大地提高。由于LCD1602以及DHT11在课堂上没有介绍过,所以一切都需要自己去学习了解,这给我的课程设计造成了比较大的困难。LCD1602跟数码管或者发光二极管有着很大区别,因为它在使用过程中不仅只需要将数据送入端口,还要不断穿插着命令控制字命令的写入,这使得在编程是不能以编写数码管或者二极管程序的写入方式来写入数据。 我在理解LCD命令和数据信息的写入方式时和DHT11的时序写入读取方法时遇到了较大的困难,由于没有学习任何相关的信息,因此即使在软件仿真时也不知道该怎么做。幸运的是由于在上单片机的课程时买了一个单片机开发版,这对我进行硬件仿真提供了很大的便利,利用
40、面包板和开发版,进行硬件仿真和对商家提供的学习教程进行模块化学习,问题才能一步一步的得到解决。 通过这次课程设计,让我对LCD1602和DHT11温湿度传感器有了一个比较深入的了解,对它的工作原理和工作方式也有了一定的了解,更重要的是在学习LCD1602和DHT11的使用过程中,学会了如何学习一个从未接触过的器件,这种学习能力的提高是这次课程设计中最大的收获,这将对我以后的学习提供极大的帮助,让我知道该如何去学习。 7、 对本设计过程及方法、手段的改进建议 由于本人对线路设计及布线在之前有过接触,因此焊接起来比较简单,但是由于线路较多,有时候焊接起来有些难度。为了更好的学习硬件电路设
41、计,本人打算学习如何使用AD软件去设计PCB板以及去制作它。另一方面是protues软件方面有很多的元器件不知道是怎么命名的,而自己对英语的学习过于肤浅,因此作为大学生应该加强对英语的学习。相信通过系列的学习,自己的能力会有更大的进步,也为日后的工作提供了有利的基础。 8、 参考文献 [1] 林立,张俊亮。 单片机原理及应用——基于Proteus和Keil C[Z]。 北京: 电子工业出版社,2009。 [2] 彭伟。 单片机C语言程序设计实训100例:基于8051+Proteus仿真(第二版)。 北京: 电子工业出版社,2009。 9、 评价(教师) 报告评分: 指导教师签字: 22
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4009-655-100 投诉/维权电话:18658249818