STM32+DHT11监测环境的温湿度

举报
DS小龙哥 发表于 2023/06/08 08:56:06 2023/06/08
【摘要】 DHT11采用单总线通信协议,只需要连接一个数字信号线和两个电源线,即可实现传感器的数据读取。传感器本身具有一定的温度和湿度校准能力,因此输出的数据比较可靠。

【1】DHT11传感器

DHT11是一种数字温湿度传感器,能够通过数字信号输出当前环境的温度和湿度值。DHT11可以通过一条数据信号线连接到微控制器或其他外设,从而实现温湿度的实时测量和数据读取。
image.png

DHT11采用单总线通信协议,只需要连接一个数字信号线和两个电源线,即可实现传感器的数据读取。传感器本身具有一定的温度和湿度校准能力,因此输出的数据比较可靠。

DHT11传感器的测量范围为0~50°C的温度和20%~90%的相对湿度,测量精度为±2°C和±5%RH。

【2】通信协议

DHT11采用单总线通信协议,使用一条数据信号线来传输数据,其中包括起始信号、数据位和校验位。通信协议如下:

  1. 主机发送一个开始信号给DHT11,即将数据信号线拉低至少18ms以上。
  2. 主机发出启动信号之后,拉低数据线至少80us,在这个过程中,DHT11将会检测到主机发送的启动信号,并做出回应。
  3. DHT11响应主机发出的启动信号后,会拉高数据信号线至少80us,表示传输数据前的“准备工作”已经完成。
  4. DHT11开始向主机发送数据,每个数据包包含40个位,高位先传输。在数据传输的过程中,DHT11会将数据信号线从低电平转换为高电平,表示1的开始,持续时间26~28us,然后将数据线拉低,表示0的开始,持续时间~70us。
  5. 在发送完40位数据后,DHT11会发送一个校验位。校验位的计算方法是将前四个字节数据相加,求出一个8位校验码,将此校验码与第五个字节进行比较,如果相等,则数据传输成功,否则需要重传数据。
  6. 主机接收到数据后,需要将数据信号线拉高,以结束传输。

【3】读取DHT11温湿度数据

以下是一个读取DHT11传感器的温度和湿度示例代码:

Copy Code#include "stm32f10x.h"
#include "dht11.h"

#define DHT11_GPIO_PORT GPIOB
#define DHT11_GPIO_PIN GPIO_Pin_12

void delay_us(uint32_t us)
{
    us *= (SystemCoreClock / 1000000) / 5;
    while (--us);
}

void dht11_start(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = DHT11_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);

    /* 发送开始信号 */
    GPIO_ResetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN);
    delay_us(18000);

    GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN);
    delay_us(40);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
}

uint16_t dht11_read_bit(void)
{
    uint16_t retry = 0;

    while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == RESET) {
        retry++;
        if (retry > 1000) {
            return 0;
        }
        delay_us(1);
    }

    retry = 0;

    while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == SET) {
        retry++;
        if (retry > 1000) {
            return 0;
        }
        delay_us(1);
    }

    if (retry < 30) {
        return 0;
    } else {
        return 1;
    }
}

uint8_t dht11_read_byte(void)
{
    uint8_t i;
    uint8_t data = 0;

    for (i = 0; i < 8; i++) {
        data <<= 1;
        if (dht11_read_bit()) {
            data |= 0x01;
        }
    }

    return data;
}

uint8_t dht11_read_data(dht11_data_t *data)
{
    uint8_t i;
    uint8_t buf[5];
    uint8_t checksum = 0;

    dht11_start();

    if (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == RESET) {
        /* 等待DHT11响应 */
        while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == RESET);

        /* 等待DHT11发射数据 */
        while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == SET);

        /* 接收数据 */
        for (i = 0; i < 5; i++) {
            buf[i] = dht11_read_byte();
        }

        /* 校验和 */
        checksum = buf[0] + buf[1] + buf[2] + buf[3];

        if (checksum == buf[4]) {
            data->humidity = buf[0];
            data->temperature = buf[2];
            return 1;
        }
    }

    return 0;
}

int main(void)
{
    dht11_data_t data;

    GPIO_InitTypeDef GPIO_InitStruct;

    /* 使能GPIOB时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* 配置DHT11引脚为输入模式 */
    GPIO_InitStruct.GPIO_Pin = DHT11_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);

    while (1) {
        if (dht11_read_data(&data)) {
            printf("Temperature: %d°C    Humidity: %d%%\n", data.temperature, data.humidity);
        } else {
            printf("Error reading data from DHT11.\n");
        }
        delay_us(2000000);
    }
}

在这个示例代码中,首先定义了一个dht11_data_t结构体,用于保存读取的温度和湿度数据。然后,编写了一些函数来执行DHT11读取操作。

delay_us()函数是一个简单的延迟函数,用于等待一定量的时间。需要精确地计算一个微秒的延迟,并在循环中使用该延迟来等待一段时间。

dht11_start()函数用于发送DHT11的开始信号。将DHT11引脚配置为输出模式,并发送18毫秒的低电平信号,然后再发送40微秒的高电平信号。

dht11_read_bit()函数用于读取DHT11传输的数据位。等待DHT11输出信号的变化,并根据变化的时间来判断数据位的值。如果一个数据位的响应时间小于30微秒,则被判定为0,否则为1。

dht11_read_byte()函数用于读取一个字节的数据(8个数据位)。通过调用dht11_read_bit()函数8次来读取每个数据位,并将结果组合成一个字节。

dht11_read_data()函数用于读取整个DHT11数据包,包括温度、湿度和校验和。首先调用dht11_start()函数发送开始信号,然后等待DHT11发送数据。使用dht11_read_byte()函数读取5个字节的数据,并验证校验和以确保数据完整和正确。

最后,在main()函数中,初始化GPIO口和DHT11传感器,并执行一个循环来读取数据。如果读取成功,则将温度和湿度打印到串口终端上,否则输出错误信息。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。