最近大学课程里的单片机实训选了题目为DHT11温湿度检测系统,在本论坛看了很多大佬的资料后,自己简单写了一下能够完成任务的程序,主要使用了STC89C52单片机、LCD1602显示屏以及DHT11模块。模块的详细略过,直接贴代码。 DHT11的DATA为P3^0; DHT11对数据的传输很严格,数据线的优劣影响数据传输的成功跟速度,所以数据DATA线要连接好,不要松动。 本代码搬运于https://blog.csdn.net/qq_40626497/article/details/103615232谢谢博主 这个主要按照DHT11的时序自己调出一个合适的时延就可以了。标准就参照以下 这里主要用蜂鸣器作报警。 这里没有使用闪烁,如果使用闪烁可以知道正在修改哪个值的报警值,读者可以自行加上,这里不作优化。目录
简要
单片机P0为1602的传输端;
RS,RW,EN自便
晶振为11.0592Mhz。
最后1602屏幕的显示应该是
K为开警报,变成G为关警报。
湿度下限为70,上限为95
温度下限为25,上限为95
上行 “Wise:00|D70|U95K”
下行 “Temp:00|D25|U95K”问题:
主函数
#include<intrins.h> //延时函数 #include<string.h> #include"delay.h" #include"DHT11.h" #include"LED1602.h" #include"init_frist.h" #include"keyadd.h" #include"K1_K4.h" #define Uint unsigned int //预定义 #define Uchar unsigned char Uchar buff_wise[]="Wise:00|D00|U00K"; //D=Down 下限 U=up 上限 Uchar buff_temp[]="Temp:00|D00|U00K"; Uchar RH=0,RL=0,TH=0,TL=0; Uchar data_byte; Uint A_OPEN=0,W0,W00=70,W11=99,T00=25,T11=99,d_wh=0,d_th=0,Y=0,t2=0; void CLOCK_DHT11() interrupt 1 //定时器配置函数。 { //static修饰的变量在程序运行的时候分配一次内存,以后不再分配 static int count=0; //重装初值,计数器再次从初值开始算50000次。 TH0 = (65536-5000)/256; //高8位。16位定时器 00000000 00000000 TL0 = (65536-5000)%256; //低8位。 count++; //每10ms加1次。 if(count == 50) //到达50次就是250ms。 { count = 0; A_OPEN = ~A_OPEN; } } void main() //主程序。 { init_frist(); }
DHT11模块代码
#include<DHT11.h> #include<delay.h> //************************************检测模块************************************* void DHT11RstAndCheck() //这为DHT11的复位程序和响应程序。 { DHT11 = 1; delay22us(); //首先拉高一个高电平。 DHT11 = 0; delay(25); // 主机把总线拉低必须大于18ms,保证DHT11能检测到起始信号。 此为22us。 DHT11 = 1; //发送开始信号结束后拉高电平延时20-40us delay22us(); // 22us } Uchar DHT11ReadByte(void) //读一字节数据 { Uchar i,temp; for(i=0;i<8;i++) //接收8bit的数据 { while(!DHT11 ); //等待50us的低电平开始信号结束 delay35us(); //开始信号结束之后延时26us-28us temp=0;//时间为26us-28us表示接收的为数据'0' if(DHT11 ==1) temp=1; //如果26us-28us之后还为高电平则表示接收的数据为'1' while(DHT11);//等待数据信号高电平'0'为26us-28us'1'为70us data_byte<<=1;//接收的数据为高位在前右移 data_byte|=temp; } return data_byte; } //读取一次数据(整数) 0-读取失败 1-读取成功 void DHT11ReadData() { Uchar T_H,T_L,R_H,R_L,check,num_check; DHT11RstAndCheck();//开始信号// DHT11=1; //主机设为输入判断从机DHT11响应信号 if(!DHT11)//判断从机是否有低电平响应信号// { while(!DHT11);//判断从机发出 80us 的低电平响应信号是否结束// while(DHT11);//判断从机发出 80us 的高电平是否结束如结束则主机进入数据接收状态 R_H=DHT11ReadByte();//湿度高位 R_L=DHT11ReadByte();//湿度低位 T_H=DHT11ReadByte();//温度高位 T_L=DHT11ReadByte();//温度低位 check=DHT11ReadByte();//校验位 DHT11=0; //当最后一bit数据接完毕后从机拉低电平50us// delay2(); DHT11=1;//总线由上拉电阻拉高进入空闲状态 num_check=R_H+R_L+T_H+T_L; if(num_check==check)//判断读到的四个数据之和是否与校验位相同 { RH=R_H; //定义湿度高位 RL=R_L; TH=T_H; //定义温度高位 TL=T_L; check=num_check; //判断 } } }
lcd1602显示模块
#include<led1602.h> #include<delay.h> //************************************显示模块************************************* bit test_BF() //检测忙信号 { Uchar LCD_status; P0=0xFF; //全选 EN=0; RS=0; RW=1; EN=1; Delay1(1); LCD_status=P0; EN=0; return (LCD_status&0x80)?1:0; } /* 写命令*/ void write_CMD(Uchar cmd) { while(test_BF()); //检测不忙时。 EN=0; RS=0; RW=0; P0=cmd; //P0口输出数据位 EN=1; _nop_(); EN=0; } /*写数据(一位一位的写)*/ void write_Data(Uchar data8) //1bit,1bit地写字。 { while(test_BF()); EN=0; RS=1; RW=0; P0=data8; EN=1; _nop_(); EN=0; } /*屏幕初始化*/ void init() { write_CMD(0x38);Delay1(1); //置功能 write_CMD(0x01);Delay1(1); //清显示 write_CMD(0x06);Delay1(1); //置输入 write_CMD(0x0C);Delay1(1); //显示开/关控制 } /*写字符串*/ void write_Str(int r, int c, char *str) //整个字符串全写出来 { int i=0; unsigned char Addressx[] = {0x80, 0xC0}; unsigned char StartAdd = (Addressx[r] | c);//按位或 write_CMD(StartAdd); for(i = 0; i < 16; i++){ if(str[i]==0) break; write_Data(str[i]); } // 如果不够16位,用空格填充 for(;i < 16; i++){ write_Data(' '); } }
延时模块,
#include<delay.h> //************************************延时模块************************************* void Delay1(Uint x) //这主要用于LCD1602显示器的延时,不需要太精准。 { Uchar O; while(x--) for(O=0; O<120; O++); } //************************************延时模块************************************* void delay(Uchar ms) //这为使用debug调试的延时,主要用于DHT11传感器的延时,25个ms为22ms。 { Uchar i; while(ms--) for(i=0;i<100;i++); } void delay22us() //这为使用debug调试的延时,主要用于DHT11传感器的延时,显示延时22us。 { Uchar i; for(i=0;i<1;i++){_nop_();_nop_(); } } void delay35us() //这为使用debug调试的延时,主要用于DHT11传感器的延时,显示延时29us。 { Uchar i; for(i=0;i<2;i++){_nop_();_nop_();_nop_();} } void delay2() //这为使用debug调试的延时,主要用于DHT11传感器的延时,显示延时50us。 { Uchar i; for(i=0;i<4;i++)_nop_(); }
启动模块
#include<init_frist.h> void init_frist() //开机全局启动 { init(); //显示屏 //定时器0,工作方式1,16位计数器 TMOD = 0x01; //(D7->D0)-->0000 0001 0000 0010 0x02 //定时10ms,初值65536-10000 TH0 = (65536-5000)/256; //高8位 0-255 50ms TL0 = (65536-5000)%256; //低8位 ET0 = 1; //允许定时器中断 TR0 = 1; //开启定时器,开始计数 EA = 1; //打开全局中断 while(1) { K1_K4(); if(A_OPEN) { DHT11ReadData(); Buzzer_b(d_wh,W00,W11,d_th,T00,T11); d_wh=RH; //湿度 d_th=TH; //温度 buff_wise[5] = d_wh/10+'0'; buff_wise[6] = d_wh%10+'0'; //湿度下限 buff_wise[9] = W00/10+'0'; buff_wise[10] = W00%10+'0'; //湿度上限 buff_wise[13] = W11/10+'0'; buff_wise[14] = W11%10+'0'; buff_temp[5] = d_th/10+'0'; buff_temp[6] = d_th%10+'0'; //温度下限 buff_temp[9] = T00/10+'0'; buff_temp[10] = T00%10+'0'; //温度上限 buff_temp[13] = T11/10+'0'; buff_temp[14] = T11%10+'0'; if(Y==0) //警报开关标志位。 { buff_wise[15] = 'K'; //开警报。 buff_temp[15] = 'K'; } else { buff_wise[15] = 'G'; //关警报。 buff_temp[15] = 'G'; } //显示 write_Str(0,0,buff_wise); write_Str(1,0,buff_temp); } } }
蜂鸣器报警模块
#include<Buzzer.h> //蜂鸣器模块 void Buzzer_b(Uint now_w,Uint w_down,Uint w_up,Uint now_t,Uint t_down,Uint t_up) { Uchar i1; if(Y==0) //如果警报标志位开启,Y=1,警报开启;Y=0,警报关闭。 { if((now_w<w_down)||(now_w>w_up )||(now_t<t_down)||(now_t>t_up )) //如果温度wise湿度temp大于上限值,小于下限值,就会报警。 { for(i1=0;i1<2;i1++) //循环2次蜂鸣器响起。 { BUZZER = 0; //蜂鸣器响起。 delay(50); //作一定时间的延时。 BUZZER = 1; //蜂鸣器不响。 } } } }
选位修改报警值
#include<K1_K4.h> //选位置调节,一共四个位置 |wise_down下限|wise_up上限 void K1_K4() //选位置调节,一共四个位置 |temp_down下限|temp_up上限 { if(KEY4==0) //检测按键4是否被按下。 { Delay1(20); //延时。 if(KEY4==0) //延时后如果按键4还是被按下,则执行程序 { while(!KEY4); t2++; } } switch(t2) { case 0: W00=keyadd(W00); break; //当t2为0时,修改湿度(wise)下限值。 case 1: W11=keyadd(W11); break; //当t2为1时,修改湿度(wise)上限值。 case 2: T00=keyadd(T00); break; //当t2为2时,修改温度(temp)下限值。 case 3: T11=keyadd(T11); break; //当t2为3时,修改温度(temp)上限值。 default: t2=0; //当t2超过3,归零。 } }
修改报警值
#include<keyadd.h> Uchar keyadd(Uchar n) { if(KEY1 == 0) //增加。 { Delay1(20); if(KEY1 == 0) {while(!KEY1); n++; } } if(KEY2 == 0) //减小。 { Delay1(20); if(KEY2 == 0) {while(!KEY2); n--; } } if(KEY3 == 0) //警报开关修改标志位。 { Delay1(20); if(KEY3==0) {while(!KEY3); Y=~Y; //标志位取反。 } } return n; //返回修改值。 }
这是我的第一篇博客,在这里见了很多大佬,也学到点知识,对我的学习生活都有很大帮助,写的东西也是简单粗略,若有不足之处,望看官能够指出。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算