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

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

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

( H2 [$ a; L( B' {$ O' I* N5 R- s
根据以上数据,即可算出温度和湿度的值,计算方法如下:
湿度 = byte4.byte3
温度 = byte2.byte1
校验 = byte4 + byte3 + byte2 + byte1

) O. q) q/ Q* n9 g
DHT11和单片机的一次通讯最大为3ms左右,建议主机连续读取时间间隔不要小于100ms,下面是DHT11的三种时序:

- {# \1 Z: q6 |8 }0 N) k
⏩ 数据发送时序
首先主机发送开始信号,即拉低数据线保持t1(至少18ms)时间,接着拉高数据线t2(20 ~ 40us)时间;然后读取DHT11的响应,正常的话DHT11会拉低数据线并保持t3(40 ~ 50us)时间作为响应信号,接着DHT11拉高数据线并保持t4(40 ~ 50us)时间后,开始传输数据

: O. ^/ U4 y9 {7 L) {/ e
微信图片_20230701181742.png

! V& X6 H# }4 @: n2 B) x" [/ r
⏩ DHT11输出0时序

- Y/ d# B0 I5 y( I
微信图片_20230701181739.png
4 @+ w0 k; ?) ~% K
⏩ DHT11输出1时序
. t7 q% o+ g2 X0 Q5 _  J
微信图片_20230701181736.png

. S: `$ T# }, i9 F
& J3 O: M* h* b
2.硬件设计
& k+ w' }- H; `! g9 ^3 p
D1指示灯用来提示系统运行状态,DS18B20温度传感器用来检测环境温度,串口1用来打印温度值
指示灯D1
USART1串口
PG11
TIM7(提供us延时)

* v5 n9 r% w9 F/ }; q8 K& Z* }' K

$ W% P9 O0 q  q& z2 p
3.软件设计
3.1 STM32CubeMX设置

  F" k$ V. {9 Y7 }5 p3 m% C
➡️ RCC设置外接HSE,时钟设置为72M

