天天看點

【STM32 .Net MF開發闆學習-19】DHT11溫濕度傳感器通信(上)

前段時間開發遠端醫療系統(Dr.Cloud)就曾用到過溫濕度傳感器,不過當時考慮到內建難度,選了一個RS485接口的傳感器,該傳感器實作了Modbus Rtu Slave的功能,隻要客戶程式實作Modbus Rtu Client即可讀出溫濕度資料。是友善了開發,不過價格不菲,要價要150元左右。

網友fangyuan推薦了一款僅7元的DHT11溫濕度傳感器,剛開始以為是TTL電平的序列槽通信,後來一研究,原來通過一根資料線的雙向通信,并且對時序要求很嚴格,這東西也許用單片做更容易,用STM32來做,反而有老虎吃天,無從下口之感。想來想去,最理想的方式也許需要深入研究時鐘的輸入捕獲相關知識了。

不過直到三個多月之後的今天,才有時間和精力去研究相關内容。閑言少叙,先看一下DHT11的典型應用電路(見下圖)。

【STM32 .Net MF開發闆學習-19】DHT11溫濕度傳感器通信(上)

通信接口為串行接口(單線雙向),通信過程如下:

【STM32 .Net MF開發闆學習-19】DHT11溫濕度傳感器通信(上)

數字0和數字1的信号表示方法如下(有點類似紅外遙控器的編碼了):

【STM32 .Net MF開發闆學習-19】DHT11溫濕度傳感器通信(上)

一次完整的資料傳輸為40bit,高位先出。

資料格式:8bit濕度整數資料+8bit濕度小數資料

+8bi溫度整數資料+8bit溫度小數資料

         +8bit校驗和

其工作模式為:使用者MCU發送一次開始信号後,DHT11從低功耗模式轉換到高速模式,等待主機開始信号結束後,DHT11發送響應信号,送出40bit的資料,并觸發一次信号采集,使用者可選擇讀取部分資料.從模式下,DHT11接收到開始信号觸發一次溫濕度采集,如果沒有接收到主機發送開始信号,DHT11不會主動進行溫濕度采集.采集資料後轉換到低速模式。

單片機讀取資料的一般思路就是,延時一定的時間,去讀Data資料線的電平是高是低,進而判斷資料是0還是1。不過這樣做,對延時精度要求很高,否則很容易把起始位當成資料位來判斷了。

但是在STM32系統,由于存在多任務和中斷程式,如果用傳統的延時方法,是很難滿足多任務下資料讀取需求的,是以我最直接的思路還是,通過時鐘的輸入捕獲功能,擷取Data資料線上所有上升沿和下降沿的精确時間,有了這個資料,就可以非常精确的判斷出數字0和數字1了。

設定時鐘的代碼如下:

//72M/(71+1)=1M   1us一次滴答    

CPU_TIMER_Initialize(timer,0xFFFF,71,TIMER_ISR,NULL);

STM32F10x_TIMER &tim=STM32F10x::TIMER(timer);

//TIM3_CH3

tim.CCMR[1] = 0x01 | 0x30;      //輸入模式,濾波為8  映射到TI3上

tim.CCER = 0x0200;              //下降沿有效

tim.DIER = 0x0008;               //中斷

//tim.CCER |= 0x0100;           //捕獲使能

//TIM3_CH4

tim.CCMR[1] |= 0x0200 | 0x3000; //輸入模式,濾波為8   映射到TI3上

tim.CCER |= 0x0000;             //上升沿有效

tim.DIER |= 0x0010;

//tim.CCER |= 0x1000;           //捕獲使能

中斷TIMER_ISR函數裡,記下中斷發生時刻的計數器的值,根據這些值,就可以換算為實際的溫濕度資料了,相關代碼如下:

STM32F10x_TIMER &tim=STM32F10x::TIMER(timer);       

  time_index = 0;

  HT_Flag = FALSE;

  tim.CCER |= 0x0100;        //捕獲使能

  tim.CCER |= 0x1000;        //捕獲使能

  Sleep(10000);              //延時 10ms  最長 80+80+40*(50+70) = 4960us = 4.96ms

  tim.CCER &= ~0x0100;       //捕獲禁止

  tim.CCER &= ~0x1000;       //捕獲禁止

  tim.CR1 = 0x0;              //禁止計數 

  if(time_index>8)

  {

     UINT32 index=0;

          UINT32 data[128];

     for(int i=4;i<time_index;i+=2)

     {

        time_data[index++]=time_data[i];

     }

     if(index==40)

        for(int i=0;i<5;i++)

        {

           HT_data[i]=0;

           for(int j=0;j<8;j++)

           {

              HT_data[i]|= time_data[i*8+j] > 40 ? (1 <<(7-j)) :0;

           }

        }

                  HT_Flag = (((HT_data[0]+HT_data[1]+HT_data[2]+HT_data[3]) & 0xFF) == HT_data[4]);

     }    

}

接線圖和運作後的結果如下圖所示,可以看出溫濕度已經源源不斷的被讀出來了。

【STM32 .Net MF開發闆學習-19】DHT11溫濕度傳感器通信(上)

是以,我打算專門寫一篇這種接口封裝的博文,以期應用開發的朋友,也可以開發出這種對時序要求嚴格的應用來。

繼續閱讀