51單片機(STC89C52RC)讀取DHT11模塊溫度濕度信號采集顯示數碼管
上上周末媳婦問我,家里溫度多少,。。。我TM哪知道,租這么個鬼地方,啥也沒有,我能猜的出來嗎,當然“TM的”的是我現在現在加的。。。^_^,然后就想之前也買了一個樹莓派4B也買了一個面包板,再回憶一下大學時曾經所學的知識,算求了,想做個這么個玩意兒,然后,就。。。。。網上一搜,20多塊錢就能買一個。。。。但是作為一個程序員,就是這么喜歡折騰。。。也想多贊點兒私房錢。。然后就多要了點兒經費。。O(∩_∩)O哈哈~
我只是一個單純的軟件開發工程師。。對於硬件僅僅局限於大學那點兒知識而且畢業四五年了,早忘的差不多了,都是靠百度和各位大神的分享來去驅動。。。
1.成品展示
左側溫度,右側濕度 成品和仿真電路有區別,做着過程中發生了變化,就沒有再去仿真了,就增加了倆個報警指示燈
下圖:左側27℃ 右側42%RH
2.問老婆申請經費(O(∩_∩)O)
3.下單,購買器件
(這里真是沒想到,買個成品可能20塊錢,但是你要做一個,各東西都得買。。前前后后下單了3次,這里只貼一張圖吧。。,還買倆個萬用表、電烙鐵。。。。各種器件。。。線材啥的。。。。。反正很多,反正是要干賠了,還倒貼了不少私房錢。。)
4.繪制電路圖仿真Proteus8.6版本
(基本百度就完了,各種各樣的都有,這個比較簡單)左側溫度,右側濕度
1.DHT11模塊的電路使用 (詳細文檔到這里一下載)
DHT11模塊的時序圖
2.電路設計
Proteus電路仿真和C語言程序源代碼下載
程序
#include<reg51.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int sbit Data=P3^6; //定義數據線 uchar rec_dat[9]; //用於顯示的接收數據數組 //數碼管數字 0--9 uint led[10]={0xc0,0xf9,0xa4, 0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; void delay(uint n) { uint x,y; for(x=n;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com) { //rs=0時輸入指令 P2=com; delay(5); } void DHT11_delay_us(uchar n) { while(--n); } void DHT11_delay_ms(uint z) { uint i,j; for(i=z;i>0;i--) for(j=110;j>0;j--); } void DHT11_start() { Data=1; DHT11_delay_us(2); Data=0; DHT11_delay_ms(30); //延時18ms以上 Data=1; DHT11_delay_us(30); } uchar DHT11_rec_byte() //接收一個字節 { uchar i,dat=0; for(i=0;i<8;i++) //從高到低依次接收8位數據 { while(!Data); ////等待50us低電平過去 DHT11_delay_us(8); //延時60us,如果還為高則數據為1,否則為0 dat<<=1; //移位使正確接收8位數據,數據為0時直接移位 if(Data==1) //數據為1時,使dat加1來接收數據1 dat+=1; while(Data); //等待數據線拉低 } return dat; } //延時程序 單位ms void delay222(unsigned int x) { unsigned int i,j; for(i=x;i>0;i--) for(j=110;j>0;j--); } //設置溫度值 void SetTemperature(uchar value) { //取出個位、十位數字 int unitPlace = value/1%10; int tenPlace = value/10%10; P0 = led[tenPlace]; P2 = 0x80; delay222(3); P2 = 0x00; P0 = led[unitPlace]; P2 = 0x40; delay222(3); P2 = 0x00; } //設置濕度值 void SetHumidity(uchar value) { //取出個位、十位數字 int unitPlace = value/1%10; int tenPlace = value/10%10; P0 = led[tenPlace]; P2 = 0x20; delay222(3); P2 = 0x00; P0 = led[unitPlace]; P2 = 0x10; delay222(3); P2 = 0x00; } void DHT11_receive() //接收40位的數據 { uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; int number; //閃爍頻率 int count2; uchar tempValue; uchar humidityValue; number = 20; count2 = 0; DHT11_start(); count2 = 0; if(Data==0) { while(Data==0); //等待拉高 DHT11_delay_us(40); //拉高后延時80us R_H=DHT11_rec_byte(); //接收濕度高八位 R_L=DHT11_rec_byte(); //接收濕度低八位 T_H=DHT11_rec_byte(); //接收溫度高八位 T_L=DHT11_rec_byte(); //接收溫度低八位 revise=DHT11_rec_byte(); //接收校正位 DHT11_delay_us(25); //結束 if((R_H+R_L+T_H+T_L)==revise) //校正 { RH=R_H; RL=R_L; TH=T_H; TL=T_L; } /*數據處理,方便顯示*/ // rec_dat[0]='0'+(RH/10); // rec_dat[1]='0'+(RH%10); // rec_dat[2]='R'; // rec_dat[3]='H'; // rec_dat[4]=' '; // rec_dat[5]=' '; // rec_dat[6]='0'+(TH/10); // rec_dat[7]='0'+(TH%10); // rec_dat[8]='C'; //讀取溫度濕度 tempValue = RH; humidityValue = TH; while(count2 < number) { //設置溫度 SetTemperature(tempValue); //設置濕度 SetHumidity(humidityValue); count2++; } count2=0; } } /*這里使用lcd1602來顯示采集到的數據,lcd1602驅動程序在博主的51單片機系列博文中有詳細講解*/ void main() { uchar i; while(1) { DHT11_receive(); } }
5.面包板調試電路和程序
買了倆個紅色的2位共陽極數碼管10腳的,結果沒有接限流電阻,燒壞了一個,被迫又一次下單購買,結果購買錯了,買了倆個綠色的共陰極18腳的,太惡心了,焊接過得人估計能體會
6.器件部署和電路板焊接
焊接的過程中,發現還可以增加個報警指示燈。於是又焊接了倆個報警指示燈連接到了P1.0(溫度)和P1.1(濕度)
因為不會繪制pcb布線,就大概擺了一下,然后就開始焊接了。。。
實不相瞞,太惡心了,就因為買錯了,買了個共陰極18腳的2位數碼管。。就焊接成這樣了,水平有限大神直接飄過吧。。。。
7.成品展示
左側是溫度,右側是濕度顯示,然后因為數碼管換了,所以程序也改了,並且新增了個報警指示燈
因為仿真電路和我的實際成品有區別成品中的程序

