基于51单片机的LCD1602显示温湿度
51單片機基礎難點知識理解后,直接通過下面3個小項目可以更好理解51單片機。中斷 定時器 串口甚至是基礎的IO輸入輸出都有結合,再加上一些外設模塊的學習(如1602顯示屏,L298N電機驅動等)
項目一:秒表設計
項目二:LCD1602顯示器顯示內容
項目三:循跡+藍牙小車
基于51單片機的LCD1602顯示溫濕度
- LCD1602顯示屏
- 介紹
- 工作原理
- 代碼驅動
- DHT11溫濕度模塊
- 介紹
- 工作原理
- 代碼驅動
- 主函數實現
- .h文件
- 主函數
- 總結
- 項目總結
- 拓展應用
LCD1602顯示屏
介紹
1602,顧名思義就是16(列) x 02(行)顯示內容,RAM地址映射,控制器內部有80X8位的RAM緩沖區,但是一行只有16個(實際上一行有40個內容,有一部分存到緩沖區沒顯示出來罷了)
實物圖以及外形尺寸圖如圖所示,下面是具體的引腳定義(后面的編程要用到)
可以主要理解為由3個控制信號 RS R/W E 和8個數據位D0-D7組成
工作原理
1.基本讀寫時序圖如下:
讀操作的時候
讀狀態: 輸入:RS = L , RW = H , E = H;
讀數據: 輸入:RS = H, RW = H , E = H;
>寫狀態的時候
寫指令 : 輸入: RS = L , RW = L , D0~D7 = 指令碼, E = 高脈沖(H)
寫數據 : 輸入 : RS = H . RW = L ,D0~D7 = s數據, E = 高脈沖(H)
關于里面的一些時序參數
這里面的單位都是ns級別,而單片機的指令周期為1us,具體看清時序里面的時間,方便延時以符合要求,具體的后面代碼中可以參考
2.指令代碼如下,表格為8位數據位
功能3: 置輸入模式
| 0 | 0 | 0 | 0 | 0 | 1 | N | S |
N =1,讀或寫一個字符后地址指針+1,光標+1;
N =0,讀或寫一個字符后地址指針-1,光標-1;
S =1,寫一個字符,整屏顯示左移(N=1)或者右移(N=0)
S =0,寫一個字符,沒有移動功能
功能4: 顯示開/關設置
| 0 | 0 | 0 | 0 | 1 | D | C | B |
D =1,開顯示;D =0,關顯示
C =1,顯示光標;C =0,不顯示光標
B =1,光標閃爍;B =0,不閃爍
功能5:光標或字符移位
| 0 | 0 | 0 | 1 | S/C | R/L | X | X |
| 0 | 0 | 光標左移1格,AC值-1 |
| 0 | 1 | 光標右移1格,AC值+1 |
| 1 | 0 | 全部左移1格,光標不動 |
| 1 | 1 | 全部右移1格,光標不動 |
功能6:置功能
| 0 | 0 | 1 | DL | N | F | 0 | 0 |
DL: 0 = 數據線4位; 1 = 數據線8位
N: 0 = 顯示1行; 1 = 顯示兩行
F: 0 = 5x7點陣; 1 = 5x10點陣
代碼驅動
大部分解釋完之后附上初始化的過程
LCD1602.c文件
#include <REG52.H> #include "LCD1602.h" #include <intrins.h> //頭文件,用到nop()函數//這里的LCD三個控制信號口根據51開發板定的,可以直接將1602顯示屏插51開發板上面 sbit LCD_RS = P2^6; sbit LCD_RW = P2^5; sbit LCD_E = P2^7; //定義三個控制信號引腳的端口 #define LCD_DatePort P0 //宏定義 數據口void LCD_Delay1ms() //延時1ms函數 {unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i); } //寫指令 void LCD_WriteCommand(unsigned char Command) {LCD_RS = 0; LCD_RW = 0; //寫指令時 輸入: RS = L , RW = L LCD_DatePort = Command; //數據口傳入指令LCD_E = 1;LCD_Delay1ms();LCD_E = 0;LCD_Delay1ms(); //這部分根據時序圖時序寫 } //寫數據 void LCD_WriteDate(unsigned char Date) {LCD_RS = 1; LCD_RW = 0; //寫數據時 輸入: RS = H , RW = L LCD_DatePort = Date; //數據口傳入數據LCD_E = 1;LCD_Delay1ms();LCD_E = 0;LCD_Delay1ms(); //這部分根據時序圖時序寫 } //LCD初始化 void LCD_Init() {LCD_WriteCommand(0x38);//數據8位,顯示2行,5x7點陣 具體參考指令6LCD_WriteCommand(0x0c);//開顯示,光標關 具體參考指令4LCD_WriteCommand(0x06);//地址,光標移動 具體參考指令3 LCD_WriteCommand(0x01);//清屏 } //LCD顯示字符函數 void LCD_Showchar(unsigned char Row,unsigned char Column,unsigned char FuHao) { //參數: 行 列 符號SetMouse(Row,Column);LCD_WriteDate(FuHao); } //LCD顯示字符串函數 void LCD_ShowString(unsigned char Row,unsigned char Column,unsigned char *String) { //參數: 行 列 字符串unsigned char i;SetMouse(Row,Column);for(i=0;String[i]!='\0';i++){LCD_WriteDate(String[i]);} } //計算m^n函數 int LCD_Power(int x,int y) //x^y {unsigned char i;int ret = 1;for(i=0;i<y;i++){ret = ret*x;}return ret; } //顯示數字函數 void LCD_ShowNum(unsigned char Row,unsigned char Column,int num,int length) {SetMouse(Row,Column);for(;length>0;length--){ LCD_WriteDate('0'+num/LCD_Power(10,(length-1))%10);//從高位開始逐漸顯示數字的每一位,前面多一個'0'+ 代表從數字0所在的RAM存儲地址算起,即讓其顯示數字字符} }DHT11溫濕度模塊
介紹
由三根線組成,VCC GND供電供地,Data為數據端口,實現數據的收發輸出為單總線數字信號,溫度測量范圍0-50度(精度正負2度,分辨率1度),濕度測量范圍為20-90%RH(精度為正負5%,分辨率1%)
工作原理
采用單總線雙向串行通信協議,每次采集都要由單片機發起開始信號,然后DHT11會向單片機發送響應并開始傳輸40位數據幀,高位在前。
數據格式
數據格式40幀(40bit)
濕度整數部分+濕度小數部分 8bit + 8bit
溫度整數部分+溫度小數部分 8bit + 8bit
校驗位部分 8bit
數據校驗,濕度和溫度的整數小數部分全部加起來判斷是否與校驗位部分相等,若相等,則取出數據;否之,數據重新獲取
濕度小數部分和溫度小數部分單片機都默認為0,即校驗位只會判斷兩者的整數部分和
時序圖
總線空閑狀態高電平.
主機 將總線拉低,等待DHT11響應, (主機發送起始信號)
從機(DHT11)接收主機起始信號后,等待主機起始信號結束, 這個過程要求18ms以上,保證DHT11檢測到起始信號
從機(DHT11)發送80us的低電平響應信號
主機延時20-40us后讀取DHT11的響應信號
主機發送完開始信號,可以切換到輸入模式或者接上拉電阻置高電平,
代碼驅動
DHT11.c文件
#include <REG52.H> #include "DHT11.h"sbit DHT11_Data = P3^6; //數據端口和IO口的連接 unsigned int rec_dat [4]; //存儲溫濕度高四位和低四位 unsigned char rec_dat_lcd0 [6];//濕度高四位 unsigned char rec_dat_lcd1 [6];//濕度低4位 unsigned char rec_dat_lcd2 [6];//溫度高4位 unsigned char rec_dat_lcd3 [6]; //溫度低4位 //微妙延時函數 void DHT11_Delayus(unsigned char us) {while(--us); } //毫秒延時函數 void DHT11_Delayms(unsigned int ms) {unsigned int i;for(;ms>0;ms--)for(i=110;i>0;i--); } //主機發送起始信號 void DHT11_START() {DHT11_Data = 1;DHT11_Delayus(2); DHT11_Data = 0; DHT11_Delayms(20); DHT11_Data = 1;DHT11_Delayus(13);//延時都根據時序來的 } //DHT11接收字節函數 unsigned char DHT11_REC_bit() {unsigned char i,dat;for(i=0;i<8;i++) //一個字節8位,循環8次{while(!DHT11_Data); //等待高電平 DHT11_Delayus(8); //等高電平穩定,根據時序來dat<<=1; //數據左移 if(DHT11_Data == 1){dat += 1; //如果數據端口為高電平,直接將該位數據置1 }while(DHT11_Data == 1); //等待電平拉低 }return dat; //返回讀取的字節 } //DHT11接收信號函數 void DHT11_REC() {unsigned int RH,RL,TH,TL,receive;unsigned char R_H,R_L,T_H,T_L;DHT11_START();DHT11_Data = 1; //保持閑置狀態if(DHT11_Data == 0) //判斷是否進入響應信號{while(DHT11_Data == 0); //等待高電平DHT11_Delayus(40);//主機40us讀取溫濕度信號 R_H = DHT11_REC_bit();//接收濕度高8R_L = DHT11_REC_bit();//接收濕度低8T_H = DHT11_REC_bit();//接收溫度高8T_L = DHT11_REC_bit();//接收溫度低8receive = DHT11_REC_bit();//接收校驗位DHT11_Delayus(25);//延時一下,開始后面校驗 if((R_H+R_L+T_H+T_L)== receive){//如果校驗通過,直接將讀取的值存到存儲數組中去,后面就只管用數組里面的數據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;} }主函數實現
.h文件
LCD1602.h
#ifndef _LCD1602_H_ #define _LCD1602_H_void LCD_Delay1ms(); void LCD_WriteCommand(unsigned char Command); void LCD_WriteDate(unsigned char Date); void LCD_Init();void SetMouse(unsigned char Row,unsigned char Column); void LCD_Showchar(unsigned char Row,unsigned char Column,unsigned char FuHao); void LCD_ShowString(unsigned char Row,unsigned char Column,unsigned char *String); int LCD_Power(int x,int y); void LCD_ShowNum(unsigned char Row,unsigned char Column,int num,int length);#endifDHT11.h
#ifndef _DHT11_H_ #define _DHT11_H_void DHT11_Delayus(unsigned char us); void DHT11_Delayms(unsigned int ms); void DHT11_START(); unsigned char DHT11_REC_bit(); void DHT11_REC(); #endif主函數
#include <REG52.H> #include "LCD1602.h" #include "DHT11.h" #include <stdio.h> //DHT11文件中定義的存儲數據數組 extern unsigned int rec_dat [4]; extern unsigned char rec_dat_lcd0 [6]; extern unsigned char rec_dat_lcd1 [6]; extern unsigned char rec_dat_lcd2 [6]; extern unsigned char rec_dat_lcd3 [6];int main() {LCD_Init(); /*在寫顯示字符串 顯示數字函數之前,自己也可以寫隨便顯示幾個來驗證函數正確性LCD_Showchar( 1, 1, 'Q'); LCD_Showchar( 1, 2, 'A'); LCD_ShowNum( 2, 7, 666,3);*/LCD_ShowString(1,0,"Humi:"); //在1行 0列顯示字符串"Humi:"LCD_ShowString(2,0,"Temp:"); //在2行 0列顯示字符串"Temp:"while(1){DHT11_Delayms(150);DHT11_REC(); //不斷接收數據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]); //包含在stdio.h文件中,將數據格式強制轉化成字符串形式 LCD_ShowString(1,6,rec_dat_lcd0);LCD_ShowString(1,8,".");LCD_ShowString(1,9,rec_dat_lcd1);LCD_ShowString(1,10," %"); //實時顯示DHT11采集的溫濕度,然后在LCD1602上顯示了LCD_ShowString(2,6,rec_dat_lcd2);LCD_ShowString(2,8,".");LCD_ShowString(2,9,rec_dat_lcd3);LCD_ShowString(2,10," C"); } }總結
項目總結
與前面一個51單片機秒表項目相比,前面一個偏向于51單片機本身的內容(IO 中斷 定時器等)。這個項目更多是偏向單片機外設的一些學習
基于51單片機溫濕度顯示的項目,主要是學習外設-LCD1602模塊 DHT11模塊。學會看外設的數據手冊(里面的截圖基本上都來自數據手冊) 看懂時序圖,會根據時序圖寫代碼,具體可以根據時序圖來驗證代碼,了解整個外設的工作過程
拓展應用
1.學會LCD1602之后,驅動代碼基本上每次可以照搬下來,如果要顯示其它內容,可以根據數據手冊或者指令在.c文件中添加相關的函數
2.DHT11模塊只是眾多傳感器的一個,基本上大部分外設模塊重點就是了解大致原理,看懂時序,直接移植相關代碼進行引腳修改,這部分重點僅僅是學會看時序圖,根據時序圖寫代碼,為后面學習更多外設做準備
3.也還可以添加串口初始化以及串口中斷函數,在電腦串口上顯示單片機從外設接收過來的內容
總結
以上是生活随笔為你收集整理的基于51单片机的LCD1602显示温湿度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RSTP接口角色
- 下一篇: 谷歌protobuf(Protocol