|
1.DHT11简介 DHT11是一款温湿度一体化的数字传感器,该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机连接。通过单片机微处理器简单的电路连接就能够实时的采集湿度和温度。DHT11与STM32之间能采用简单的单总线进行通讯,仅需一个IO口。传感器内部温度和湿度数据40个bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。 DHT11采用单总线数据格式,即单个数据引脚端口完成输入输出双向传输。其数据包由5个字节(40Bit)组成。数据分小数和整数部分,一次完整的数据传输为40bit,高位先出。数据格式如下图示
; a/ F7 \) L3 F5 r {7 t
1 p6 n4 F- T1 N7 P7 n# B9 s
根据以上数据,即可算出温度和湿度的值,计算方法如下: 湿度 = byte4.byte3 温度 = byte2.byte1 校验 = byte4 + byte3 + byte2 + byte1 0 ~/ \$ V0 M E, D+ z$ `
DHT11和单片机的一次通讯最大为3ms左右,建议主机连续读取时间间隔不要小于100ms,下面是DHT11的三种时序: 1 Y! h1 a+ C& `" b9 h: h
⏩ 数据发送时序 首先主机发送开始信号,即拉低数据线保持t1(至少18ms)时间,接着拉高数据线t2(20 ~ 40us)时间;然后读取DHT11的响应,正常的话DHT11会拉低数据线并保持t3(40 ~ 50us)时间作为响应信号,接着DHT11拉高数据线并保持t4(40 ~ 50us)时间后,开始传输数据 % z! F( f8 J: f9 }
( c, n! \# G2 J5 \
⏩ DHT11输出0时序 8 v3 F- A; @2 W# z) o8 Q
# C& P9 H. {3 K: {5 D
⏩ DHT11输出1时序 : s; x5 y% u4 t, W
" i0 x7 |: ~) p. v/ n; J0 _
; _- M2 O2 M# ]. B/ T3 T- J0 k6 U ]
2.硬件设计
1 f- T) H: Y! S8 Y. o/ J aD1指示灯用来提示系统运行状态,DS18B20温度传感器用来检测环境温度,串口1用来打印温度值 指示灯D1 USART1串口 PG11 TIM7(提供us延时)
: o9 z) w) \4 w+ M1 w! H6 L ) T3 Q1 p; w( ~5 l$ W! {
3.软件设计 3.1 STM32CubeMX设置
) x ~9 k4 i) u
➡️ RCC设置外接HSE,时钟设置为72M
/ ~3 ]1 n9 ^1 X% L. { ~1 H
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
% s5 C3 p2 Y7 ~; p+ h$ a
➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位 ' z: _% s9 J j. u& ^+ e0 R5 V
➡️ PG11设置为GPIO推挽输出模式、上拉、高速 $ a$ S$ I8 Z, V, ^1 O
➡️ 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us
1 X* M. P' V, r+ H& I
. u+ c. t8 |& H) S; ]
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
" l$ b( v) |* N `( ]7 P3.2 MDK-ARM软件编程 3 d6 T( ]7 K+ D4 [; q" ~
➡️ 在tim.c文件下实现微秒延时(us)函数 - void delay_us(uint16_t us){
) C6 ?9 ?5 g; Z" r - uint16_t differ = 0xffff-us-5;9 L3 a9 u" z5 A) o, n. a
- //设定TIM7计数器起始值 * X9 N4 q) L8 n
- __HAL_TIM_SET_COUNTER(&htim7,differ);
' l9 S8 k2 X# M( f, G% g+ H* H - //启动定时器 0 v" ]3 { {# j4 E
- HAL_TIM_Base_Start(&htim7); + l3 j/ n6 u5 x; F- q1 E" Y3 b
- # y: l6 f! R4 P( K/ f4 X9 H
- while(differ < 0xffff-5){ //判断. `6 u5 X4 @# q& o' y+ k* E5 Q
- //查询计数器的计数值( {! p6 A! x0 [# h
- differ = __HAL_TIM_GET_COUNTER(&htim7); " i- v2 G, c- `( r' f
- }
/ a: v" W' z- Y - HAL_TIM_Base_Stop(&htim7);
) ~% K1 G5 a" ~ - }
复制代码
4 ^4 e) h4 c" F% s5 f! A( K➡️ 创建DHT11温湿度传感器驱动文件DHT11.c 和相关头文件DHT11.h - void DHT11_IO_IN(void){ //IO口方向设置为输入
- F w* N) ?3 e - GPIO_InitTypeDef GPIO_InitStructure;1 P, p* M# k: i7 E
- GPIO_InitStructure.Pin = GPIO_PIN_11;+ ?, X- R0 l$ G& r
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT;: r0 v1 O! O. l Z
- HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);' n. A0 w! n9 a$ ^. R) F7 A
- }
& V* Z; v# N* L - 4 A P5 A7 t% V8 Z
- void DHT11_IO_OUT(void){ //IO口方向设置为输出
% j( @' F% A6 D3 @, V$ v6 \ - GPIO_InitTypeDef GPIO_InitStructure;" }+ F8 ]8 r$ d6 i3 v
- GPIO_InitStructure.Pin = GPIO_PIN_11;
$ @1 z& Y- i }! Z5 A - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;9 {9 m! }) @9 C4 T; d4 |
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;6 H0 y$ i# ~: `: H4 _. E1 G. n
- HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);
! ^, U0 I2 H, E0 S - }
" f8 q" ^+ N2 B$ c1 u8 d* G
" G9 ]$ v; }7 g2 u# X* a- void DHT11_Rst(void){
% {" j F9 ]" N2 k8 i( J - DHT11_IO_OUT(); //设置为输出( l7 L, g" ]" o$ {& Q1 ]& P
- DHT11_DQ_OUT_LOW; //拉低1 h2 c+ g% j3 z* ^! h) z. c
- HAL_Delay(20); //至少18ms% E3 Z$ b( p" v3 h, [
- DHT11_DQ_OUT_HIGH; //拉高
x7 ~7 P8 h3 I/ Z$ z* V* [( {0 F, P - delay_us(30); //至少20~40us2 X/ m ?% T8 S
- }
; y; ?, p; ]. z% l$ h
! F5 y( _% q9 m, ?- uint8_t DHT11_Check(void){
' l6 n- I5 E. g' r) H - uint8_t retry=0;
, J) w8 G4 ~( J% V - DHT11_IO_IN(); , ^, g+ Y5 Q: w$ S X+ f+ }
- while (DHT11_DQ_IN&&retry<100){ //拉低40~80us
% |' h/ c2 G0 {; Z$ V - retry++;
1 P0 z. ], F9 k/ Z+ i - delay_us(1);1 b$ C2 n0 B1 H* l
- };
8 m% r' ?+ k3 g) \5 t% n - if(retry>=100)return 1;3 n/ C8 I5 u- b: T0 e6 `
- else retry=0;
( A7 X" J% Y3 k+ W - while (!DHT11_DQ_IN&&retry<100){ //拉高40~80us! U& q& G) e7 C. Y
- retry++; T. f+ L2 g6 G' i9 v0 X2 V
- delay_us(1);3 e8 [& }; y* b ^8 k6 R- ?* f0 x& W
- };
3 s+ z/ R3 f/ b | - if(retry>=100)return 1; 5 e. W. P) Z- ]+ |5 ^
- return 0; //检测到DHT11返回0! P: B% _0 r0 |$ q8 v
- }8 n* x/ }& [( H1 e$ S
- 7 L! h; M7 f* a4 \! O1 L
- uint8_t DHT11_Read_Bit(void){* l- T, D0 E" u! |8 k- d% F' r
- uint8_t retry=0;
' R3 x+ R' E# @; i. o3 B9 \ - while(DHT11_DQ_IN&&retry<100){//等待变为低电平$ ^) l. p* k X( w
- retry++;9 }1 D. ?% P! j/ p. P8 ?
- delay_us(1);
5 W! D& S. a9 g - }# T) b; V' \: _0 h/ h
- retry=0;
9 S( O$ s Z! V% ]8 @, J: Y - while(!DHT11_DQ_IN&&retry<100){//等待变为高电平
; B, n( u) @ a1 p8 G' z - retry++;
, _1 A% n1 \! W" T - delay_us(1);' z" ^% z( u( w* i4 Y4 t+ t8 t
- }9 x; B3 F) ?, G g, }
- delay_us(40); //等待40us( n T' b7 x) f4 T. C
- if(DHT11_DQ_IN)return 1;
0 l% L: z2 G( a6 p - else return 0; / D/ Y% j0 ?# e9 J
- }6 @0 V" P. o' |. v- G0 i( |
- * U. g1 h O- L! r
- uint8_t DHT11_Read_Byte(void){ 9 c0 p6 B% S ?+ {
- uint8_t i,dat;
* p( [, v8 k/ X( T4 \ - dat=0;+ t. t$ B( [8 N- M
- for (i=0;i<8;i++){5 G: O/ h# j" J
- dat<<=1; # n- [! l8 u* k0 {& n. k: k: ?
- dat|=DHT11_Read_Bit();9 o" v/ O9 R8 H
- } # g% i* b: w$ J* o- h
- return dat;
* `* k/ e% X1 t* u ]$ G% x0 T! E - }
8 u, M" ^( }! l3 U, I
! V/ A1 A% w- M# k; h- uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi){
( L; i5 F; Y; T- A: b+ L - uint8_t buf[5];
; h7 r6 v( B& ~. L: c/ n4 V" j/ ?; p - uint8_t i;
4 U' j# ^, o$ |& { - DHT11_Rst();
8 ?8 {; z) ]' J; V3 f - if(DHT11_Check()==0){3 {+ c- M& n' `1 g: }
- for(i=0;i<5;i++){' t& T+ K9 B( ?+ _) V' j
- buf[i]=DHT11_Read_Byte();
4 a4 R5 }3 U& ]/ C) E! } - }
% ]) [. T i+ h% M. q, D4 J - if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){
& \& w1 }1 L8 M. G; { - *humi=(buf[0]<<8) + buf[1];! q+ Y s5 E% `- i) z
- *temp=(buf[2]<<8) + buf[3];7 V5 S6 ]6 S! y W+ @
- }- B5 t8 H) A; u' W
- }else return 1;
`: W) s6 d3 z+ l* b( n" G - return 0;
3 `9 J2 \( L( u, V6 _* P, _ - }- t" i' Z! x9 ~- [/ c5 T
- - x7 C1 | G9 M4 [% h) X- q6 ~' \
- uint8_t DHT11_Init(void){/ _7 z0 V$ e5 I5 D$ J! L
- //PG11的初始化已经在cubemx中完成,可以忽略此段初始化代码% G' M: S- t( E# v6 v8 U" V9 `
- GPIO_InitTypeDef GPIO_Initure;
) ^$ D# H7 \. ?. d. |* L - __HAL_RCC_GPIOG_CLK_ENABLE(); , z) b5 m5 c1 j) R1 b" J
- GPIO_Initure.Pin=GPIO_PIN_11;
, q) L F0 F$ A! Z! z! \ - GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; , ~' F5 a, l. u
- GPIO_Initure.Pull=GPIO_PULLUP;
/ X3 a- s: `" @ - GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;
: }5 n4 j8 V, i) o& ? - HAL_GPIO_Init(GPIOG,&GPIO_Initure);
5 o) z: y$ m- l1 R! ?) ~1 H - DHT11_Rst();
, X! a, v, R+ d$ W# U - return DHT11_Check();, R8 J2 O0 O' l+ y3 Y; V5 l8 j7 j4 k
- }
复制代码
, Y! s2 h5 _! N: G2 `5 o# x➡️ 在main.c文件下编写DHT11测试代码 - int main(void){
`: z: ?1 e( n6 X9 z- c8 O - /* USER CODE BEGIN 1 */
7 i! ]3 R$ i0 ~" C( }* h4 C - uint16_t temperature;3 C0 t- C3 B# V( ?
- uint16_t humidity;8 |; T& H* C. O0 V
- /* USER CODE END 1 */# b" @8 V9 r+ O( o4 B8 t2 E
- HAL_Init();; G& R* B9 d7 o" R3 ~8 ]/ T" q, }
- SystemClock_Config();% D! B" m) z5 _( S- M
- MX_GPIO_Init();
# {7 ^" B3 m+ {" M- A1 d1 a - MX_TIM7_Init();4 x$ c5 Q5 C9 O) K& E3 C! y& t, I
- MX_USART1_UART_Init();
% F6 T ?5 R! u/ q- h/ X - /* USER CODE BEGIN 2 */
% Y3 O$ A9 s" r# P. m3 q - while(DHT11_Init()){5 r& z8 ?7 d2 [7 D+ b4 ^. v6 {
- printf("DHT11 Checked failed!!!\r\n");
' k) M$ `9 O) h+ M - HAL_Delay(500);! W p+ e3 Z8 }0 t0 [& A4 s# `
- }7 @5 h" P# F2 Z% {1 T, P/ `, h9 q0 H4 ]
- printf("DHT11 Checked Sucess!!!\r\n");& r. `) I+ \( p) |
- /* USER CODE END 2 */& t, g3 q" x3 z% U0 O
- while (1){
6 m% g7 W% P. }5 v) B - DHT11_Read_Data(&temperature,&humidity);
1 h4 ^9 K* A% H* u9 A& F - printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
& y. f/ U3 h3 [$ h. C9 c - printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);
# H: ?" R% f- t6 s2 E7 { - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
; R0 b7 o. \* i! G - HAL_Delay(500);/ z# p) {- _3 \, j0 t) n3 m
- }) }; c6 ^, X$ ~; Q; x/ F: z
- }
复制代码
6 p: b! e$ v/ F$ l1 D) u5 F7 J4.下载验证 编译无误下载到开发板后,可以看到D1指示灯不断闪烁,串口不断打印出当前温湿度值。串口输出如下信息: DHT11 Checked Sucess!!! DHT11 Temperature = 28.20 degree DHT11 Humidity = 30.21% 转载自: 嵌入式攻城狮( M; u C/ }6 B; D
如有侵权请联系删除7 I! H5 w# ^9 T# x; I. d( D2 z: d+ B
8 e0 G' `* S1 e+ ]& _: h( U* d$ O6 H& n2 N4 j% x0 |
|