STM32讀取溫濕度傳感器DHT11和DHT21(AM2301)系列問題


1、DHT11和DHT21傳感器

    這兩種傳感器都是奧松公司的產品,具體的傳感器說明書在其官網上有(www.aosong.com)。

    DHT11 數字溫濕度傳感器是一款含有已校准數字信號輸出的溫濕度復合傳感器。它應用專用的數 字模塊采集技術和溫濕度傳感技術,確保產品具有枀高的可靠性與卓越的長期穩定性。傳感器包括一 個電容式感濕元件和一個 NTC 測溫元件,並與一個高性能 8 位單片機相連接。

    DHT21(AM2301)濕敏電容數字溫濕度模塊是一款含有己校准數字信號輸出的溫濕度復合傳感器。它應用專用的數字模塊采集技術和溫濕度傳感技術,確保產品具有極高的可靠性與卓越的長期穩定性。傳感器包括一個電容式感濕元件和一個高精度測溫元件,並與一個高性能 8 位單片機相連接。因此該產品具有品質卓越、超快響應、抗干擾能力強、性價比極高等優點。每個傳感器都在極為精確的濕度校驗室中進行校准。校准系數以程序的形式儲存在單片機中,傳感器內部在檢測信號的處理過程中要調用這些校准系數。標准單總線接口,使系統集成變得簡易快捷。超小的體積、極低的功耗,信號傳輸距離可達 20 米以上,使其成為各類應用甚至最為苛刻的應用場合的最佳選擇。產品為 3 引線(單總線接口)連接方便。特殊封裝形式可根據用戶需求而提供。

2、溫濕度讀取方式

    兩種傳感器均采用簡化的單總線通信。單總線即只有一根數據線,系統中的數據交換、控制均由單總線完 成。設備(主機或從機)通過一個漏極開路或三態端口連至該數據線,以允許設備在不發送數據時能夠釋 放總線,而讓其它設備使用總線;單總線通常要求外接一個約 4.7kΩ的上拉電阻,這樣,當總線閑置時, 其狀態為高電平。由於它們是主從結構,只有主機呼叫從機時,從機才能應答,因此主機訪問器件都必須 嚴格遵循單總線序列,如果出現序列混亂,器件將不響應主機。

3、兩種傳感器的主要區別

   包括兩點,分別是單總線起始信號的數據總線拉低時間溫濕度高低位數據含義

   DHT11的單總線格式定義:

   DHT21的單總線格式定義:

4、微秒級延時函數

    根據上面的介紹我們現在需要一個微秒級的精確延時函數,否則就不能成功的讀取傳感器數據。STM32單片機的滴答定時器可以滿足。

  (1)保證滴答定時器的時鍾頻率為72MHz

    STM32F103內部8M的內部震盪,經過倍頻后最高可以達到72M。在固件庫3.0以上,只需要通過兩步就可以完成對時鍾頻率的選擇。

   ①修改system_stm32f10x.c開頭的時鍾宏定義,如下:

/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000

   ②在主函數main中調用SystemInit()函數。

   ③如果沒有成功,需要檢查單片機的晶振是否起振。簡單的檢測方法:

       有示波器的可以查看晶振的輸出波形,正常應為正弦波。沒有示波器的可以利用萬用表分別測量晶振的管腳電平,正常應在1/2*VCC左右。

  (2)程序編寫

    ①在main()函數中添加:SysTick_Config(72000000 / 1000000);//除以1000000微秒級(100000十微秒級,1000毫秒級),指進入中斷的間隔時間

int main(void)
{      
    SystemInit();
    SysTick_Config(72000000 / 1000000);
}

    ②Delay.c

#include "stm32f10x.h"
#include "Delay.h"

int TimingDelay=0;

void delay_us(u32 n)
{
    TimingDelay=n;
  while(TimingDelay!=0); 
}
void delay_ms(u32 n)
{
    while(n--)
    {
     delay_us(1000);        
    }
}

      Delay.h

#ifndef _DELAY__H_
#define _DELAY__H_

void delay_us(u32 n);
void delay_ms(u32 n);

#endif

    ③stm32f10x_it.c

extern int TimingDelay;
void SysTick_Handler(void)
{
    if(TimingDelay!=0)
    {
        TimingDelay--;    
    }
}

5、編寫讀傳感器數據程序

    ①DHxx.c

