51单片机 DHT11温湿度传感器LCD显示+串口打印显示
第一部分:DHT11詳解:
DHT11是一款有已校準數字信號輸出的溫濕度傳感器。 精度濕度±5%RH, 溫度±2℃,量程濕度20-90%RH, 溫度0~50℃。
**一.電路連接分析
1.引腳圖**
**
這里特別注意,該實驗選擇P3^6引腳位DATA數據引腳,其他引腳可以修改
**
2.實物圖
二、數據分析
1.數據采集及時序分析
DHT11采用單總線通信,單總線即只有一根數據線,系統中的數據交換、控制均由單總線完成。
傳送數據位定義
DATA 管腳用于DHT11與單片機之間的通訊和同步,采用單總線數據格式,一次傳送40 位數據,高位先出。
數據格式:
8bit 濕度整數數據+ 8bit 濕度小數數據+ 8bit 溫度整數數據+ 8bit 溫度小數數據+ 8bit 校驗位。
注:其中濕度小數部分為0。
校驗位數據定義
8bit 濕度整數數據 + 8bit 濕度小數數據 + 8bit 溫度整數數據 + 8bit 溫度小數數據 = 8bit 校驗位,如果以上等式成立,則本次傳感器采集的數據有效,否則無效
數據位的定義
0011 0101 0000 0000 0001 1000 0000 0100 0101 0001
濕度高8 位 濕度低8 位 溫度高8 位 溫度低8 位 校驗位
計算: 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,接收數據正確。
濕度:0011 0101(整數)=35H=53%RH 0000 0000(小數)=00H=0.0%RH =>53%RH + 0.0%RH = 53.0%RH
溫度:0001 1000(整數)=18H=24℃ 0000 0100(小數)=04H=0.4℃ =>24℃ + 0.4℃ = 24.4℃
2.時序分析
用戶主機(MCU)發送一次開始信號后,DHT11 從低功耗模式轉換到高速模式,待主機開始信號結束后,DHT11 發送響應信號,送出 40bit 的數據,幵觸發一次信采集,依次輪回
總時序圖
開始時序:
單片機連接DHT11的DATA引腳的I/O口輸出低電平,且低電平保持時間不能小于 18ms,然后等待 DHT11 作出應答信號。
應答信號時序:
DHT11 的 DATA 引腳檢測到外部信號有低電平時, 等待外部信號低電平結束, 延遲后 DHT11 的 DATA引腳處于輸出狀態,輸出 80 微秒的低電平作為應答信號,緊接著輸出 80 微秒的高電平通知外設準備接收數據。
接收數據
位數據“0”的格式為: 50 微秒的低電平和 26-28 微秒的高電平,位數據“1”的格式為: 50 微秒的低電平加 70微秒的高電平
第二部分:代碼分析
main,c
/******************************************************************************* * 實驗名 :溫度顯示實驗 * 使用的IO : * 實驗效果 :1602顯示溫度 * 注意 : *******************************************************************************/#include<reg51.h> #include"lcd.h" #include<intrins.h> #include<stdio.h>sbit Temp_data=P3^6; /******************************************************************************* * 函數名 : main * 函數功能 : 主函數 * 輸入 : 無 * 輸出 : 無 *******************************************************************************/ unsigned int rec_dat[4]; //unsigned char data_byte; //unsigned char rec_dat_lcd=[4]; unsigned char rec_dat_lcd0[6]; unsigned char rec_dat_lcd1[6]; unsigned char rec_dat_lcd2[6]; unsigned char rec_dat_lcd3[6];//定義 void DHT11_delay_us(unsigned char n); void DHT11_delay_ms(unsigned int z); void DHT11_start(); unsigned char DHT11_rec_byte(); void DHT11_receive(); void InitUART(void);//主函數 void main() {//unsigned char i,j;InitUART();P1=0xf0;InitLcd1602();LcdShowStr(0,0,"Humi:");LcdShowStr(0,1,"Temp:");EA = 1; //開總中斷while(1){DHT11_delay_ms(150);DHT11_receive();sprintf(rec_dat_lcd0,"%d",rec_dat[0]);sprintf(rec_dat_lcd1,"%d",rec_dat[1]);sprintf(rec_dat_lcd2,"%d",rec_dat[2]);sprintf(rec_dat_lcd3,"%d",rec_dat[3]);DHT11_delay_ms(100);//濕度LcdShowStr(6,0,rec_dat_lcd0);LcdShowStr(8,0,".");LcdShowStr(9,0,rec_dat_lcd1);LcdShowStr(10,0," %");//溫度LcdShowStr(6,1,rec_dat_lcd2);LcdShowStr(8,1,".");LcdShowStr(9,1,rec_dat_lcd3);LcdShowStr(10,1," C");//下面通過串口助手打印溫度printf("Humi:%d.%d \n",rec_dat[0],rec_dat[1]);printf("Temp:%d.%d °C\n",rec_dat[2],rec_dat[3]);} }//DHT11起始信號void DHT11_start() {Temp_data=1;DHT11_delay_us(2);Temp_data=0;DHT11_delay_ms(20);Temp_data=1;DHT11_delay_us(13);}//接收一個字節unsigned char DHT11_rec_byte() {unsigned char i,dat;for(i=0;i<8;i++){while(!Temp_data);DHT11_delay_us(8);dat<<=1;if(Temp_data==1){dat+=1;}while(Temp_data);}return dat;}//接收溫濕度數據 void DHT11_receive() {unsigned int R_H,R_L,T_H,T_L;unsigned char RH,RL,TH,TL,revise;DHT11_start();Temp_data=1;if(Temp_data==0){while(Temp_data==0); //等待拉高 DHT11_delay_us(40); //拉高后延時80usR_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]=RH;rec_dat[1]=RL;rec_dat[2]=TH;rec_dat[3]=TL;}}//延時us --2*n+5us void DHT11_delay_us(unsigned char n) {while(--n); }//延時ms void DHT11_delay_ms(unsigned int z) {unsigned int i,j;for(i=z;i>0;i--)for(j=110;j>0;j--); }void InitUART(void)//使用定時器1作為串口波特率發生器 {SCON=0x40; //串口通信工作方式1REN=1; //允許接收TMOD=0x20; //定時器1的工作方式2TH1=0xF3,TL1=0xF3; TI=1; //這里一定要注意TR1=1; }
Lcd.c
#include"lcd.h"//void Read_Busy() //忙檢測函數,判斷bit7是0,允許執行;1禁止 //{ // unsigned char sta; // // LCD1602_DB = 0xff; // LCD1602_RS = 0; // LCD1602_RW = 1; // do // { // LCD1602_EN = 1; // sta = LCD1602_DB; // LCD1602_EN = 0; //使能,用完就拉低,釋放總線 // }while(sta & 0x80); //}void Lcd1602_Write_Cmd(unsigned char cmd) //寫命令 {//Read_Busy();LCD1602_RS = 0;LCD1602_RW = 0;LCD1602_DB = cmd;LCD_Delay10ms(1);LCD1602_EN = 1;LCD_Delay10ms(1);LCD1602_EN = 0; }void Lcd1602_Write_Data(unsigned char dat) //寫數據 {//Read_Busy();LCD1602_RS = 1;LCD1602_RW = 0;LCD1602_DB = dat;LCD_Delay10ms(1);LCD1602_EN = 1;LCD_Delay10ms(1);LCD1602_EN = 0; } //指定位置開始顯示數據! void LcdSetCursor(unsigned char x,unsigned char y) //坐標顯示 {unsigned char addr;if(y == 0)addr = 0x00 + x;//第一行開始,x表示一行的第x個elseaddr = 0x40 + x;//第二行開始,x表示一行的第x個Lcd1602_Write_Cmd(addr|0x80); }void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str) //顯示字符串 {LcdSetCursor(x,y); //當前字符的坐標while(*str != '\0'){Lcd1602_Write_Data(*str++);} }void InitLcd1602() //1602初始化 {Lcd1602_Write_Cmd(0x38); //打開,5*8,8位數據Lcd1602_Write_Cmd(0x0c);Lcd1602_Write_Cmd(0x06);Lcd1602_Write_Cmd(0x01); //清屏 }void LCD_Delay10ms(unsigned int c) //誤差 0us {unsigned char a,b;for(;c>0;c--)for(b=38;b>0;b--)for(a=130;a>0;a--); }Lcd.h
#ifndef __LCD_H_ #define __LCD_H_ /********************************** 當使用的是4位數據傳輸的時候定義, 使用8位取消這個定義 **********************************/ //#define LCD1602_4PINS/********************************** 包含頭文件 **********************************/ #include<reg51.h>//---重定義關鍵詞---// #ifndef uchar #define uchar unsigned char #endif#ifndef uint #define uint unsigned int #endif/********************************** PIN口定義 **********************************/ #define LCD1602_DB P0 //data bus 數據總線 sbit LCD1602_RS = P2^6; sbit LCD1602_RW = P2^5; sbit LCD1602_EN = P2^7; /********************************** 函數聲明 **********************************/ /*在51單片機12MHZ時鐘下的延時函數*/ //void Lcd1602_Delay1ms(uint c); //誤差 0usvo void LCD_Delay10ms(unsigned int c); //void Read_Busy(); //忙檢測函數,判斷bit7是0,允許執行;1禁止 void Lcd1602_Write_Cmd(unsigned char cmd); //寫命令 void Lcd1602_Write_Data(unsigned char dat); //寫數據 void LcdSetCursor(unsigned char x,unsigned char y); //坐標顯示 void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str); //顯示字符串 void InitLcd1602(); //1602初始化#endif本人親測:該代碼可運行!
第三部分:實驗現象
LCD1602實時顯示
第四部分:實驗中的問題
在實驗中一開始,并未能正常的在LCD1602上顯示,反而出現亂碼,此時分析原因為,顯示的數據類型不對。在此過程中,不斷通過串口打印DHT11傳回來的數據進行調試最后才成功。其中,printf()串口打印又成一個問題,通過學習發現一個很好的方法
首先導入#include<stdio.h>C語言頭文件
設置定時器,一開始,用波特率位9600,將TL、TH都設置成0xfd后不管是英文還是中文的都是亂碼。
后來查詢得知:
12M的晶振波特率只能是2400,9600的情況下會有7.8%的誤差,所以會產生亂碼,而2400波特率的情況下誤差是0.16%,這樣就不會產生亂碼了,因此TH1和TL1都設為F3
注意點:因為本實驗使用的晶振是12M,如果你的晶振是11.0592,將TH1和TL1設置為0xFd,波特率=9600;
成功打印出溫度數據后,接下來就是將溫度數據在LCD1602上顯示了,于是,使用sprintf()函數進行字符串拼接,進行顯示,當然這只是我當時想到的方法,如果你有更好的方法也可以的!
第五部分:感謝幫助的博主文檔
https://blog.csdn.net/u013151320/article/details/50389624
https://blog.csdn.net/tongxin082/article/details/81639018
為方便沒有積分的用戶下載,將資源放在百度網盤,有需要自己下載哈!!!感謝支持!
注:V1版本是只有STM32+As608,V2版本是STM32+As608+openmv.大家結合需求自己下載
鏈接:https://pan.baidu.com/s/16viOu4Uu4r0bOjRD1KTd4g
提取碼:cbg1
復制這段內容后打開百度網盤手機App,操作更方便哦
總結
以上是生活随笔為你收集整理的51单片机 DHT11温湿度传感器LCD显示+串口打印显示的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 题目:用D触发器带同步高置数和异步高复位
- 下一篇: unity .obj文件的导出