后续:问题就出在DHT11.c的DHT11_ReadByte函数里少了一句timeout = 0,导致下一个timeout计数很快溢出,从而导致读取dht11高低电平时机过早,后面所有数据的读取全部出错。
排查过DHT11硬件模块没有问题,用别的代码就能正常读出温湿度数据,用我自己的代码就是数据校验和出错的状态,五个字节都是不正常的数据。
DHT11.c代码如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#define DHT11_RCC RCC_APB2Periph_GPIOA
#define DHT11_GPIO GPIOA
#define DHT11_Pin GPIO_Pin_0
void DHT11_Init_Out(void)
{
// RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = DHT11_Pin;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_GPIO, &GPIO_InitStruct);
GPIO_SetBits(DHT11_GPIO, DHT11_Pin);
}
void DHT11_Init_In(void)
{
// RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = DHT11_Pin;
// GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_GPIO, &GPIO_InitStruct);
}
void DHT11_BitValue(uint8_t BitValue)
{
GPIO_WriteBit(DHT11_GPIO, DHT11_Pin, (BitAction)BitValue);
}
void DHT11_Start(void)
{
DHT11_Init_Out();
DHT11_BitValue(0);
Delay_ms(20);
DHT11_BitValue(1);
Delay_us(30);
}
//返回1:DHT11响应失败
//返回0:响应成功,准备传输40位温湿度数据
uint8_t DHT11_Response(void)
{
uint8_t timeout = 0;
DHT11_Init_In();
while((GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_Pin) == 1) && timeout < 100)//等待dht11响应拉低电平
{
timeout++;
Delay_us(1);
}
if(timeout >= 100)
return 1;
else
timeout = 0;
while((GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_Pin) == 0) && timeout < 100)//dht11已拉低电平,会拉低80us,等待dht11拉高电平
{
timeout++;
Delay_us(1);
}
if(timeout >= 100)
return 1;
return 0;
}
uint8_t DHT11_Init(void)
{
RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = DHT11_Pin;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_GPIO, &GPIO_InitStruct);
GPIO_SetBits(DHT11_GPIO, DHT11_Pin);//默认高电平
DHT11_Start();
return DHT11_Response();
}
uint8_t DHT11_ReadByte(void)
{
uint8_t i, timeout = 0, DHT11_Byte = 0x00;
for(i = 0; i < 8; i++)
{
while((GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_Pin) == 1) && timeout < 100)//dht11已拉高电平,等待dht11拉低电平,读第一位数据前会拉高80us,后面的数据只有读取到1之后才需要等一会低电平
{
timeout++;
Delay_us(1);
}
timeout = 0;//加上这句就没问题了,之前没有把timeout清零导致下面的timeout溢出,最终导致读取数据的时机错乱
while((GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_Pin) == 0) && timeout < 100)//dht11拉低50us,等待dht11发送0/1数据
{
timeout++;
Delay_us(1);
}
Delay_us(40);//dht11超过40us仍处于高电平则读取该位为1,否则读取该位为0
if(GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_Pin) == 1)
{
DHT11_Byte |= (0x80 >> i);
}
}
return DHT11_Byte;
}
uint8_t DHT11_ReadData(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d, uint8_t *e)
{
uint8_t i, DHT11_Data[5];
DHT11_Start();
if(!DHT11_Response())
{
for(i = 0; i < 5; i++)
{
DHT11_Data[i] = DHT11_ReadByte();
}
// if(DHT11_Data[0]+DHT11_Data[1]+DHT11_Data[2]+DHT11_Data[3] == DHT11_Data[4])
// {
*a = DHT11_Data[0];
*b = DHT11_Data[1];
*c = DHT11_Data[2];
*d = DHT11_Data[3];
*e = DHT11_Data[4];
// }
// else return 1;
}
else return 1;//读取失败
return 0;//读取成功
}
main.c代码如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "LED.h"
#include "Key.h"
#include "DHT11.h"
uint8_t a, b, c, d, e;
int main(void)
{
OLED_Init();
LED_Init();
Key_Init();
OLED_Clear();
while(DHT11_Init())
{
OLED_ShowString(1, 1, "DHT11_Init_ERROR!");
Delay_s(1);
}
OLED_ShowString(1, 1, "DHT11_READY!");
Delay_s(1);
OLED_Clear();
OLED_ShowString(1, 1, "a: b:");
OLED_ShowString(2, 1, "c: d:");
OLED_ShowString(4, 1, "e:");
Delay_s(1);
while(1)
{
// if(Key_GetState())
// {
// LED_Turn();
// }
if(DHT11_ReadData(&a, &b, &c, &d, &e))
{
OLED_ShowString(1, 3, "ERR");
OLED_ShowString(2, 3, "ERR");
}
else
{
OLED_ShowNum(1, 3, a, 3);
OLED_ShowNum(1, 9, b, 3);
OLED_ShowNum(2, 3, c, 3);
OLED_ShowNum(2, 9, d, 3);
OLED_ShowNum(4, 3, e, 5);
}
Delay_s(1);
}
}