[应用相关] STM32读取温湿度传感器DHT11和DHT21(AM2301)系列问题

[复制链接]
1715|13
 楼主| 734774645 发表于 2018-12-5 22:54 | 显示全部楼层 |阅读模式
1、DHT11和DHT21传感器
    这两种传感器都是奥松公司的产品,具体的传感器说明书在其官网上有(www.aosong.com)。
    DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数 字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一 个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。
    DHT21(AM2301)湿敏电容数字温湿度模块是一款含有己校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个高精度测温元件,并与一个高性能 8 位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在单片机中,传感器内部在检测信号的处理过程中要调用这些校准系数。标准单总线接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达 20 米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选择。产品为 3 引线(单总线接口)连接方便。特殊封装形式可根据用户需求而提供。
2、温湿度读取方式
    两种传感器均采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完 成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释 放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ的上拉电阻,这样,当总线闲置时, 其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须 严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

 楼主| 734774645 发表于 2018-12-5 22:54 | 显示全部楼层
3、两种传感器的主要区别
   包括两点,分别是单总线起始信号的数据总线拉低时间和温湿度高低位数据含义。
   DHT11的单总线格式定义:
1070495-20180407105844968-1719120366.jpg
   DHT21的单总线格式定义:
1070495-20180407110001893-308796152.jpg
 楼主| 734774645 发表于 2018-12-5 22:56 | 显示全部楼层
4、微秒级延时函数
    根据上面的介绍我们现在需要一个微秒级的精确延时函数,否则就不能成功的读取传感器数据。STM32单片机的滴答定时器可以满足。
  (1)保证滴答定时器的时钟频率为72MHz
    STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。在固件库3.0以上,只需要通过两步就可以完成对时钟频率的选择。
   ①修改system_stm32f10x.c开头的时钟宏定义,如下:
  1. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
  2. /* #define SYSCLK_FREQ_24MHz  24000000 */
  3. /* #define SYSCLK_FREQ_36MHz  36000000 */
  4. /* #define SYSCLK_FREQ_48MHz  48000000 */
  5. /* #define SYSCLK_FREQ_56MHz  56000000 */
  6. #define SYSCLK_FREQ_72MHz  72000000
②在主函数main中调用SystemInit()函数。
   ③如果没有成功,需要检查单片机的晶振是否起振。简单的检测方法:
       有示波器的可以查看晶振的输出波形,正常应为正弦波。没有示波器的可以利用万用表分别测量晶振的管脚电平,正常应在1/2*VCC左右。
  (2)程序编写
    ①在main()函数中添加:SysTick_Config(72000000 / 1000000);//除以1000000微秒级(100000十微秒级,1000毫秒级),指进入中断的间隔时间
  1. int main(void)
  2. {      
  3.     SystemInit();
  4.     SysTick_Config(72000000 / 1000000);
  5. }
②Delay.c
  1. #include "stm32f10x.h"
  2. #include "Delay.h"

  3. int TimingDelay=0;

  4. void delay_us(u32 n)
  5. {
  6.     TimingDelay=n;
  7.   while(TimingDelay!=0);
  8. }
  9. void delay_ms(u32 n)
  10. {
  11.     while(n--)
  12.     {
  13.      delay_us(1000);        
  14.     }
  15. }


 楼主| 734774645 发表于 2018-12-5 22:58 | 显示全部楼层
Delay.h
  1. #ifndef _DELAY__H_
  2. #define _DELAY__H_

  3. void delay_us(u32 n);
  4. void delay_ms(u32 n);

  5. #endif

③stm32f10x_it.c
  1. extern int TimingDelay;
  2. void SysTick_Handler(void)
  3. {
  4.     if(TimingDelay!=0)
  5.     {
  6.         TimingDelay--;   
  7.     }
  8. }


 楼主| 734774645 发表于 2018-12-5 23:04 | 显示全部楼层
