基于52单片机温湿度传感器课程设计报告含代码Word文档格式.docx
《基于52单片机温湿度传感器课程设计报告含代码Word文档格式.docx》由会员分享,可在线阅读,更多相关《基于52单片机温湿度传感器课程设计报告含代码Word文档格式.docx(63页珍藏版)》请在冰豆网上搜索。
备份电源。
当Vcc2>
Vcc1+0.2V时,由Vcc2
向DS1302供电,当Vcc2<
Vcc1时,由Vcc1向DS1302供电。
SCLK:
串行时钟,输入,控制数据的输入与输出;
I/O:
三线接口时的双向数据线;
RST为复位引脚,在读、写数据期间,必须为高,
X1X2为32867Hz晶振管脚,为芯片提供时钟脉冲。
3.报警电路
各I/O口在上电时为高电平,LED灯和蜂鸣器处于熄灭和不响状态。
其中LED灯通过一个1K的电阻限流,防止点亮时电流过大被烧坏。
蜂鸣器要用NPN型三极管驱动,当P2.5口输出高电平时,Q1饱和导通,蜂鸣器获得工作电流发出响声。
4.键盘扫描电路
这里用了5个按键。
其中按键1是调时按键,根据按的次数依次进入年、月、日、时、分、秒、星期调整,再按一次那么退出。
按键2和3分别是加操作和减操作。
按键4是设置温湿度上下限值及报警开关;
按键5是关报警。
5.12864LCD显示电路
ST7920系列12864是带中文字库的液晶显示器,它可以显示4行,每行16个字节,各行的地址依次为0x80~0x87、0x90~0x97、0x88~0x8F
0x98~0x9F。
注:
RB0~RB7〔为数据口〕依次接P1各口,变阻器R2下端接地。
5.1接口说明:
VSS为电源地;
VDD为电源正端;
V0为LCD驱动电压输入端;
RS:
并行的指令/数据选择信号,串行的片选信号;
RW:
并行的读写选择信号,串行的数据口;
E:
并行的使能信号,串行的同步时钟;
PSB:
并/串行接口选择,高电平时为并行;
NC:
空脚;
RST:
复位信号,低电平有效;
BLA:
背光源正极;
BLK:
背光源负极。
5.2、12864读写时序图如下:
读写操作时序
数据与命令时序
5.3、根本操作时序
〔1〕读状态:
输入:
RS=L,RW=H,E=H输出:
D0~D7=状态字
〔2〕写指令:
RS=L,RW=L,D0~D7=指令码,E=高脉冲输出:
无
〔3〕读数据:
RS=H,RW=H,E=H输出:
D0~D7=数据
〔4〕写数据:
RS=H,RW=L,D0~D7=数据,E=高脉冲输出:
5.4、初始化过程〔复位过程〕指令:
〔1〕延时15毫秒
〔2〕写指令38H;
显示模式设置
〔3〕写指令08H;
显示关闭
〔4〕写指令01H;
显示清屏
〔5〕写指令06H;
显示光标移动设置
〔6〕写指令0CH;
显示开及光标设置
6.与PC机通信模块
从上述电路可知,单片机要与计算机通信,必须通过MAX232〔或其他〕芯片。
这是因为计算机串口上的电平执行的是RS-232标准,它定义的上下电平和单片机的TTL逻辑电平不兼容。
而MAX232芯片加上几个电解电容,能完成电压的加倍和反相,实现TTL电平和RS-232电平的转换。
单片机的串行口TXD与MAX232的一组电平转换器的TTL输入端〔管脚12〕相连,经过MAX232转换后,RS-232标准输出端〔管脚14〕输出的信号进入计算机串口的RXD。
同样计算机串口的TXD与MAX232的RS-232标准输入端〔管脚13〕相连,经过电平转换后,由TTL输出端〔管脚11〕输出到单片机的RXD上。
7.AM2301温湿度检测电路
上图中DHT11和AM2301是一个系列的,他们的引脚和功能一样。
7.1AM2301温湿度传感器简介
DHT11的供电电压为3-5.5V。
传感器上电后,要等待1s以越过不稳定状态在此期间无需发送任何指令。
电源引脚〔VDD,GND〕之间可增加一个100nF的电容,用以去耦滤波。
DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数局部和整数局部,具体格式在下面说明,当前小数局部用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输40bit,高位先出。
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和用户MCU发送一次开场信号后,DHT11从低功耗模式转换到高速模式,等待主机开场信号完毕后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取局部数据.从模式下,DHT11接收到开场信号触发一次温湿度采集,如果没有接收到主机发送开场信号,DHT11不会主动进展温湿度采集.采集数据后转换到低速模式。
1、总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。
DHT11接收到主机的开场信号后,等待主机开场信号完毕,然后发送80us低电平响应信号.主机发送开场信号完毕后,延时等待20-40us后,读取DHT11的响应信号,主机发送开场信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。
2、总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开场,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,那么DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
四、各模块流程图
1、温度模块控制流程图:
2、湿度模块控制流程图
3、显示模块控制流程图
4、报警模块流程图
5、温湿度报警设置流程图
6、万年历设置流程图
7、与PC通信模块流程图
五、设计过程问题解决
本次设计过程很费周折,由于proteus里面缺少一些必要的元件如20引脚12864液晶显示模块和AM2301温湿传感器,故实验过程中是先设计好硬件电路,焊好电路以后才进展调试的,其间的困难可想而知。
也因为这样,硬件电路的错误比拟多,中间一直在修改硬件电路,造成电路板修修补补不美观。
实验过程中遇到的困难很多,尤其是实现界面切换和返回主界面的过程,要保持时钟仍在运行,同时光标也要随着界面一起移动。
否那么就会显示出错。
此外开关报警的设置如何能够保持,这就要做到返回主界面以后要保存设置量,当报警时按下了关报警,要刷新设置界面。
而在本次设计过程中,我们调用了两次显示,一次写显示格式,一次刷新,只要有更改就刷新,对于那些不变的汉字我们不刷新,这样也使得显示得到简化。
此外,由于使用到单片机与计算机通信知识,通过查阅相关书籍,用VB编写了一个上位机显示界面,将12864上显示的温湿度数值通过串口控件显示。
下面将分步骤将实现过程中的问题和解决方案作说明:
1.刚开场烧了程序以后,发现LCD什么都不显示,后来发现是因为没有开背光,因为没开背光显示不明显,如果角度不对会发现什么都没显示。
而背光要通过可调电阻来调,在12864的BLA背光正极接一个可调电阻,电阻的两端是接地和电源〔之间还有一个拨码开关〕。
当翻开开关时,背光关掉,可以省电;
合上开关,调节电阻可以使12864显示亮度变化。
2.能够显示以后,发现显示界面一直在刷新,显示不稳定。
原因是每秒随着秒刷新初始化界面一次,解决的方案是不重新调用显示,而是只给显示秒的位置刷新,其他时间随秒变化。
温湿度值那么是有了变化就刷新。
3.由于编写程序时,没有考虑到串口通信中传回PC的数据的十六进制与显示字符之间的数据处理关系,导致在串口助手软件中只显示了传回的最后一个十六进制数所对应的ASCⅡ的字符,找到问题的解决关键所在后,经过数的分位与字符显示后,成功的显示了传回的温度、湿度的数据,让我们距离成功只差一小步了。
接下来的任务就是显示在12864液晶上,根据之前单独在其上显示过液晶万年历的根底,知道只要将dht11检测的数据进展相应处理后并且与液晶万年历的显示集成一起送显示就行了。
理论虽简单,但实际在下载到芯片中检测现象时,我们发现分别单独显示两者的数据没有问题,但集成在一块显示不久就会花屏的现象,问题出在刷新汉字时,指针光标的位置修改错误所导致的。
之后经过重新写回指针后就到达了较为满意的效果。
在报警程序的设置上,主要解决蜂鸣器报警间隔和LED灯闪烁的时间匹配问题,让两者现象统一。
4.单片机与计算机通信。
上位机界面设计,利用VB编程,用MSComm控件能够实现单片机传送数据到计算机并显示。
PrivateSubMSComm1_OnComm()
DimrecAsString;
定义接收字符串
SelectCaseMSComm1.CommEvent;
串口事件选择
CasecomeEvReceive;
串口事件为接收
rec=MSComm1.Input;
从接收缓冲区中读取数据
Text1.Text=rec;
将接收到的字符串写入文本框
MSComm1.InBufferCount=0;
设置接收缓冲区中等待计算机承受的字符数为0
EndSelect
EndSub
PrivateSubform_load()
MSComm1.Settings="
9600,N,8,1"
;
波特率,奇偶校验,发送位数,停顿位
MSComm1.CommPort=5;
串口号
IfMSComm1.PortOpen=TrueThenMSComm1.PortOpen=False
MSComm1.RThreshold=8;
接收缓冲区字符为8时,串口控件设置串口事件为接收,并产生OnComm事件
MSComm1.SThreshold=2;
发送缓冲区中字符小于2时,串口控件设置串口事件为发送,并产生OnComm事件
MSComm1.InputLen=0;
返回一次从接收缓冲区读取所有字节
MSComm1.InputMode=comInputModeText;
接收模式为文本
IfMSComm1.PortOpen=FalseThenMSComm1.PortOpen=True
MSComm1.InBufferCount=0
Me.Caption="
温湿度显示"
EndSub
PrivateSubForm_Resize();
窗体背景图片设置
Image1.Top=0
Image1.Left=0
Image1.Stretch=True
Image1.Height=Me.ScaleHeight
Image1.Width=Me.ScaleWidth
PrivateSubmnuQuit_Click()
End
六、设计总结
本次设计是小组三人共同努力的成果,大家齐心协力克制了上述种种困难,才把实物做出来。
通过这次设计,我们学习到了如何把传感器联系单片机知识做成一个简单的检测系统,如何完成简单的通信任务,如何编写高效率的C代码。
当然我们的缺乏也有很多,比方硬件设计电路考虑不全面,造成后来不得不修改一些连线和元件使得电路板不够美观;
还有程序不够模块化,有不少冗余,移植性和兼容性也不好,今后要更加注重这些方面的改良。
附录代码:
/*****基于单片机的温湿度检测系统******/
#include<
reg52.h>
#defineucharunsignedchar
#defineuintunsignedint
/***端口定义***/
sbitLCD_RS=P3^5;
//存放器选择输入
sbitLCD_RW=P3^6;
//液晶读/写控制
sbitLCD_EN=P3^4;
//液晶使能控制
sbitLCD_PSB=P3^7;
//串/并方式控制
sbits5=P0^3;
//关报警
sbits4=P0^4;
//设置温湿度报警值及开关报警
sbits3=P0^5;
//调时开/关
sbits2=P0^6;
//加操作
sbits1=P0^7;
//减操作
sbitled1=P2^0;
//温度报警
sbitled2=P2^1;
//湿度报警
sbitbuzzer=P2^5;
//蜂鸣器
sbitAM2301=P2^6;
//P2.6口为通讯口连接DHT11
typedefunsignedcharU8;
typedefunsignedintU16;
charsec,min,hour,week,day=1,month=1,year;
bitflag,flag2,flag3=0,flag4=0,flag5=0,flag6=0;
uchara;
uchars1num,s4num;
ucharcodedis1[]={"
2021年12月02日"
};
ucharcodedis2[]={"
00时00分00秒"
ucharcodedis3[]={"
温度:
25.0日"
ucharcodedis4[]={"
湿度:
40.0"
ucharcodedis5[]={"
温度上限:
"
//温湿度设置界面
ucharcodedis6[]={"
温度下限:
ucharcodedis7[]={"
湿度上限:
ucharcodedis8[]={"
湿度下限:
ucharcodedisx[]={0xc8,0xd5,0xd2,0xbb,0xb6,0xfe,0xc8,0xfd,0xcb,0xc4,0xce,0xe5,0xc1,0xf9};
//"
日"
"
一"
二"
三"
四"
五"
六"
(两个字节为一个汉字)
//----------------定义区--------------------//
U8Temp,RH1;
U8U8FLAG;
U8U8count,U8temp;
U8datatab[8]={0x00,0x00,0x2e,0x00,0x00,0x00,0x2e,0x00};
//存储温湿度数据
U8U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
//温湿度的上下位及校验位
U8U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
U8temp_H=30,temp_L=0,RH_H=50,RH_L=10;
U8U8comdata;
U8outdata[8];
//定义发送的字节数
U8str[8]={“〞};
U8count;
U16U16temp1,U16temp2;
/***延时1ms子函数***/
voiddelay(uintz)
{
uintx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
}
/***延时子函数***/
voidDelay2(U16j)
{
U8i;
for(;
j>
j--)
for(i=0;
i<
27;
i++);
/***延时10us子函数***/
voidDelay_10us(void)
i--;
/***发送字符串子函数***/
voidSendData(U8*a)
outdata[0]=a[0];
outdata[1]=a[1];
outdata[2]=a[2];
outdata[3]=a[3];
outdata[4]=a[4];
outdata[5]=a[5];
outdata[6]=a[6];
outdata[7]=a[7];
count=0;
SBUF=outdata[0];
/***写指令子函数***/
/*RS=0,RW=0,E=0,D0-D7=指令码*/
voidwrite_com(ucharcom)
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
P1=com;
delay(5);
LCD_EN=1;
LCD_EN=0;
/***写数据子函数***/
/*RS=1,RW=0,E=0,D0-D7=数据*/
voidwrite_dat(uchardat)
LCD_RS=1;
LCD_RW=0;
P1=dat;
/***设定显示位置***/
voidlcd_pos(ucharX,ucharY)
ucharpos;
if(X==0)X=0x80;
elseif(X==1)X=0x90;
elseif(X==2)X=0x88;
elseif(X==3)X=0x98;
pos=X+Y;
write_com(pos);
/***LCD初始化设定***/
voidinit()
LCD_PSB=1;
//并口方式
write_com(0x30);
//根本指令操作
write_com(0x0c);
//显示开,关光标
write_com(0x01);
//去除LCD的显示内容
TMOD=0x21;
TH0=0x4c;
TL0=0x00;
ET0=1;
EA=1;
TR0=1;
TH1=253;
//初始化串口
TL1=253;
TR1=1;
SCON=0x50;
ES=1;
TI=0;
RI=0;
SendData(str);
Delay2
(1);
/***写年月日子函数***/
voidwrite_ymd(ucharadd,uchardat)
ucharshi,ge;
shi=dat/10;
ge=dat%10;
write_com(0x80+add);
write_dat(0x30+shi);
write_dat(0x30+ge);
/***写时分秒子函数***/
voidwrite_hms(ucharadd,uchardat)
ge=dat%10;
write_com(0x90+add);
/******温湿度上下限设置更新***********/
voidwrite_lim1(ucharadd,uchardat)
voidwrite_lim2(ucharadd,uchardat)
voidwrite_lim3(ucharadd,uchardat)
write_com(0x88+add);
voidwrite_lim4(ucharadd,uchardat)
write_com(0x98+add);
/*温度显示子函数*/
voidwrite_tem(ucharadd)
write_dat(tab[4]);
write_dat(tab[5]);
write_dat(tab[6]);
write_dat(tab[7]);
/*湿度显示子函数*/
voidwrite_hum(ucharadd)
write_dat(tab[0]);
write_dat(tab[1]);
write_dat(tab[2]);
write_dat(tab[3]);
voidCOM(void)
8;
i++)
{
U8FLAG=2;
while((!
AM2301)&
&
U8FLAG++);
Delay_10us();
U8temp=0;
if(AM2301)U8temp=1;
wh