; N( F: W; Y5 B2 l& X9 b7 G' ~/ x4 Y2 T
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平

; q1 a- s! M' o( n4 \  i& |
➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
+ u- u. n2 T- L# w# }
➡️ PG11设置为GPIO推挽输出模式、上拉、高速

8 {+ F6 i3 @% H' i
➡️ 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us

9 N/ g! R1 _' a4 u1 w7 N
微信图片_20230701181727.png

& X4 W6 D  v# z9 ^
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

6 S4 e3 g6 v2 z, _" _& S$ u+ R
3.2 MDK-ARM软件编程

6 X7 M% x3 J8 K+ b; j1 D7 Z) V0 J
➡️ 在tim.c文件下实现微秒延时(us)函数
  1. void delay_us(uint16_t us){
    8 F6 H5 Q1 Y2 y, s) _2 k
  2.   uint16_t differ = 0xffff-us-5;
    + a+ q4 }2 Q( a% E2 ~
  3.   //设定TIM7计数器起始值                               
    # o- I* C* w) E3 k$ m
  4.   __HAL_TIM_SET_COUNTER(&htim7,differ);
    , ?% N( e% r  F5 B% k2 x2 c
  5.   //启动定时器        , r1 U) P& B/ s# B
  6.   HAL_TIM_Base_Start(&htim7);                        1 W2 N, K6 A4 l3 e" k3 X1 `& K
  7.        
    ) `- i1 ^$ F( ?# ^& |  |. {
  8.   while(differ < 0xffff-5){        //判断
    " o( A, w" K! @' T# v6 x) a0 d4 H
  9.     //查询计数器的计数值
    * l/ M& k! n: n4 u
  10.     differ = __HAL_TIM_GET_COUNTER(&htim7);               
    " W: c. Y! v! h! ]2 k& `
  11.   }
    / `5 D# p1 m+ m
  12.   HAL_TIM_Base_Stop(&htim7);% I4 A# k4 U% c/ J+ s6 M
  13. }
复制代码

/ A+ \( `0 D) W! x. [' }
➡️ 创建DHT11温湿度传感器驱动文件DHT11.c 和相关头文件DHT11.h
  1. void DHT11_IO_IN(void){  //IO口方向设置为输入  A2 e- c1 l$ G% a
  2.   GPIO_InitTypeDef GPIO_InitStructure;! `8 p9 Y! u# o
  3.   GPIO_InitStructure.Pin = GPIO_PIN_11;: K6 Z) B$ y4 X, d& P7 r. A4 h
  4.   GPIO_InitStructure.Mode = GPIO_MODE_INPUT;) K  a( {3 ~# g, ^
  5.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);
    1 l; c: K4 }% b+ g% [+ x" y
  6. }6 G* \3 g& E: I. [5 t

  7. 1 a! a( e- n) q: ^
  8. void DHT11_IO_OUT(void){  //IO口方向设置为输出
    % @, o; Z  ^3 I% w$ l- P( N) S
  9.   GPIO_InitTypeDef GPIO_InitStructure;% n7 y4 h( O& N" e
  10.   GPIO_InitStructure.Pin = GPIO_PIN_11;0 d2 J- b- z5 Y
  11.   GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;+ h1 I" n% [$ C& _
  12.   GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    2 T% W' r* u- b
  13.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);
    5 d+ }0 |& j, t; M+ [1 S* ~0 h
  14. }
    " R5 D. G" K$ t2 C& U2 ~; h

  15. & G: Z! I. N5 Q* j
  16. void DHT11_Rst(void){                 ) u2 _) K, K8 t8 _1 J' I# v
  17.   DHT11_IO_OUT();         //设置为输出
    " ~* \8 t7 z5 e8 V5 l
  18.   DHT11_DQ_OUT_LOW;         //拉低% E& O) N& ^1 E1 t( k, ~; g4 K& B0 z
  19.   HAL_Delay(20);            //至少18ms
    ; P& v' i3 @* q* h# g! d
  20.   DHT11_DQ_OUT_HIGH;         //拉高 1 m7 R7 s: J5 \. r) V* F
  21.   delay_us(30);             //至少20~40us
    & L1 m3 X0 o2 L& t% K8 ^& D
  22. }' U- A3 k% H$ q! l) i! {
  23. " R9 x; h) m7 j# ]
  24. uint8_t DHT11_Check(void){   
    7 c6 l1 N* K. D- P1 T& |2 |8 d) G
  25.   uint8_t retry=0;" V9 r9 P' \7 f  J6 I
  26.   DHT11_IO_IN();      & F; M, v* r0 i& G5 q5 J
  27.   while (DHT11_DQ_IN&&retry<100){ //拉低40~80us
    3 k, z% j; u1 c
  28.     retry++;
    , Q  s* H! j0 S1 }
  29.     delay_us(1);# q. G  B! B2 F. v9 R1 V. [/ h
  30.   };         5 H; V! a: R: H1 [& f# |
  31.   if(retry>=100)return 1;
    2 g4 l6 x! ~5 ~0 {! b4 Z3 e
  32.   else retry=0;
    * m, n! F, j, L: x/ {
  33.   while (!DHT11_DQ_IN&&retry<100){ //拉高40~80us
    3 O" Z& F4 c0 c7 l3 ]7 Q
  34.     retry++;# i. f, r% Z5 E/ v! f- i
  35.     delay_us(1);
    1 S" h2 r/ N8 X/ F' F
  36.   };
    4 G- N% [, V8 I# j& X
  37.   if(retry>=100)return 1;            + h3 h3 X- ^! I$ G8 R7 C  [
  38.   return 0;        //检测到DHT11返回0
    & {% x5 a, _- p9 w
  39. }
    + E2 Q% z; b2 ?, O
  40. 3 M) k* h* p4 z  X6 L4 K
  41. uint8_t DHT11_Read_Bit(void){" G6 [; Q5 X) n, |
  42.   uint8_t retry=0;( R4 F: O9 m+ X  |
  43.   while(DHT11_DQ_IN&&retry<100){//等待变为低电平
    / [3 f6 m* T6 r$ P" a4 _2 Z$ o) U5 I$ l
  44.     retry++;
    # M' i' g: \, G! {9 i, v
  45.     delay_us(1);
    3 W' r9 `* q- O6 B5 N
  46.   }
    % P' g9 j% p6 I: h6 O& l. a* T
  47.   retry=0;) M# B$ Q" [- U" a2 q2 {* R3 m4 @
  48.   while(!DHT11_DQ_IN&&retry<100){//等待变为高电平& E; o5 T8 [1 V; f9 k& b3 m
  49.     retry++;0 i/ d6 s" P1 N0 B  t' P9 _
  50.     delay_us(1);
    % s+ }" y4 `0 ?" w8 [: O* C; v$ O
  51.   }
    / ^) {! n% b7 P' b  k- |* f
  52.   delay_us(40);        //等待40us9 B* |3 z9 v: J, b: d
  53.   if(DHT11_DQ_IN)return 1;1 e+ W- e. e+ ^. {/ l
  54.   else return 0;                  
    - r2 ]# l/ Q( _! y
  55. }
    3 t" e( L4 s% ^4 F$ S5 `

  56. / k& r5 Q1 R% |, ?( Z# h
  57. uint8_t DHT11_Read_Byte(void){        - {1 F1 M# d7 s: r( q8 m* o; s; ^
  58.   uint8_t i,dat;
    * c  b* P! \% t2 y/ _- v
  59.   dat=0;
    . w: K+ I7 \% ^$ u% K
  60.   for (i=0;i<8;i++){
    ) c9 p! h- `( ?$ t6 k' M
  61.     dat<<=1;
    ' n- k% y! J8 l9 ?% C/ K
  62.     dat|=DHT11_Read_Bit();
    8 Y4 k! B; U# M$ A
  63.   }                                                    1 I5 U* x# t1 q% K3 _
  64.   return dat;
    " W! U5 Q3 l# n( Y7 j- S4 V
  65. }
    2 F% C) ^0 X) T

  66. # N9 ~4 n  {6 d4 H* N" h* \% r
  67. uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi){        
    ! \& S& \. u( u0 }
  68.   uint8_t buf[5];% R; V3 r2 m4 \" m. w% P: ~
  69.   uint8_t i;
    ' ~$ Y, X  K% z, p! s4 S" F
  70.   DHT11_Rst();
    8 v% E) b$ }6 l! G! U5 ]
  71.   if(DHT11_Check()==0){
    & X" b: y8 C9 @" g0 I
  72.     for(i=0;i<5;i++){7 w- K9 u# x. ]) E1 b  K# x& K/ E
  73.       buf[i]=DHT11_Read_Byte();
    & {# J" [9 L% d, ?
  74.     }0 {) K2 ~" F' d4 t: i) h+ c
  75.     if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){& f; C" u& ~# P" x
  76.       *humi=(buf[0]<<8) + buf[1];
    8 M$ b4 I3 Z# s' U' k; c
  77.       *temp=(buf[2]<<8) + buf[3];
    9 K, w' u9 ?' @, W" P
  78.     }
    ( y: N3 W7 a- S) B7 M
  79.   }else return 1;
    9 x3 y% y  s8 u5 y+ Z
  80.   return 0;            
      E5 R# H. I% b# e1 ~
  81. }' }& k2 k- z: @: L' G
  82.            * o) b7 S( C. G# U/ |
  83. uint8_t DHT11_Init(void){
    4 X. J5 @7 s* I  S, y  s  r
  84.   //PG11的初始化已经在cubemx中完成,可以忽略此段初始化代码& V$ }* R+ V) u( i
  85.   GPIO_InitTypeDef GPIO_Initure;       
    ! Q  o' ^8 E) q* |
  86.   __HAL_RCC_GPIOG_CLK_ENABLE();                       
    + W" C$ i7 a& @* ^
  87.   GPIO_Initure.Pin=GPIO_PIN_11;           9 d# x, p3 }: N, l  `- s6 k  v
  88.   GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  3 A4 c% j: d6 L3 P/ f
  89.   GPIO_Initure.Pull=GPIO_PULLUP;         0 h# _9 ^! f! O8 P% {, B
  90.   GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;7 }4 }/ p. ]. N. ]# r
  91.   HAL_GPIO_Init(GPIOG,&GPIO_Initure);    * b7 N6 {6 t) r6 r! x; g8 \) w
  92.   DHT11_Rst();4 b2 ~/ _) b* e9 W! Y# r
  93.   return DHT11_Check();
    " s+ i+ i& ]6 e* C6 W
  94. }