5、编写读传感器数据程序

    ①DHxx.c
  1. #include "stm32f10x.h"
  2. #include "DHxx.h"
  3. #include "Delay.h"
  4. #include "sys.h"
  5. u8 tdata[4]={0x00,0x00,0x00,0x00};
  6. u8 sbuf,check;

  7. //***************************************************************************/
  8. //      //uchar       i;
  9. //      uchar    U8FLAG,k;
  10. //      uchar    U8count,U8temp;
  11. //      uchar    U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
  12. //      uchar    U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
  13. //      uchar    U8comdata;
  14. //      uint   ReceiveHighByte;
  15. //      uint   ReceiveLowByte;
  16. //***************Global defination for DHT11 end****//
  17. void DHT_PortIN(void)
  18. {
  19.     GPIO_InitTypeDef  GPIO_InitStructure;
  20.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;     
  23.     GPIO_Init(GPIOB,&GPIO_InitStructure);
  24. }
  25. void DHT_PortOUT(void)
  26. {
  27.     GPIO_InitTypeDef  GPIO_InitStructure;
  28.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
  29.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
  31.     GPIO_Init(GPIOB,&GPIO_InitStructure);
  32. }
  33. unsigned char StartDHT11(void)
  34. {
  35.    DHT_PortOUT();
  36.    DHT_Out = 0;
  37.    delay_ms(20);  //DHT11>18ms
  38.   
  39.    DHT_Out = 1;   
  40.      DHT_PortIN();
  41.    delay_us(20);  

  42.    if(!DHT_In)
  43.    {
  44.            while(!DHT_In);
  45.            while(DHT_In);
  46.            return 1;
  47.    }
  48.     return 0;
  49. }

  50. unsigned char StartDHT21(void)
  51. {
  52.    DHT_PortOUT();
  53.    DHT_Out = 0;
  54.    delay_ms(1);  //DHT21>800us
  55.   
  56.    DHT_Out = 1;
  57.      DHT_PortIN();
  58.    delay_us(20);  

  59.    if(!DHT_In)
  60.    {
  61.             while(!DHT_In);
  62.            while(DHT_In);
  63.            return 1;
  64.    }
  65.     return 0;
  66. }
  67. void com(void)
  68. {
  69.     u8 i,tt;
  70.     tt = 0;
  71.     for(i = 0;i<8;i++)
  72.     {
  73.         sbuf <<= 1;
  74.         delay_us(20);
  75.         while(!DHT_In);
  76.         delay_us(25);
  77.         tt = 100;
  78.         while(tt++);
  79.         if(DHT_In)
  80.         {
  81.              sbuf |= 0x01;
  82.              delay_us(30);
  83.         }
  84.         else
  85.         {
  86.             sbuf &= 0xfe;
  87.         }
  88.     }
  89. }
  90. u8 ReadDHT11(void)
  91. {
  92.     u8 sum;
  93.     if(StartDHT11())   
  94.     {
  95.         com();
  96.         tdata[0]=sbuf;
  97.         com();
  98.         tdata[1]=sbuf;
  99.         com();
  100.         tdata[2]=sbuf;        
  101.         com();
  102.         tdata[3]=sbuf;
  103.         com();
  104.         check = sbuf;
  105.         sum = (tdata[0]+tdata[1]+tdata[2]+tdata[3]);
  106.     }
  107.     if(check == sum)
  108.     return(1);
  109.     else   
  110.     return 0;
  111. }

  112. u8 ReadDHT21(void)
  113. {
  114.     u8 sum;
  115.     if(StartDHT21())   
  116.     {
  117.         com();
  118.         tdata[0]=sbuf;
  119.         com();
  120.         tdata[1]=sbuf;
  121.         com();
  122.         tdata[2]=sbuf;        
  123.         com();
  124.         tdata[3]=sbuf;
  125.         com();
  126.         check = sbuf;
  127.         sum = (tdata[0]+tdata[1]+tdata[2]+tdata[3]);
  128.     }
  129.     if(check == sum)
  130.     return(1);
  131.     else   
  132.     return 0;
  133. }

 楼主| 734774645 发表于 2018-12-5 23:05 | 显示全部楼层
DHxx.h                     //(注意:我这边定义的DATA管脚为PB1)
  1. #ifndef _DHXX__H_
  2. #define _DHXX__H
  3. #include "sys.h"
  4. #define DHT_Out PBout(1)
  5. #define DHT_In  PBin(1)

  6. #define uchar unsigned char
  7. #define uint  unsigned int

  8. unsigned char StartDHT11(void);
  9. unsigned char StartDHT21(void);
  10. void DHT_PortIN(void);
  11. void DHT_PortOUT(void);
  12. u8 ReadDHT11(void);
  13. u8 ReadDHT21(void);
  14. void com(void);
  15. //**********************************

  16. //**********************************

  17. extern u8 tdata[4];
  18. extern u8 sbuf;
  19. extern u8 check;

  20. #endif

②sys.h
  1. #include "stm32f10x.h"

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

  14. #define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808
  15. #define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08
  16. #define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008
  17. #define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408
  18. #define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808
  19. #define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08
  20. #define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

  21. //IO口操作,只针对单一的IO口//n的值小于16
  22. #define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
  23. #define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

  24. #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  
  25. #define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  

  26. #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)
  27. #define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  

  28. #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)
  29. #define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)

  30. #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  
  31. #define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  

  32. #define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  
  33. #define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  

  34. #define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  
  35. #define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)
  36. /////////////////////////////////////////////////////////////////


③main.c
  1. /* Includes ------------------------------------------------------------------*/
  2. #include "stm32f10x.h"
  3. #include <stdio.h>
  4. #include "system.h"
  5. #include "sys.h"
  6. #include "DHxx.h"
  7. #include "Delay.h"
  8. int main(void)
  9. {      
  10.     SystemInit();
  11.     SysTick_Config(72000000 / 1000000);
  12.     while(1)
  13.     {
  14.         ReadDHT11();// ReadDHT21();//读取的信息在DHxx.c的tdata[]数组中
  15.         delay_ms(1000);
  16.         delay_ms(1000);  //注意读取间隔应该在2秒以上
  17.         }
  18. }

磨砂 发表于 2018-12-7 13:55 | 显示全部楼层
非常详细  写的不错啊
晓伍 发表于 2018-12-7 14:00 | 显示全部楼层
是传说中的二总线吗
八层楼 发表于 2018-12-7 14:04 | 显示全部楼层
湿度传感器的原理是什么呀
观海 发表于 2018-12-7 14:48 | 显示全部楼层
良心作品 支持一个
xuanhuanzi 发表于 2018-12-7 22:29 | 显示全部楼层
湿度传感器,可以感应空气中水分
xiaoqizi 发表于 2018-12-12 12:44 | 显示全部楼层
湿度传感器的原理是什么呀
13413604662 发表于 2019-7-5 20:39 | 显示全部楼层
请问sys.h定义这么多这是什么意思呀
稳稳の幸福 发表于 2020-8-27 13:17 | 显示全部楼层
学习学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则

211

主题

3588

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部