你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeMX DHT11温湿度传感器经验分享

[复制链接]
攻城狮Melo 发布时间:2023-7-1 18:18
1.DHT11简介
DHT11是一款温湿度一体化的数字传感器,该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机连接。通过单片机微处理器简单的电路连接就能够实时的采集湿度和温度。DHT11与STM32之间能采用简单的单总线进行通讯,仅需一个IO口。传感器内部温度和湿度数据40个bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。
DHT11采用单总线数据格式,即单个数据引脚端口完成输入输出双向传输。其数据包由5个字节(40Bit)组成。数据分小数和整数部分,一次完整的数据传输为40bit,高位先出。数据格式如下图示

/ J: y1 j! n6 A: B0 [8 @- z
微信图片_20230701181746.png

) X8 h1 I# r, U5 T1 \
根据以上数据,即可算出温度和湿度的值,计算方法如下:
湿度 = byte4.byte3
温度 = byte2.byte1
校验 = byte4 + byte3 + byte2 + byte1
2 C$ w- d) L/ ^- x. b
DHT11和单片机的一次通讯最大为3ms左右,建议主机连续读取时间间隔不要小于100ms,下面是DHT11的三种时序:

. o* _/ K$ o. Z$ J' s; I! m
⏩ 数据发送时序
首先主机发送开始信号,即拉低数据线保持t1(至少18ms)时间,接着拉高数据线t2(20 ~ 40us)时间;然后读取DHT11的响应,正常的话DHT11会拉低数据线并保持t3(40 ~ 50us)时间作为响应信号,接着DHT11拉高数据线并保持t4(40 ~ 50us)时间后,开始传输数据
, ?; p( I# M5 G/ r/ p1 V
微信图片_20230701181742.png

3 g9 Y( @) G& Z5 \+ ^0 W
⏩ DHT11输出0时序
3 u% V, p: {: S+ \9 [
微信图片_20230701181739.png
. }0 W" D( a2 E% `/ }9 s. C1 {& y
⏩ DHT11输出1时序
$ h# @# c0 d- Y! ~" y) J, `! [
微信图片_20230701181736.png
* m4 o2 S, q/ _6 E

# l8 x6 D& r% }
2.硬件设计

% S; j  V- \1 d6 v7 E6 d9 G
D1指示灯用来提示系统运行状态,DS18B20温度传感器用来检测环境温度,串口1用来打印温度值
指示灯D1
USART1串口
PG11
TIM7(提供us延时)
- a) i* c0 m  [9 d/ G8 m! b

9 X1 m4 g  O8 }/ Q. u8 V: P. d
3.软件设计
3.1 STM32CubeMX设置
; E8 M: Y5 F! H1 ~' h. f& w
➡️ RCC设置外接HSE,时钟设置为72M
7 i6 l" G. H* L. ~+ m" t. u
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
5 x: \5 J. Z9 {* g; K6 w1 S* B/ k/ j
➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位

( w+ {/ M# e. K$ @, E2 V
➡️ PG11设置为GPIO推挽输出模式、上拉、高速
+ |) h0 C. p# g9 b7 g$ G& B. o+ e
➡️ 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us

" F* q) Z2 {9 g/ C0 m6 Z
微信图片_20230701181727.png

8 L7 [- z1 |, f* ~
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

. g& K* B; J) J1 M* V5 |  ?
3.2 MDK-ARM软件编程
0 C8 v; T! p- b5 R, Z1 [3 R
➡️ 在tim.c文件下实现微秒延时(us)函数
  1. void delay_us(uint16_t us){
      ~5 g. Y* A+ F
  2.   uint16_t differ = 0xffff-us-5;# d7 Z1 [" G6 G# @' n9 ^
  3.   //设定TIM7计数器起始值                               
    ! j) ]$ F9 P9 \. d7 N' n
  4.   __HAL_TIM_SET_COUNTER(&htim7,differ);4 [- M: s1 P* J+ \/ G% Z
  5.   //启动定时器       
    - z' N- f2 R4 ]( y
  6.   HAL_TIM_Base_Start(&htim7);                       
    . A6 V3 |% U) K2 @( t1 A/ e
  7.        
    , W) a2 D6 e1 @; M
  8.   while(differ < 0xffff-5){        //判断$ c- E2 G: c+ q2 V# F
  9.     //查询计数器的计数值
    - K9 ~. O: A) z/ L' M3 N
  10.     differ = __HAL_TIM_GET_COUNTER(&htim7);                8 C8 ?8 U5 L: v6 v
  11.   }
    6 n6 ^2 ^4 w3 G; e: r# q0 G
  12.   HAL_TIM_Base_Stop(&htim7);& a4 o' M% X- a2 v- D( b
  13. }
复制代码

; g1 ]4 ~( O, J/ w
➡️ 创建DHT11温湿度传感器驱动文件DHT11.c 和相关头文件DHT11.h
  1. void DHT11_IO_IN(void){  //IO口方向设置为输入- E! K. Z# D4 G  A7 {3 b
  2.   GPIO_InitTypeDef GPIO_InitStructure;; [- a4 k- W8 V, T" {2 q
  3.   GPIO_InitStructure.Pin = GPIO_PIN_11;
    ; i7 k; t2 b  i) Y; h* j2 Y. H
  4.   GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    ) P/ y8 R! Z' ?; G
  5.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);7 J: S8 w5 x' U% j3 a) N
  6. }6 D% O, Y# D$ H, j0 v5 F

  7. # Q1 n0 i: W$ J$ s9 j
  8. void DHT11_IO_OUT(void){  //IO口方向设置为输出
    2 S5 f! p* ^4 Z8 Q; {. |: s
  9.   GPIO_InitTypeDef GPIO_InitStructure;7 J5 f  H0 l: j
  10.   GPIO_InitStructure.Pin = GPIO_PIN_11;
    / B  g* v* v6 k  h/ ]9 A* m
  11.   GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;0 Z  _; F$ P+ I8 f
  12.   GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;7 p! }( s" T- e9 W
  13.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);4 L7 K6 o# F% x' n, A
  14. }
    5 I2 Z" k* l0 @* P* q  h
  15. 8 [1 W, M' M) o; Q. {
  16. void DHT11_Rst(void){                 % |( Q7 ^  W) @3 q' C
  17.   DHT11_IO_OUT();         //设置为输出) {/ D4 B, _$ M3 I3 Q4 P
  18.   DHT11_DQ_OUT_LOW;         //拉低* |& E" [2 D5 _$ Z' C" o9 V
  19.   HAL_Delay(20);            //至少18ms+ f: N% k3 r) l! q
  20.   DHT11_DQ_OUT_HIGH;         //拉高
      Z9 n. G5 ]9 j/ s' U# Z
  21.   delay_us(30);             //至少20~40us: S6 }, C% K2 h9 h! z
  22. }
    7 N( D- Q( O3 f: A( I

  23. ( F  }  T: I0 q* a
  24. uint8_t DHT11_Check(void){   
    , b& T+ ]! d7 M; N# j% k
  25.   uint8_t retry=0;
    7 A4 J( W0 _+ B: `- T
  26.   DHT11_IO_IN();      : u. u% U. P8 i: M
  27.   while (DHT11_DQ_IN&&retry<100){ //拉低40~80us
    1 [  t1 Q/ |/ V
  28.     retry++;
    & Y( \5 N& e" ?3 [1 u1 }
  29.     delay_us(1);
    # }' Y; ~' p- {
  30.   };         / W' N2 a# Y" |% s' e- [- T. G- i9 F
  31.   if(retry>=100)return 1;/ x9 P' I1 v. x0 I
  32.   else retry=0;1 W: B7 R0 h+ ^
  33.   while (!DHT11_DQ_IN&&retry<100){ //拉高40~80us
    ) l4 m2 n+ B6 l$ o+ H6 M0 r7 t
  34.     retry++;, E- E. r; D4 F; |# i4 V
  35.     delay_us(1);$ X+ V* p0 q+ q
  36.   };
    ) y+ W* g0 U3 o$ i! H1 g' d
  37.   if(retry>=100)return 1;            
    1 l. H4 X5 [: h, Y& P& Y
  38.   return 0;        //检测到DHT11返回0
    5 w& ?6 O) h3 ]2 q8 M
  39. }6 O" C0 @/ q7 m6 n) e
  40. % Y2 N9 k1 Z" k0 E. |! k7 ]0 ?1 F
  41. uint8_t DHT11_Read_Bit(void){! @$ f" H: q/ w* u4 [% R- \: }$ l
  42.   uint8_t retry=0;
    ( Z+ M* |4 B) w. i9 Y
  43.   while(DHT11_DQ_IN&&retry<100){//等待变为低电平# y: K& \% B! z
  44.     retry++;+ o+ r0 M+ u. D/ x) p9 d! t
  45.     delay_us(1);0 T# @4 p) [; B0 {0 |) l! P* A
  46.   }( h  N- u) B" o% E
  47.   retry=0;. L, c0 Y# s: N5 @4 K
  48.   while(!DHT11_DQ_IN&&retry<100){//等待变为高电平
    5 b+ c* S6 t$ p# u3 D5 v2 z
  49.     retry++;9 P6 W, \) {! m9 r7 B: {
  50.     delay_us(1);6 f5 J6 s! o$ c' c$ I" t9 [" ]* A
  51.   }
    & Z( {; V: K5 v+ N2 p" I5 h
  52.   delay_us(40);        //等待40us" A5 A+ L$ Q$ U8 u$ C9 c
  53.   if(DHT11_DQ_IN)return 1;1 F5 j- s/ L+ T8 c2 U' c/ ~3 q
  54.   else return 0;                  
    : L3 O# [2 ]& G) Q9 E. \8 Z
  55. }& d) C  K; Q/ Z8 o* i9 X( z- `

  56. 9 m% h: c% h4 h8 [  z8 r$ ~
  57. uint8_t DHT11_Read_Byte(void){        
    7 w9 f. E5 e4 N1 J
  58.   uint8_t i,dat;4 g( d  ~. P0 [4 U9 A
  59.   dat=0;
    ( g, j: u6 o! k" x% M5 I
  60.   for (i=0;i<8;i++){5 A& \& k* J. n
  61.     dat<<=1;
    1 U% {" g9 U+ G) i- w) w
  62.     dat|=DHT11_Read_Bit();/ b1 k! i/ t" {5 ]: v* G
  63.   }                                                    
    ; Y5 u" t% Q6 b2 y# J
  64.   return dat;
    + W* t9 ]2 h+ C8 |$ k8 z
  65. }
    9 |4 b  N- ]  Q& e7 o& R
  66. * r' Y: z; \+ A( m+ B! w
  67. uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi){        7 g, L1 [/ V: O+ `/ G6 |
  68.   uint8_t buf[5];
    9 V" e* }* r/ b3 D' o4 O
  69.   uint8_t i;3 T* [0 s& T1 @7 g
  70.   DHT11_Rst();
    $ f5 J* W; b+ Q
  71.   if(DHT11_Check()==0){
    3 @6 y" b0 J* [5 r
  72.     for(i=0;i<5;i++){- h+ V1 \+ b3 K
  73.       buf[i]=DHT11_Read_Byte();
    ' H9 v; T* S- ]
  74.     }
    1 y/ f6 S. J8 T- g6 x
  75.     if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){
    5 C6 B7 I" v7 x8 R2 v! q
  76.       *humi=(buf[0]<<8) + buf[1];
    . i* b8 l! a4 D; l/ l
  77.       *temp=(buf[2]<<8) + buf[3];4 s# |* ]9 ~- \7 B
  78.     }: x- F8 E" C1 o) U% d) N6 w, h& `
  79.   }else return 1;, e' m0 e; X) l) X3 n
  80.   return 0;            2 W$ E. ^) H' ^3 \
  81. }% D' J0 `2 h  h- d6 n
  82.            4 B- H8 P5 T" B- x/ _
  83. uint8_t DHT11_Init(void){
    # O4 e/ y' W. d' n/ z; E2 d6 c
  84.   //PG11的初始化已经在cubemx中完成,可以忽略此段初始化代码( V: @2 I( L6 D# C. r
  85.   GPIO_InitTypeDef GPIO_Initure;        4 ~) W# C9 w" z1 K
  86.   __HAL_RCC_GPIOG_CLK_ENABLE();                        9 J% K8 u. W* h& x
  87.   GPIO_Initure.Pin=GPIO_PIN_11;           , b& k; ?5 W: g4 N
  88.   GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  
    7 a+ p1 d5 R5 o6 K
  89.   GPIO_Initure.Pull=GPIO_PULLUP;         ; B' p4 h: h6 x* R
  90.   GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;( N3 n/ u& ?8 V% Q2 ]7 i
  91.   HAL_GPIO_Init(GPIOG,&GPIO_Initure);   
    ' v1 _1 x; a$ O8 G8 i- S0 Y# Y
  92.   DHT11_Rst();
    : R9 B* z/ c; \3 V# a7 s0 I
  93.   return DHT11_Check();# o7 _4 Y8 g$ s; F: }
  94. }
复制代码
( P. ~; e: h+ X4 V; W2 U
➡️ 在main.c文件下编写DHT11测试代码
  1. int main(void){9 X8 Z# k* M6 X) n
  2.   /* USER CODE BEGIN 1 */
    7 I3 [, J3 t; f; r% D+ ?! D
  3.   uint16_t temperature;
    % y# N. f! U& Q4 b3 \* q  [( }* }
  4.   uint16_t humidity;
    9 T3 r4 l6 a* Y5 h2 y2 Z+ u3 Y
  5.   /* USER CODE END 1 */
    % Z. b: \. A1 V3 [3 n. w
  6.   HAL_Init();$ \6 h" J  ?; k3 _: Q
  7.   SystemClock_Config();
    " B+ K: K& l' V* O8 e8 i8 K- x- ~- x' H
  8.   MX_GPIO_Init();1 |2 Q8 l( R0 i$ Y
  9.   MX_TIM7_Init();& j, l; V0 G" e; l9 t% s3 U
  10.   MX_USART1_UART_Init();6 m* r, Z4 [5 J3 O
  11.   /* USER CODE BEGIN 2 */
    ( T: g; ^  s& u8 V
  12.   while(DHT11_Init()){
      ]5 H  r' ^* a( X& _
  13.     printf("DHT11 Checked failed!!!\r\n");
    ' T/ k" F% c% T% n1 ?. Q5 X2 ?
  14.     HAL_Delay(500);
    ( D+ s3 J1 W; o8 o: s1 b8 X5 r
  15.   }; {5 \- f( k, V# k) t8 B: r( |
  16.   printf("DHT11 Checked Sucess!!!\r\n");) \% E7 Y8 S# R' [2 Y, B
  17.   /* USER CODE END 2 */$ m& P/ |8 z+ a- Z
  18.   while (1){
    6 G* N+ j6 e  b- S; q
  19.     DHT11_Read_Data(&temperature,&humidity);
    % G1 b6 ~0 [& I% [
  20.     printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
    : N1 \# L8 g* v7 m& D2 G
  21.     printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);                ! [& s9 X9 \/ I( L
  22.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);: }" [8 Z8 B" O
  23.     HAL_Delay(500);
    2 A- y2 m, s" u9 o/ k$ ]* V  N7 k5 |
  24.   }
    # O% K- z4 y& v5 \- y6 V$ U' Y- g: X$ p
  25. }
复制代码

* a1 K+ ]4 `7 z9 F$ X  P, V, v5 I
4.下载验证
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,串口不断打印出当前温湿度值。串口输出如下信息:
DHT11 Checked Sucess!!!
DHT11 Temperature = 28.20 degree
DHT11 Humidity = 30.21%
转载自: 嵌入式攻城狮
( J! B- [4 t/ i) G% U4 x7 G如有侵权请联系删除' \: k* k7 ^& B. x4 p4 T+ Y

. h- J/ s0 @4 O! {* K- M0 P1 N
& A2 Z! ~( Y8 ]! n9 J) d$ b7 T
赞 收藏 评论0 发布时间:2023-7-1 18:18

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版