#include "stm32f10x.h"
#include "DHxx.h"
#include "Delay.h"
#include "sys.h"
u8 tdata[4]={0x00,0x00,0x00,0x00};
u8 sbuf,check;

//***************************************************************************/
//      //uchar       i;
//      uchar    U8FLAG,k;
//      uchar    U8count,U8temp;
//      uchar    U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
//      uchar    U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
//      uchar    U8comdata;
//      uint   ReceiveHighByte;
//      uint   ReceiveLowByte;
//***************Global defination for DHT11 end****// 
void DHT_PortIN(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;     
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void DHT_PortOUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}
unsigned char StartDHT11(void)
{
   DHT_PortOUT();
   DHT_Out = 0;
   delay_ms(20);  //DHT11>18ms
  
   DHT_Out = 1;    
     DHT_PortIN();
   delay_us(20);  

   if(!DHT_In)
   {
           while(!DHT_In);
           while(DHT_In);
           return 1;
   }
    return 0;
}

unsigned char StartDHT21(void)
{
   DHT_PortOUT();
   DHT_Out = 0;
   delay_ms(1);  //DHT21>800us
  
   DHT_Out = 1;
     DHT_PortIN();
   delay_us(20);  

   if(!DHT_In)
   {
            while(!DHT_In);
           while(DHT_In);
           return 1;
   }
    return 0;
}
void com(void)
{
    u8 i,tt;
    tt = 0;
    for(i = 0;i<8;i++)
    {
        sbuf <<= 1;
        delay_us(20);
        while(!DHT_In);
        delay_us(25);
        tt = 100;
        while(tt++);
        if(DHT_In)
        {
             sbuf |= 0x01;
             delay_us(30);
        }
        else
        {
            sbuf &= 0xfe;
        }
    }
}
u8 ReadDHT11(void)
{
    u8 sum;
    if(StartDHT11())    
    {
        com();
        tdata[0]=sbuf;
        com();
        tdata[1]=sbuf;
        com();
        tdata[2]=sbuf;        
        com();
        tdata[3]=sbuf;
        com();
        check = sbuf;
        sum = (tdata[0]+tdata[1]+tdata[2]+tdata[3]);
    }
    if(check == sum)
    return(1);
    else    
    return 0;
}

u8 ReadDHT21(void)
{
    u8 sum;
    if(StartDHT21())    
    {
        com();
        tdata[0]=sbuf;
        com();
        tdata[1]=sbuf;
        com();
        tdata[2]=sbuf;        
        com();
        tdata[3]=sbuf;
        com();
        check = sbuf;
        sum = (tdata[0]+tdata[1]+tdata[2]+tdata[3]);
    }
    if(check == sum)
    return(1);
    else    
    return 0;
}

    DHxx.h                     //(注意:我這邊定義的DATA管腳為PB1)

#ifndef _DHXX__H_
#define _DHXX__H
#include "sys.h"
#define DHT_Out PBout(1)
#define DHT_In  PBin(1)

#define uchar unsigned char 
#define uint  unsigned int

unsigned char StartDHT11(void);
unsigned char StartDHT21(void);
void DHT_PortIN(void);
void DHT_PortOUT(void);
u8 ReadDHT11(void);
u8 ReadDHT21(void);
void com(void);
//**********************************

//**********************************

extern u8 tdata[4];
extern u8 sbuf;
extern u8 check;

#endif

    ②sys.h

#include "stm32f10x.h"

///////////////////////////////////////////////////////////////
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只針對單一的IO口//n的值小於16
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //輸入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) /////////////////////////////////////////////////////////////////

    ③main.c

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "system.h"
#include "sys.h"
#include "DHxx.h"
#include "Delay.h"
int main(void)
{      
    SystemInit();
    SysTick_Config(72000000 / 1000000);
    while(1)
    {
        ReadDHT11();// ReadDHT21();//讀取的信息在DHxx.c的tdata[]數組中
        delay_ms(1000);
        delay_ms(1000);  //注意讀取間隔應該在2秒以上 
        }
}    

6、參考

【1】單片機stm32時鍾頻率 http://www.elecfans.com/dianzichangshi/20171113578546.html

【2】https://wenku.baidu.com/view/6306fbf484254b35eefd3428.html

【3】http://www.aosong.com/products-28.html

  

人不曾老去,直至悔恨取代了夢想!---約翰.巴里摩

 轉載需說明出處,筆者總結之前的知識,與大家分享,有問題的可以留給我哦~

     

     

    

     

      

 

 

   

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM