dht11如何才能精确到小数点后两位啊,还有这里为什么写的是<<8啊
一次完整的数据传输为40bits,也就是32位机的5个字节(byte),假如数据为buf[0]~buf[4],每个buf为一个unsigned char,或者其他8位的数据类型,buf[0]就是湿度的整数数据,buf[1]就是其湿度的小数部分,然后buf[2]就是温度的整数部分,buf[3]就是其温度的小数部分,buf[4]是校验和,也就是前面4个buf加起来的和。如果前面四个加起来等于校验和,说明数据传输成功,否则说明数据传输有问题。
解决方案: 在stm32中实现对dht11读取温湿度值的精确控制,需要对DHT11输出的波形进行解码,从而获取到温湿度数据。在解码波形的过程中,需要计算出低电平持续时间和高电平持续时间,用于将波形转换为二进制数。根据DHT11手册,温湿度数据分为整数和小数两部分,因此需要分别计算出整数和小数部分,再将它们组合成一个完整的数值。
以下是代码示例:
// 解码DHT11输出的波形,获取温湿度数据
// 参数:data 保存温湿度数据的数组,长度为5
// 返回值:成功返回0,失败返回负数
int decode_dht11(uint8_t* data)
{
// 发送开始信号
// 设置引脚为输出模式,并输出低电平
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择引脚
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 输出模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 输出低电平
HAL_Delay(20); // 低电平持续时间至少18ms
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 输出高电平
HAL_Delay(40); // 高电平持续时间20-40us
// 切换引脚为输入模式,接收DHT11响应信号
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
uint32_t t = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
HAL_Delay(1);
++t;
if (t > 80) {
return -1; // 响应信号持续时间大于80us,通信失败
}
}
t = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
HAL_Delay(1);
++t;
if (t > 80) {
return -2; // 响应信号持续时间大于80us,通信失败
}
}
t = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
HAL_Delay(1);
++t;
if (t > 80) {
return -3; // 响应信号持续时间大于80us,通信失败
}
}
// 解码温湿度数据
uint8_t buffer[5];
for (int j = 0; j < 5; ++j) {
uint8_t d = 0;
for (int i = 7; i >= 0; --i) {
// 测量低电平持续时间
t = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
HAL_Delay(1);
++t;
if (t > 100) {
return -4;
}
}
HAL_Delay(40);
// 判断是否有高电平产生
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
d |= 1 << i;
// 测量高电平持续时间
t = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
HAL_Delay(1);
++t;
if (t > 100) {
return -5;
}
}
}
}
buffer[j] = d;
}
// 数据校验
uint8_t sum = buffer[0] + buffer[1] + buffer[2] + buffer[3];
if (sum != buffer[4]) {
return -6; // 校验和错误
}
// 计算温度和湿度值
int temp_int = (int)buffer[2];
int temp_dec = (int)buffer[3];
int humidity_int = (int)buffer[0];
int humidity_dec = (int)buffer[1];
data[0] = (uint8_t)(humidity_int * 10 + humidity_dec);
data[1] = 0;
data[2] = (uint8_t)(temp_int * 10 + temp_dec);
data[3] = 0;
data[4] = sum;
return 0;
}
关于参考资料中的 <<8 操作,它是将一个8位的数左移8位,相当于将该数乘以256。在温湿度数据传输过程中,第1个字节表示湿度的整数部分,第2个字节表示湿度的小数部分,而温度的整数部分和小数部分分别在第3个和第4个字节中。为了将整数部分和小数部分组合成一个带小数的数值,需要将小数部分左移8位,相当于将它乘以256,再与整数部分相加。因此,代码中需要进行左移位运算,将小数部分左移8位,再与整数部分相加得到完整的温湿度数值。
DHT11温湿度传感器只能输出整数,无法精确到小数点后两位。如果需要更高精度的温湿度数据,可以考虑使用DHT22或AM2302等高精度的传感器,它们可以输出小数。或者使用其他类型的温湿度传感器,如SHT30、BME280等,它们可以提供更高的精度和稳定性。但是请注意,在使用更高精度的传感器时,需要进行相应的代码修改,以便正确解析传感器输出的数据。