环境温湿度监控系统(51+DHT11+1602液晶)
一.原理图
二.1602显示模块
模块头文件:引脚定义,接口定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #ifndef _1602_H_ #define _1602_H_
#include <reg51.h> #include <intrins.h> #define LCD_Bus P2 sbit RS = P0^7; sbit RW = P0^6; sbit EN = P0^5;
sbit busy_led1 = P1^0;
extern void Lcd_Init(void); extern void Lcd_WriteData(unsigned char Data); extern void Lcd_WriteCmd(unsigned char Cmd); extern void Lcd_WriteStr(unsigned char *Str);
#endif
|
函数实现见GIT仓库
或参考SMC1602 Datasheet
编写。
三.DHT11模块
模块头文件:引脚定义,接口定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #ifndef _DHT11_H_ #define _DHT11_H_
#include <reg51.h> #include <intrins.h>
sbit DHT11_Data = P0^4;
sbit NOresponse_led2 = P1^1; sbit start_led3 = P1^2; sbit ERRORREVISE_LED4 = P1^3; sbit test_led5 = P1^4; sbit ASK_LED6 = P1^5; sbit rec_byte_led7 = P1^6; sbit rec_40_led8 = P1^7;
extern unsigned char rec_dat[16]; extern unsigned char RH,TH;
extern void DHT11_delay_ms(unsigned int ms); extern void DHT11_rec_40(void); #endif
|
函数实现见GIT仓库
或参考DHT11 Datasheet
编写。
四.功能模块
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
| #include <reg51.h> #include <intrins.h> #include "1602.h" #include "DHT11.h" #define uchar unsigned char #define uint unsigned int
sbit ok_SW1 = P3^5; sbit add_SW2 = P3^4; sbit sub_SW3 = P3^3; sbit sw_SW4 = P3^2;
sbit bell = P3^6;
uchar HTemp,LTemp,HRH,LRH,set;
unsigned char Key_Scan(); void Init_Alarm_Timer0();
int main () { uchar i; DHT11_delay_ms(1500); DHT11_rec_40(); Lcd_Init(); HTemp=35,LTemp=15;HRH=80,LRH=20;set=2; Init_Alarm_Timer0(); while(1) { switch(set) { case 1: Lcd_WriteCmd(0x80); Lcd_WriteStr("Press S1 to set "); Lcd_WriteCmd(0x80 + 0x40); for(i=0;i<16;i++){Lcd_WriteData(rec_dat[i]);} if(Key_Scan() == 1) {set = 2;} DHT11_delay_ms(2500); DHT11_rec_40(); break; case 2: Lcd_WriteCmd(0x80); Lcd_WriteStr("Set the max RH "); Lcd_WriteCmd(0x80 + 0x40); Lcd_WriteStr("Maximum RH: "); Lcd_WriteData('0'+(HRH/10)); Lcd_WriteData('0'+(HRH%10)); Lcd_WriteStr("% "); switch(Key_Scan()) { case 1: set = 3; break; case 2: HRH+=1; break; case 3: HRH-=1; break; } break; case 3: Lcd_WriteCmd(0x80); Lcd_WriteStr("Set the min RH "); Lcd_WriteCmd(0x80 + 0x40); Lcd_WriteStr("Minimum RH: "); Lcd_WriteData('0'+(LRH/10)); Lcd_WriteData('0'+(LRH%10)); Lcd_WriteStr("% "); switch(Key_Scan()) { case 1: set = 4; break; case 2: LRH+=1; break; case 3: LRH-=1; break; } break; case 4: Lcd_WriteCmd(0x80); Lcd_WriteStr("Set the max Temp "); Lcd_WriteCmd(0x80 + 0x40); Lcd_WriteStr("Max Temp: "); Lcd_WriteData('0'+(HTemp/10)); Lcd_WriteData('0'+(HTemp%10)); Lcd_WriteData('0'+175); Lcd_WriteStr("C "); switch(Key_Scan()) { case 1: set = 5; break; case 2: HTemp+=1; break; case 3: HTemp-=1; break; } break; case 5: Lcd_WriteCmd(0x80); Lcd_WriteStr("Set the min Temp "); Lcd_WriteCmd(0x80 + 0x40); Lcd_WriteStr("Min Temp: "); Lcd_WriteData('0'+(LTemp/10)); Lcd_WriteData('0'+(LTemp%10)); Lcd_WriteData('0'+175); Lcd_WriteStr("C "); switch(Key_Scan()) { case 1: set = 1; break; case 2: LTemp+=1; break; case 3: LTemp-=1; break; } break; case 6: Lcd_WriteCmd(0x80); Lcd_WriteStr("Over Temp alarm "); bell = ~bell; if(Key_Scan()) { set = 4; } break; case 7: Lcd_WriteCmd(0x80); Lcd_WriteStr("Over RH alarm "); bell = ~bell; if(Key_Scan()) { set = 2; } break; default : Lcd_WriteCmd(0x80); Lcd_WriteStr("ERROR 101 "); Lcd_WriteCmd(0x80 + 0x40); Lcd_WriteStr("UNKNOW SET VALUE"); if(Key_Scan()) { set = 1; } break; } } return 0; }
void Init_Alarm_Timer0(void) { TMOD |= 0x01; TH0 = (65535-46082) / 256; TL0 = (65535-46082) % 256; EA=1; ET0=1; TR0 = 1; }
void Timer0_Alarm(void) interrupt 1 { TH0 = (65535-46082) / 256; TL0 = (65535-46082) % 256; if(set == 1) { if(TH<LTemp||TH>HTemp) { set = 6; }else if(RH<LRH||RH>HRH) { set = 7; } } }
unsigned char Key_Scan() { unsigned char keyValue = 0 , i; if (ok_SW1 != 1) { DHT11_delay_ms(10); if (ok_SW1 != 1) { keyValue = 1; i = 0; while ((i<50) && (ok_SW1 != 1)) { DHT11_delay_ms(10); i++; } } } if (add_SW2 != 1) { DHT11_delay_ms(10); if (add_SW2!= 1) { keyValue = 2; i = 0; while ((i<50) && (add_SW2 != 1)) { DHT11_delay_ms(10); i++; } } } if (sub_SW3 != 1) { DHT11_delay_ms(10); if (sub_SW3 != 1) { keyValue = 3; i = 0; while ((i<50) && (sub_SW3 != 1)) { DHT11_delay_ms(10); i++; } } } if (sw_SW4 != 1) { DHT11_delay_ms(10); if (sw_SW4!= 1) { keyValue = 4; i = 0; while ((i<50) && (sw_SW4 != 1)) { DHT11_delay_ms(10); i++; } } } return keyValue; }
|
Tips:
nop指令的作用:
1)就是通过nop指令的填充(nop指令一个字节),使指令按字对齐,从而减少取指令时的内存访问次数。(一般用来内存地址偶数对齐,比如有一条指令,占3字节,这时候使用nop指令,cpu 就可以从第四个字节处读取指令了。)
2)通过nop指令产生一定的延迟,但是对于快速的CPU来说效果不明显,可以使用rep前缀,多延迟几个时钟。
3)i/o传输时,也会用一下 nop,等待缓冲区清空,总线恢复;
4)清除由上一个算术逻辑指令设置的flag位;
该函数是在51单片机中用的延时函数,表示执行一条没有什么意义的指令,延时一个指令周期,有的指令周期是两个或两个以上的机械周期,但是_nop_();指令需要的只是一个机械周期也就是12个时钟周期(震荡周期)。
51单片机中,1个机械周期 = 12个时钟周期 = 12 * ( 1 / f)。(f 为晶振频率)。
如果只用的是12MHZ的晶振,那么 一个机械周期就是1us;也就是说:
nop(); 指令的延迟时间为 1us。可以较为精确得控制延迟时间。