打印
[活动专区]

【AT-START-F423测评】5.单数据线通讯读取DHT11温湿度

[复制链接]
1356|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yuyy1989|  楼主 | 2023-10-27 19:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
#申请原创# @21小跑堂  

DHT11是一种数字温湿度传感器,使用一根数据线进行数据传输,要求IO既能输出又能输入,使用开漏输出模式正好能满足要求
开漏模式下GPIO可以真正输出低电平,输出高电平需要借助上拉电阻,当需要作为输入时,只需要程序内输出高电平,之后外设就可以控制电平高低了

在AT32 Work Bench中将PD8配置成开漏输出,DHT11已经内置了10K的上拉电阻,这里就不配置上拉了,默认输出高电平


实现GPIO的操作,开漏模式下可以通过读输入读取真实的电平
#define YUYY_GPIO_LEV_TYPE flag_status
#define YUYY_GPIO_LEV1 SET
#define YUYY_GPIO_LEV0 RESET
void yuyy_gpio_setlev(YUYY_GPIO_DEV_t *gpio_dev,YUYY_GPIO_LEV_TYPE lev)
{
    gpio_bits_write(gpio_dev->gpio,gpio_dev->pin,lev);
}
YUYY_GPIO_LEV_TYPE yuyy_gpio_readlev(YUYY_GPIO_DEV_t *gpio_dev)
{
     return gpio_input_data_bit_read(gpio_dev->gpio,gpio_dev->pin);
}
void yuyy_gpio_opod_out(YUYY_GPIO_DEV_t *gpio_dev)
{
   
}
void yuyy_gpio_opod_in(YUYY_GPIO_DEV_t *gpio_dev)
{
    gpio_bits_write(gpio_dev->gpio,gpio_dev->pin,YUYY_GPIO_LEV1);
}
参考手册实现DHT11的通讯

enum
{
    YUYY_DHT11_OK = 0,
    YUYY_DHT11_ERROR_DATIOBUSY,
    YUYY_DHT11_ERROR_NOACK,
    YUYY_DHT11_ERROR_ACKBLOCK,
    YUYY_DHT11_ERROR_READDATA,
    YUYY_DHT11_ERROR_DATACHECK
};
typedef struct
{
    YUYY_GPIO_DEV_t dat;
}YUYY_DHT11_DEV_t;
uint8_t yuyy_dht11_readHT(YUYY_DHT11_DEV_t *dht11_dev,float *tem,float *hum)
{
    uint8_t retry = 0,i=0,j=0,check=0;
    uint8_t buffer[5] = {0};
    yuyy_gpio_opod_out(&(dht11_dev->dat)); //输出模式
    yuyy_gpio_setlev(&(dht11_dev->dat),YUYY_GPIO_LEV0); //拉低
    yuyy_dht11_delay_ms(20);
    yuyy_gpio_opod_in(&(dht11_dev->dat)); //输入模式
    retry = 0;
    while  (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV0)
    {
        yuyy_dht11_delay_us(10);
        retry += 1;
        if(retry > 2)
            return YUYY_DHT11_ERROR_DATIOBUSY;
    }
    while (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV1)
    {
        yuyy_dht11_delay_us(10);
        retry += 1;
        if(retry > 20)
            return YUYY_DHT11_ERROR_NOACK;
    }
    retry = 0;
    while  (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV0)
    {
        yuyy_dht11_delay_us(10);
        retry += 1;
        if(retry > 9)
            return YUYY_DHT11_ERROR_ACKBLOCK;
    }
    retry = 0;
    while (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV1)
    {
        yuyy_dht11_delay_us(10);
        retry += 1;
        if(retry > 10)
            return YUYY_DHT11_ERROR_ACKBLOCK;
    }
    while(i<5)
    {
        j = 0;
        while (j < 8)
        {
            buffer[i] <<= 1;
            retry = 0;
            while (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV0)
            {
                yuyy_dht11_delay_us(10);
                retry += 1;
                if(retry > 6)
                    return YUYY_DHT11_ERROR_READDATA;
            }
            retry = 0;
            while (yuyy_gpio_readlev(&(dht11_dev->dat)) == YUYY_GPIO_LEV1)
            {
                yuyy_dht11_delay_us(10);
                retry += 1;
                if(retry > 8)
                    return YUYY_DHT11_ERROR_READDATA;
            }
            if(retry > 5)
                buffer[i] |= 0x01;
            j += 1;
        }
        if(i<4)
            check += buffer[i];
        i += 1;
    }
    if(check != buffer[4])
        return YUYY_DHT11_ERROR_DATACHECK;
    *hum = buffer[0];
    *tem = buffer[2];
    if((buffer[3] & 0x7F) < 10)
    {
        *tem += (buffer[3] & 0x7F)/10.0;
    }
    if((buffer[3] & 0x80) > 0)
        *tem = 0 - *tem;
    return YUYY_DHT11_OK;
}
使用printf打印温湿度
YUYY_DHT11_DEV_t dht11_dev;
void dht11_init()
{
    dht11_dev.dat.gpio = DHT11_DAT_GPIO_PORT;
    dht11_dev.dat.pin = DHT11_DAT_PIN;
}

void dht11_readHT()
{
    float humi,temp;
    uint8_t result = yuyy_dht11_readHT(&dht11_dev,&temp,&humi);
    if(YUYY_DHT11_OK == result)
    {
        printf("DHT11 读取 温度:%.1f℃ 湿度:%.1f%%",temp,humi);
    }
    else
    {
        printf("DHT11 读取错误:%d",result);
    }
}
运行效果

结合之前的LCD屏幕,可以做个简单地温湿度监测器


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

695

帖子

6

粉丝