前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >108-ESP32_SDK开发-使用RMT实现读取DHT11温湿度传感器

108-ESP32_SDK开发-使用RMT实现读取DHT11温湿度传感器

作者头像
杨奉武
发布2024-04-17 08:16:34
1750
发布2024-04-17 08:16:34
举报
文章被收录于专栏:知识分享知识分享

本文参考:https://blog.csdn.net/qq_53381910/article/details/130776069  不过本文中做了些改动

说明

RMT 是ESP32内置的红外收发器, 其实就是脉冲输出和捕获控制器

使用RMT呢就可以不用像原先硬延时采集DHT11的电平,大大提高了程序执行效率

直接上程序

代码语言:javascript
复制
#include <driver/rmt.h>
#include <soc/rmt_reg.h>

// 温度 湿度变量
int temp = 0,hum = 0;
#define DHT11_GPIO    33        // DHT11引脚定义 

// 温度是10倍,/10有1位小数
int temp_x10 = 123;
int humidity = 60;
const int channel = 0;

uint8_t DHT11_PIN = -1;
// 将RMT读取到的脉冲数据处理为温度和湿度
static int parse_items(rmt_item32_t *item, int item_num, int *humidity, int *temp_x10);

// DHT11 初始化
void DHT11_Init(uint8_t dht11_pin)
{
    DHT11_PIN = dht11_pin;
    const int RMT_CLK_DIV = 80;                                        // RMT计数器时钟分频器
    const int RMT_TICK_10_US = (80000000 / RMT_CLK_DIV / 100000);    // RMT计数器10us.(时钟源是APB时钟)
    const int rmt_item32_tIMEOUT_US = 1000;                            // RMT接收超时us
    rmt_config_t rmt_rx = {
        .gpio_num = dht11_pin,
        .channel = channel,
        .clk_div = RMT_CLK_DIV,
        .mem_block_num = 1,
        .rmt_mode = RMT_MODE_RX,                    // 接收模式
        .rx_config.filter_en = false,
        .rx_config.filter_ticks_thresh = 100,
        .rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US),
    };
    rmt_config(&rmt_rx);
    rmt_driver_install(rmt_rx.channel, 1000, 0);    // 安装驱动
    //rmt_driver_uninstall(rmt_rx.channel)            // 卸载驱动
}

// 将RMT读取到的脉冲数据处理为温度和湿度
static int parse_items(rmt_item32_t *item, int item_num, int *humidity, int *temp_x10)
{
    int i = 0;
    unsigned rh = 0, temp = 0, checksum = 0;
    if (item_num < 42){                    // 检查是否有足够的脉冲数
        ESP_LOGI(TAG, "item_num < 42  %d",item_num);
        return 0;
    }
    item++;                                // 跳过开始信号脉冲
    for (i = 0; i < 16; i++, item++){    // 提取湿度数据
        rh = (rh << 1) + (item->duration1 < 35 ? 0 : 1);
    }
    for (i = 0; i < 16; i++, item++){    // 提取温度数据
        temp = (temp << 1) + (item->duration1 < 35 ? 0 : 1);
    }
    for (i = 0; i < 8; i++, item++){    // 提取校验数据
        checksum = (checksum << 1) + (item->duration1 < 35 ? 0 : 1);
    }
    // 检查校验
    if ((((temp >> 8) + temp + (rh >> 8) + rh) & 0xFF) != checksum){
        ESP_LOGI(TAG, "Checksum failure %4X %4X %2X\n", temp, rh, checksum);
        return 0;
    }
    // 返回数据
    *humidity = rh >> 8;
    *temp_x10 = (temp >> 8) * 10 + (temp & 0xFF);
    return 1;
}
// 使用RMT接收DHT11数据
int DHT11_StartGet(int *temp_x10, int *humidity)
{
    RingbufHandle_t rb = NULL;
    size_t rx_size = 0;
    rmt_item32_t *item;
    int rtn = 0;
    //获得RMT RX环形缓冲区句柄,并处理RX数据
    rmt_get_ringbuf_handle(channel, &rb);
    if (!rb){
        return 0;
    }

    gpio_pad_select_gpio(DHT11_PIN);//选择GPIO口

    //发送20ms脉冲启动DHT11单总线
    gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DHT11_PIN, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(DHT11_PIN, 0);
    vTaskDelay(25 / portTICK_PERIOD_MS);

    //将rmt_rx_start和rmt_rx_stop放入缓存
    rmt_rx_start(channel, 1);
    rmt_rx_stop(channel);

    //信号线设置为输入准备接收数据
    gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT);

    //这次启动RMT接收器以获取数据
    rmt_rx_start(channel, 1);

    //从环形缓冲区中取出数据
    item = (rmt_item32_t *)xRingbufferReceive(rb, &rx_size, 1000 / portTICK_RATE_MS);
    if (item != NULL){
        int n;
        n = rx_size / 4 - 0;
        // 解析来自ringbuffer的数据值.
        rtn = parse_items(item, n, humidity, temp_x10);
        // 解析数据后,将空格返回到ringbuffer.
        vRingbufferReturnItem(rb, (void *)item);
    }
    //停止RMT接收
    rmt_rx_stop(channel);
    return rtn;
}
代码语言:javascript
复制
void app_main()
{
    //初始化 NVS(配置WiFi的参数存储需要用到NVS)
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
    //初始化内部的lwip
    ESP_ERROR_CHECK(esp_netif_init());
    //创建系统事件任务
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    
    DHT11_Init(DHT11_GPIO);
    while (1){
        if (DHT11_StartGet(&temp, &hum)){
            ESP_LOGI(TAG, "[%lld] temp->%i.%i C     hum->%i%%", esp_timer_get_time(), temp / 10, temp % 10, hum);
        }

        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本文参考:https://blog.csdn.net/qq_53381910/article/details/130776069  不过本文中做了些改动
  • 说明
    • RMT 是ESP32内置的红外收发器, 其实就是脉冲输出和捕获控制器
      • 使用RMT呢就可以不用像原先硬延时采集DHT11的电平,大大提高了程序执行效率
      • 直接上程序
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档