公司动态
C8T6主板+DHT11温湿度传感器+oled显示——编写以及自纠
了解DHT11的原理做了一个关于温湿度传感器的程序中间遇到了一些问题1.时序的问题 2.dht11采样值为0其实也是时序问题关于dht11的知识点主要说一下传输时序绿色是主机发送的信号 蓝色是传感器往主机中传输的信号 主机输出用推挽输出有控制电平的能力输入模式用上拉输入 默认高电平。绿色阶段主机拉低电平18ms ,紧接着释放总线到高电平20~40us。蓝色DHT11响应阶段输出低电平80us接着输出高电平80us 这里可以设置一个函数检测是否超时并且返回对应数字检测问题。蓝色DHT11发送数据阶段接收的数据0的构成是50us的低电平 26us~28us高电平1的构成是50us的低电平 70us高电平 一共有四十bits数据 分为5块分别是湿度整数、湿度小数、温度整数、温度小数、校验位前四项数据和这其中我出现的问题是 数据采集是0,检查代码问题一天最后找到是因为时序问题 。下面是代码部分 只包含dht11.h dht11.c 以及main.c屏幕驱动以及延迟函数没有。DHT11.h文件#ifndef __DHT11_H #define __DHT11_H #include stdint.h #include stm32f10x.h // Device header #include delay.h #include OLED.h //DHT11引脚定义 #define DHT11_GPIO_PORT GPIOB #define DHT11_GPIO_PIN GPIO_Pin_1 //PB1引脚 //GPIO 操作宏 #define DHT11_DATA_IN() GPIO_ReadInputDataBit(DHT11_GPIO_PORT,DHT11_GPIO_PIN) #define DHT11_DATA_OUT_HIGH() GPIO_SetBits(DHT11_GPIO_PORT,DHT11_GPIO_PIN) #define DHT11_DATA_OUT_LOW() GPIO_ResetBits(DHT11_GPIO_PORT,DHT11_GPIO_PIN) void DHT11_init(void); uint8_t DHT11_ReadData(uint8_t *temp ,uint8_t *humi); #endifDHT11.c文件我拆成几个部分static修饰的函数只能在本函数中使用输出推挽模式 输入上拉输入 引脚部分在.h文件中宏定义声明了直接用宏定义#include DHT11.h static void DHT11_Mode_out(void) { GPIO_InitTypeDef GPIO_initSturcture; GPIO_initSturcture.GPIO_ModeGPIO_Mode_Out_PP; GPIO_initSturcture.GPIO_PinDHT11_GPIO_PIN; GPIO_initSturcture.GPIO_SpeedGPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO_PORT,GPIO_initSturcture); } static void DHT11_Mode_in(void) { GPIO_InitTypeDef GPIO_initSturcture; GPIO_initSturcture.GPIO_ModeGPIO_Mode_IPU; GPIO_initSturcture.GPIO_PinDHT11_GPIO_PIN; GPIO_initSturcture.GPIO_SpeedGPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO_PORT,GPIO_initSturcture); }这两个代码表示一位一位读取数据一共四十位第一个函数每八位凑成一个字节数据第二个函数 这个里面容易有问题的点是初始化参数记得置0。不知道是不是每个元器件的原因在第一个函数结尾的部分也就是设置高电平时间的部分是我一直卡卡着的点我一直设置的是40 修改为三十之后就能采集到数据了还是得严谨一点static uint8_t DHT11_ReadBit(void) { uint16_t timeout 0;//初始值设定 uint16_t hightime 0; while(!DHT11_DATA_IN() timeout 100) { Delay_us(1); timeout; } timeout 0; while(DHT11_DATA_IN() timeout 100) { Delay_us(1); timeout; } hightime timeout; if(hightime 30) return 1; else return 0; } static uint8_t DHT11_ReadByte(void) { uint8_t data 0; for(uint8_t i 0 ; i 8 ; i) { data 1; data | DHT11_ReadBit(); } return data; }初始化使能时钟以及将设置输出模式clk线置为高电平咱们一开始讲的时序图就是高电平开始的void DHT11_init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); DHT11_Mode_out(); DHT11_DATA_OUT_HIGH(); }这一部分是咱们一开始图片蓝色线条 dht11回应部分检测dht11是不是接收到主机的信号。这一部分的主要的检测是 dht11是否响应以及超时DHT11_DATA_IN()在.h文件中宏定义设置过了主要逻辑是检测引脚是否变为低电平如果没有变一直并且计数值没有超过1000那么就一直加到超时 如果函数变为低电平了那么下一个函数。下一个函数是检测有没有变为高电平逻辑一样。最后一个是检查她有没有变为低电平准备进入数据位。//DHT11 接收并且回应 static uint8_t DHT11_CheckResponse(void) { uint16_t timeout 0; // 1. 等待DHT11拉低总线响应开始 while(DHT11_DATA_IN() timeout 1000) { Delay_us(1); timeout ; } if(timeout 1000) return 1; // 无响应超时 timeout 0; // 2. 等待DHT11拉高总线响应低电平结束80us while(!DHT11_DATA_IN() timeout 1000) { Delay_us(1); timeout; } if(timeout 1000) return 2; // 低电平超时 timeout 0; // 3. 等待响应高电平结束80us进入数据位 while(DHT11_DATA_IN() timeout 1000) { Delay_us(1); timeout; } if(timeout 1000) return 3; // 高电平超时 return 0; }这一部分就是开始读取数据 上面咱们写了 输出模式输入模式 读取bit 读取字节 检查回应 还有初始化引脚定义五个变量用于存储数据接着调成输出模式 拉低电平延迟30ms 再拉高30ms主机发送信号模式改为输入模式等待dht11接收用一个参数接收返回值输出有可能的错误信息。下一个阶段是停止中断 专门用来接收温湿度数据。然后判断第五个字节的数据是否是前几项之和然后把数据传参给指针用来存放温湿度的整数部分全都没有错误的话是返回0uint8_t DHT11_ReadData(uint8_t *temp ,uint8_t *humi) { uint8_t humi_int,humi_dec,temp_int,temp_dec,checksum; DHT11_Mode_out(); DHT11_DATA_OUT_LOW(); Delay_ms(30);//至少18ms DHT11_DATA_OUT_HIGH(); Delay_us(30);//20us~40us DHT11_Mode_in();//释放通信给dht11 uint8_t response DHT11_CheckResponse(); if(response ! 0) return response; // 返回 1 或 2//无响应 __disable_irq(); humi_int DHT11_ReadByte(); humi_dec DHT11_ReadByte(); temp_int DHT11_ReadByte(); temp_dec DHT11_ReadByte(); checksum DHT11_ReadByte(); __enable_irq(); if(checksum ! humi_int humi_dec temp_int temp_dec) return 4; *temp temp_int; *humi humi_int; return 0; }下面是主函数main.c#include stm32f10x.h // Device header #include Delay.h #include OLED.h #include stdio.h // 用于 sprintf #include DHT11.h #include string.h // 用于 strlen int main(void) { uint8_t temp 0,humi 0; uint8_t ret 0; // 显示缓冲区 char display_buffer[20]; OLED_Init(); DHT11_init(); Delay_ms(1000); // OLED_Clear(); while(1) { ret DHT11_ReadData(temp,humi); if(ret 0) { // 显示温度 sprintf(display_buffer, Temp: %d C, temp); OLED_ShowString(1, 2, display_buffer); // 显示湿度 sprintf(display_buffer, Humi: %d %%, humi); OLED_ShowString(2, 2, display_buffer); OLED_ShowString(3, 1, OK); OLED_ShowNum(4,1,ret,1); } else { OLED_ShowString(3,1,ERR:); OLED_ShowNum(3,5,ret,1); } Delay_ms(2000); } }