参考文章:《DHT11详细介绍》:http://t.csdn.cn/L0M3r
本文实验平台:MM32F527x平台验证通过
开源器件这个系列将记录一系列我接触到的各种器件驱动模块,现在开源的资料众多,编程已经是基于模块化的思想,尤其是Arduino、Micropython等语法简单的开发语言的入局,大大降低了开发者开发难度。对于最经典的32位产品STM32而言,意法半导体公司也停止了标准库的更新,转而投入HAL库开发。以上无一例外是隐藏了部分底层原理结构换取调用的便捷性,这种对用户友好的做法很大程度上会带来系统性能的牺牲。接下来的这款DHT11的开发虽然简单,但是debug过程也遇到了一些与性能有关系的问题值得记录,与其让它烂在网盘里,不如发出来可能会对别人有所启发。
DHT11工作时序
DHT11采用单总线通信方式,过程为: 1
主从机引脚初始化,主机拉高总线至VCC,从机高电平下无应答; 2
主机发出通信请求,拉低总线电平至少18ms,再拉高总线电平20-40us,切换至浮空输入监听从机响应;
3
从机识别到主机信号,发起响应:从机拉低总线电平80us,再拉高电平80us,然后传输数据;
4 数据的组成为40位:8bit 湿度整数数据+8bit 湿度小数数据+8bit
温度整数数据+8bit
温度小数数据+8bit校验和,每个字节数据高位在前,低位在后。 5
发送完成从机会拉低总线电平,主机应切换到推挽输出,重新拉高总线电平。
几点说明: 1
浮空输入:因为是需要监听从机低电平响应,主机不应该主动拉高或者拉低电平,因此采取浮空输入;
2
数据格式:传输每一位数据,都是以50us的低电平开始,后面如果接26-28us表示数据“0”,如果是70us
则表示数据“1”;
代码 dht11.h
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | #ifndef __DHT11_H#define	__DHT11_H
 
 #define DATA B4
 
 typedef struct    //结构体存数据
 {
 uint8_t  humi_int;
 uint8_t  humi_deci;
 uint8_t  temp_int;
 uint8_t  temp_deci;
 uint8_t  check_sum;
 
 }DHT11_Data_TypeDef;
 
 void DHT11_GPIO_Config(void);
 uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);
 static uint8_t Read_Byte(void);
 #endif
 
 | 
代码 dht11.c
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 
 | #include "dht11.h"#include "headfile.h"
 void DHT11_GPIO_Config(void)
 {
 gpio_init(DATA, GPO, GPIO_HIGH, GPO_PUSH_PULL);
 gpio_set_level(DATA,1);
 }
 
 static uint8_t Read_Byte(void)
 {
 uint8_t i, temp=0;
 
 for(i=0;i<8;i++)
 {
 while(gpio_get_level(DATA)==0);
 system_delay_us(40);
 if(gpio_get_level(DATA)==1)
 {
 while(gpio_get_level(DATA)==1);
 temp|=(uint8_t)(0x01<<(7-i));
 }
 else
 {
 temp&=(uint8_t)~(0x01<<(7-i));
 }
 
 }
 return temp;
 }
 
 uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
 {
 gpio_set_dir(DATA,GPO,GPO_PUSH_PULL);
 gpio_set_level(DATA,0);
 system_delay_ms(20);
 gpio_set_level(DATA,1);
 system_delay_us(30);
 gpio_set_dir(DATA, GPI, GPI_FLOATING_IN);
 if(gpio_get_level(DATA)==0)
 {
 while(gpio_get_level(DATA)==0);
 while(gpio_get_level(DATA)==1);
 DHT11_Data->humi_int= Read_Byte();
 
 DHT11_Data->humi_deci= Read_Byte();
 
 DHT11_Data->temp_int= Read_Byte();
 
 DHT11_Data->temp_deci= Read_Byte();
 
 DHT11_Data->check_sum= Read_Byte();
 
 gpio_set_dir(DATA, GPO,GPO_PUSH_PULL);
 gpio_set_level(DATA,1);
 
 if(DHT11_Data->check_sum == (uint8_t)(DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci))
 {return 1;}
 else return 0;
 }
 else
 return 0;
 }
 
 | 
代码 main.c
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | #include "headfile.h"#include "oled.h"
 #include "dht11.h"
 int main (void)
 {
 clock_init(SYSTEM_CLOCK_120M);
 debug_init();
 OLED_Init();
 DHT11_Data_TypeDef DHT11_Data;
 DHT11_GPIO_Config();
 while(1)
 {
 while(!Read_DHT11(&DHT11_Data));
 OLED_ShowString(4,1,"success");
 OLED_ShowString(1,1,"Tem:");
 OLED_ShowNum(1,5,DHT11_Data.temp_int,2);
 OLED_ShowString(1,8,".");
 OLED_ShowNum(1,9,DHT11_Data.temp_deci,1);
 OLED_ShowString(1,11,"C");
 OLED_ShowString(2,1,"Hum:");
 OLED_ShowNum(2,5,DHT11_Data.humi_int,2);
 OLED_ShowString(2,8,".");
 OLED_ShowNum(2,9,DHT11_Data.humi_deci,2);
 OLED_ShowString(2,12,"%");
 system_delay_ms(500);
 }
 }
 
 | 
debug遇到的问题
源程序是基于mm32寄存器库开发的,原来习惯在stm32标准库中大量使用了头文件调用和函数调用语句能正常实现,移植在mm32平台下载发现一直无法正常显示;进入debug模式发现是由于DHT11一直无法正常响应造成的,反复卡在while循环中,反复检查时序无明显问题,测量查看引脚电平无误,考虑到是延时出现问题;由于没有示波器难以精细确认完整时序,查看系统延迟函数,发现us延时函数注释“程序跳转会使实际延时比设定延时高一些”,考虑到有可能是上述大量头文件和函数调用带来us级的延时,而DHT11对时序的把控相当严格,造成这个错误;遂把头文件调用函数全部用显式加入C文件中,成功解决,以上均是排查的猜想,由于身边没有精确仪器,不能百分百确定是跳转产生时延的问题,这一点尚需商榷。