参考文章:《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
1 2 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
1 2 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
1 2 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文件中,成功解决,以上均是排查的猜想,由于身边没有精确仪器,不能百分百确定是跳转产生时延的问题,这一点尚需商榷。