來源:百問網_嵌入式Linux wiki_jz2440 新1期視頻維基教程 (視頻文字版)
作者:韋東山
本文字數:2379,閱讀時長:4分鐘
這節課開始講解DH11溫溼度傳感器的使用,首先查看晶片手冊,裡面的典型應用電路如下:
MCU通過一條數據線與DH11連接,MCU通過這條線發命令給DH11,DH11再通過這條線把數據發送給MCU。
因此,溫溼度模塊的核心就是 MCU發給DH11的命令格式和DH11返回的數據格式。
再來先簡單看一下通訊的時序:
灰色這條線是由MCU驅動控制的,淺色的部分是由DH11驅動控制的。
首先MCU發送一個開始信號,這個開始信號是一個低脈衝,然後再拉高。
然後,DH11拉低,做出一個響應信號,再拉高。
接著就是DH11返回的數據。
這些數據一共有40bit,高位先出。
數據格式:8bit溼度整數數據+8bit溼度小數數據+8bi溫度整數數據+8bit溫度小數數據+8bit校驗和
且當前小數部分用於以後擴展,現讀出為零.
數據傳送正確時校驗和數據等於「8bit溼度整數數據+8bit溼度小數數據+8bi溫度整數數據+8bit溫度小數數據」所得結果的末8位。
DH11的難點是前面所說的時序脈衝,需要滿足一定的時長.比如開始信號:
MCU必須先拉低至少18ms,然後再拉高20-40us,DH11再拉低80us以響應,最後再拉高80us.
接下來就是傳輸數據,我們的目的就是讀到溫溼度的數據,這些數據由DH11提供,那它怎麼傳回這些數據,怎麼表示0和1呢?
可以看到,不管是0還是1,都開始是50us的低電平,
對於0數據,之後是26~28us的高電平;
對於1數據,之後是70us的高電平;
有了上面的知識,加上之前的高精度延時,現在就可以開始寫程序了。
複製前面的第二個程序,文件名改為003_dht11_022_003,然後在sensors目錄裡新建dht11目錄,再創建一個dht11.c文件。
我們的目的是,控制GPIO讀取DHT11的數據,流程如下:
bit0 : 50us低脈衝, 26-28us高脈衝
bit1 : 50us低脈衝, 70us高脈衝
DH11的DATA引腳連接到了GPG5。
先實現GPIO的基本操作,配置GPIO模式,實現輸出、輸入引腳的功能:
static void dht11_data_cfg_as_output(void){ GPGCON &= ~(3<<10); GPGCON |= (1<<10);}static void dht11_data_cfg_as_input(void){ GPGCON &= ~(3<<10);}
再設置輸出電平或讀取引腳數據:
static void dht11_data_set(int val){ if (val) GPGDAT |= (1<<5); else GPGDAT &= ~(1<<5);}static int dht11_data_get(void){ if (GPGDAT & (1<<5)) return 1; else return 0;}
再來實現DHT11的讀操作。
在晶片手冊裡介紹說,DH11傳感器上電後,要等待1s,以越過不穩定狀態,在此期間無需發送任何指令。
因此首先寫一個初始化函數,跳過這個不穩定狀態:
void dht11_init(void){ dht11_data_cfg_as_output(); dht11_data_set(1); mdelay(2000);}
根據start時序要求,編寫程序,維持一個大於18ms的低電平,然後釋放引腳,即設置為輸入引腳即可。
因為該引腳接有上拉電阻,一旦MCU設置為輸入,引腳電平將由上拉電阻決定。
static void dht11_start(void){ dht11_data_set(0); mdelay(20); dht11_data_cfg_as_input();}
然後等待40us以上,再去讀取引腳電平,判斷是否被拉低,以確定DH11給了響應。
static int dht11_wait_ack(void){ udelay(60); return dht11_data_get();}
再寫個延時函數,用於時序中的,等待響應信號結束:
static int dht11_wait_for_val(int val, int timeout_us){ while (timeout_us--) { if (dht11_data_get() == val) return 0; /* ok */ udelay(1); } return -1; /* err */}
後面的數據會有五個字節組成,這裡先寫出讀取一個字節,每個字節要讀取8位。
先等待直到高電平,過濾到共同的50us延時,然後延時28us以上,再讀取引腳電平,
如果引腳電平是1,則數據是1,反之是0。
然後再直到低電平的到來,循環8次,完成一個字節數據的讀取。
static int dht11_recv_byte(void){ int i; int data = 0; for (i = 0; i < 8; i++) { if (dht11_wait_for_val(1, 1000)) { printf(&34;); return -1; } udelay(40); data <<= 1; if (dht11_data_get() == 1) data |= 1; if (dht11_wait_for_val(0, 1000)) { printf(&34;); return -1; } } return data;}