1 //****************************************************************// 2 //大男孩溫濕度信號采集 3 //單片機 STC89C52RC 4 //功能 數碼管顯示溫度和濕度 備注:晶振 11.0592M 波特率 9600 5 //硬件 P3.6口為通訊口連接DHT11,DHT11的電源和地連接單片機的電源和地 6 //****************************************************************// 7 8 #include <reg51.h> 9 #include <intrins.h> 10 11 12 //數據類型定義 13 typedef unsigned char U8; /* defined for unsigned 8-bits integer variable 無符號8位整型變量 */ 14 typedef signed char S8; /* defined for signed 8-bits integer variable 有符號8位整型變量 */ 15 typedef unsigned int U16; /* defined for unsigned 16-bits integer variable 無符號16位整型變量 */ 16 typedef signed int S16; /* defined for signed 16-bits integer variable 有符號16位整型變量 */ 17 typedef unsigned long U32; /* defined for unsigned 32-bits integer variable 無符號32位整型變量 */ 18 typedef signed long S32; /* defined for signed 32-bits integer variable 有符號32位整型變量 */ 19 typedef float F32; /* single precision floating point variable (32bits) 單精度浮點數(32位長度) */ 20 typedef double F64; /* double precision floating point variable (64bits) 雙精度浮點數(64位長度) */ 21 22 23 //----------------------------------------------// 24 //----------------IO口定義區--------------------// 25 //----------------------------------------------// 26 sbit P3_6 = P3^6 ; //DHT11數據針腳 27 sbit P1_0 = P1^0; //溫度報警針腳 28 sbit P1_1 = P1^1; //濕度報警針腳 29 30 //----------------------------------------------// 31 //----------------數碼管數字 0--9---------------// 32 //----------------------------------------------// 33 34 //uint led[10]={0xc0,0xf9,0xa4, 0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; 35 U8 led[10]={0x3F,0x06,0x5b, 0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; 36 37 //----------------------------------------------// 38 //----------------數據存儲和數據緩存區----------// 39 //----------------------------------------------// 40 U8 U8FLAG; 41 U8 U8temp; 42 U8 U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata; 43 U8 U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp; 44 U8 U8comdata; 45 46 //----------------------------------------------// 47 //----------------延時程序----------------------// 48 //----------------------------------------------// 49 50 //延時程序 51 void Delay(U16 j) 52 { 53 U8 i; 54 for(;j>0;j--) 55 { 56 for(i=0;i<27;i++); 57 58 } 59 } 60 61 //延時程序10us 62 void Delay_10us(void) 63 { 64 U8 i; 65 i--; 66 i--; 67 i--; 68 i--; 69 i--; 70 i--; 71 } 72 73 //延時程序 單位ms 74 void Delayms(unsigned int x1) 75 { 76 unsigned int i1,j1; 77 78 for(i1=x1;i1>0;i1--) 79 for(j1=110;j1>0;j1--); 80 } 81 82 83 84 //-------------------------------- 85 //-----濕度讀取子程序 ------------ 86 //-------------------------------- 87 //----以下變量均為全局變量-------- 88 //----溫度高8位== U8T_data_H------ 89 //----溫度低8位== U8T_data_L------ 90 //----濕度高8位== U8RH_data_H----- 91 //----濕度低8位== U8RH_data_L----- 92 //----校驗 8位 == U8checkdata----- 93 //----調用相關子程序如下---------- 94 //---- Delay();, Delay_10us();,COM(); 95 //-------------------------------- 96 97 98 void COM(void) 99 { 100 101 U8 i; 102 103 for(i=0;i<8;i++) 104 { 105 106 U8FLAG=2; 107 while((!P3_6)&&U8FLAG++); 108 109 Delay_10us(); 110 Delay_10us(); 111 Delay_10us(); 112 113 U8temp=0; 114 115 if(P3_6)U8temp=1; 116 U8FLAG=2; 117 118 while((P3_6)&&U8FLAG++); 119 120 //超時則跳出for循環 121 if(U8FLAG==1) 122 break; 123 124 //判斷數據位是0還是1 125 // 如果高電平高過預定0高電平值則數據位為 1 126 127 U8comdata<<=1; 128 U8comdata|=U8temp; //0 129 }//rof 130 131 } 132 133 134 //總線數據讀取 135 void RH(void) 136 { 137 //主機拉低18ms 138 P3_6=0; 139 Delay(180); 140 141 //總線由上拉電阻拉高 主機延時20us 142 P3_6=1; 143 Delay_10us(); 144 Delay_10us(); 145 Delay_10us(); 146 Delay_10us(); 147 148 //主機設為輸入 判斷從機響應信號 149 P3_6=1; 150 151 //判斷從機是否有低電平響應信號 如不響應則跳出,響應則向下運行 152 if(!P3_6) //T ! 153 { 154 U8FLAG=2; 155 //判斷從機是否發出 80us 的低電平響應信號是否結束 156 while((!P3_6)&&U8FLAG++); 157 158 U8FLAG=2; 159 //判斷從機是否發出 80us 的高電平,如發出則進入數據接收狀態 160 while((P3_6)&&U8FLAG++); 161 162 163 //數據接收狀態 164 COM(); 165 U8RH_data_H_temp=U8comdata; 166 COM(); 167 U8RH_data_L_temp=U8comdata; 168 COM(); 169 U8T_data_H_temp=U8comdata; 170 COM(); 171 U8T_data_L_temp=U8comdata; 172 COM(); 173 U8checkdata_temp=U8comdata; 174 175 //數據讀取完后拉高總線電平 176 P3_6=1; 177 178 //數據校驗 179 U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp); 180 if(U8temp==U8checkdata_temp) 181 { 182 U8RH_data_H=U8RH_data_H_temp; 183 U8RH_data_L=U8RH_data_L_temp; 184 U8T_data_H=U8T_data_H_temp; 185 U8T_data_L=U8T_data_L_temp; 186 U8checkdata=U8checkdata_temp; 187 } 188 } 189 190 } 191 192 193 //----------------------------------------------// 194 //------------溫度濕度數碼管顯示區--------------// 195 //----------------------------------------------// 196 //設置溫度值 197 void SetTemperature(unsigned char value) 198 { 199 200 unsigned char unitPlace, tenPlace; 201 202 //取出個位、十位數字 203 unitPlace = value/1%10; 204 tenPlace = value/10; 205 206 P0 = led[tenPlace]; 207 P2 = 0x7f; 208 Delayms(4); 209 P2 = 0xff; 210 211 P0 = led[unitPlace]; 212 P2 = 0xbF; 213 Delayms(4); 214 P2 = 0xff; 215 } 216 217 //設置濕度值 218 void SetHumidity(unsigned char value) 219 { 220 unsigned char unitPlace, tenPlace; 221 222 //取出個位、十位數字 223 unitPlace = value/1%10; 224 tenPlace = value/10; 225 226 227 P0 = led[tenPlace]; 228 P2 = 0xDF; 229 Delayms(4); 230 P2 = 0xFF; 231 232 P0 = led[unitPlace]; 233 P2 = 0xEF; 234 Delayms(4); 235 P2 = 0xFF; 236 } 237 238 239 //----------------------------------------------// 240 //-----系統初始化點亮報警燈和顯示數碼管---------// 241 //-----點亮報警燈,顯示數碼管88------------------// 242 //----------------------------------------------// 243 //系統初始化 244 void Init(void) 245 { 246 U8 number = 100; //閃爍頻率 247 U8 count = 0; //計數 248 249 P1_0 = 0; 250 P1_1 = 0; 251 252 while(count < number) 253 { 254 //設置溫度 255 SetTemperature(88); 256 //設置濕度 257 SetHumidity(88); 258 259 count++; 260 } 261 262 Delayms(500); 263 264 P1_0 = 1; 265 P1_1 = 1; 266 267 } 268 269 270 //----------------------------------------------// 271 //----------溫度濕度讀取和顯示控制--------------// 272 //----------------------------------------------// 273 void main() 274 { 275 276 //報警值區域 277 U8 tempAlarmMin = 20; 278 U8 tempALarmMax = 32; 279 U8 HumidityMin = 45; 280 U8 HumidityMax = 65; 281 282 //顯示循環次數 283 U8 number = 250; 284 U8 count = 0; 285 286 //系統初始化 287 Init(); 288 289 while(1) 290 { 291 count =0; 292 293 //調用溫濕度讀取子程序 294 RH(); 295 296 297 if(U8T_data_H > tempALarmMax || U8T_data_H < tempAlarmMin) 298 { 299 P1_0 = 0; 300 } 301 else 302 { 303 P1_0 = 1; 304 } 305 306 if(U8RH_data_H < HumidityMin || U8RH_data_H > HumidityMax) 307 { 308 P1_1 = 0; 309 } 310 else 311 { 312 P1_1 = 1; 313 } 314 315 //讀取模塊數據周期不易小於 2S 所以這里循環顯示2s后讀取 316 while(count < number) 317 { 318 //設置溫度 319 SetTemperature(U8T_data_H); 320 //設置濕度 321 SetHumidity(U8RH_data_H); 322 323 count++; 324 } 325 326 327 } 328 329 }
電路大概介紹
硬件程序優化版