复制代码

' X; d9 }1 |7 A. ?  B( X; ?" U
➡️ 在main.c文件下编写DHT11测试代码
  1. int main(void){; E4 v5 z+ u; @4 O6 F; V
  2.   /* USER CODE BEGIN 1 */
    6 [$ o1 p$ \* g; e# X
  3.   uint16_t temperature;7 c4 {) N) I8 {4 S4 q
  4.   uint16_t humidity;
    6 y  f3 a. r1 n8 V
  5.   /* USER CODE END 1 */  y! E# G4 Y9 N% ]" c" L
  6.   HAL_Init();  Y, \9 x  q7 k
  7.   SystemClock_Config();; E# p. A- q6 i  y" \2 [, A$ V) s
  8.   MX_GPIO_Init();
    , `- g! j# ]- f
  9.   MX_TIM7_Init();) I$ @7 l( {6 n
  10.   MX_USART1_UART_Init();
    9 N0 s$ C# u0 E. m6 y  E
  11.   /* USER CODE BEGIN 2 */9 }5 x: Y3 R; [; w7 h- _! Q' ?, o
  12.   while(DHT11_Init()){# J/ |+ j" M; ]: {% c6 u1 Q$ _2 R
  13.     printf("DHT11 Checked failed!!!\r\n");! }/ {0 n" q% g2 F
  14.     HAL_Delay(500);( {/ g5 v3 _0 O; Q
  15.   }
    % a3 V: I* U: M7 a
  16.   printf("DHT11 Checked Sucess!!!\r\n");
    + u) R! b" Q0 M) E6 j$ Y# {5 x
  17.   /* USER CODE END 2 */
    & _9 g5 \) g$ J& \
  18.   while (1){. r; v4 s1 h1 P9 I0 q$ a) B% j
  19.     DHT11_Read_Data(&temperature,&humidity);
    * s+ s! I$ L+ l* q/ k- _
  20.     printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);: K+ u: Q& I) |& {% T. W* z
  21.     printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);               
    1 y$ H( h$ g+ l# t# N. G* ]& ]
  22.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    2 Q: E$ k; {. r. E6 q
  23.     HAL_Delay(500);
    # V/ A* S8 y0 L: x9 k9 `
  24.   }
    ! ~' c, l7 n9 H# k5 ?
  25. }
复制代码
" O$ V* ?$ u; |2 k8 H& x- L
4.下载验证
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,串口不断打印出当前温湿度值。串口输出如下信息:
DHT11 Checked Sucess!!!
DHT11 Temperature = 28.20 degree
DHT11 Humidity = 30.21%
转载自: 嵌入式攻城狮/ z. t0 o% k& r* K, a7 w5 @
如有侵权请联系删除
# J6 y  t/ o2 S4 m8 w& O0 X" B+ e. v' X6 ^
5 m) {0 G8 V2 h5 \0 _: Q
赞 收藏 评论0 发布时间:2023-7-1 18:18

举报

0个回答

所属标签

相似技术帖

官网相关资源

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