DHT11驱动

DHT11驱动

介绍

参考《HAL快速入门与项目实战(基于DshanMCU-F407)_V1.0》

参考《dht11_datasheet.pdf》

DHT11 驱动涉及引脚的读取操作,具体操作在驱动程序注释中已经说明

驱动程序

driver_dht11.h

#ifndef __DRIVER_DHT11_H__
#define __DRIVER_DHT11_H__

#include "main.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @brief dht11 handle structure definition
 */
typedef struct dht11_handle_s
{
    uint8_t (*bus_init)(void);                              /**< point to a bus_init function address */
    uint8_t (*bus_read)(uint8_t *value);                    /**< point to a bus_read function address */
    uint8_t (*bus_write)(uint8_t value);                    /**< point to a bus_write function address */
    uint8_t (*bus_deinit)(void);                            /**< point to a bus_deinit function address */
    void (*delay_ms)(uint32_t ms);                          /**< point to a delay_ms function address */
    void (*delay_us)(uint32_t us);                          /**< point to a delay_us function address */
    void (*enable_irq)(void);                               /**< point to an enable_irq function address */
    void (*disable_irq)(void);                              /**< point to a disable_irq function address */
    void (*debug_print)(const char *const fmt, ...);        /**< point to a debug_print function address */
    uint8_t inited;                                         /**< inited flag */
} dht11_handle_t;

/**
 * @brief dht11 info structure definition
 */
typedef struct dht11_info_s
{
    char chip_name[32];                /**< chip name */
    char manufacturer_name[32];        /**< manufacturer name */
    char interface[8];                 /**< chip interface name */
    float supply_voltage_min_v;        /**< chip min supply voltage */
    float supply_voltage_max_v;        /**< chip max supply voltage */
    float max_current_ma;              /**< chip max current */
    float temperature_min;             /**< chip min operating temperature */
    float temperature_max;             /**< chip max operating temperature */
    uint32_t driver_version;           /**< driver version */
} dht11_info_t;

/**
 * @brief     initialize dht11_handle_t structure
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] STRUCTURE is dht11_handle_t
 * @note      none
 */
#define DRIVER_DHT11_LINK_INIT(HANDLE, STRUCTURE)   memset(HANDLE, 0, sizeof(STRUCTURE))

/**
 * @brief     link bus_init function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a bus_init function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_BUS_INIT(HANDLE, FUC)    (HANDLE)->bus_init = FUC

/**
 * @brief     link bus_deinit function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a bus_deinit function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_BUS_DEINIT(HANDLE, FUC)  (HANDLE)->bus_deinit = FUC

/**
 * @brief     link bus_read function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a bus_read function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_BUS_READ(HANDLE, FUC)    (HANDLE)->bus_read = FUC

/**
 * @brief     link bus_write function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a bus_write function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_BUS_WRITE(HANDLE, FUC)   (HANDLE)->bus_write = FUC

/**
 * @brief     link delay_ms function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a delay_ms function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_DELAY_MS(HANDLE, FUC)    (HANDLE)->delay_ms = FUC

/**
 * @brief     link delay_us function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a delay_us function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_DELAY_US(HANDLE, FUC)    (HANDLE)->delay_us = FUC

/**
 * @brief     link enable_irq function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to an enable_irq function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_ENABLE_IRQ(HANDLE, FUC)  (HANDLE)->enable_irq = FUC

/**
 * @brief     link disable_irq function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a disable_irq function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_DISABLE_IRQ(HANDLE, FUC) (HANDLE)->disable_irq = FUC

/**
 * @brief     link debug_print function
 * @param[in] HANDLE points to a dht11 handle structure
 * @param[in] FUC points to a debug_print function address
 * @note      none
 */
#define DRIVER_DHT11_LINK_DEBUG_PRINT(HANDLE, FUC) (HANDLE)->debug_print = FUC

/**
 * @brief      get chip's information
 * @param[out] *info points to a dht11 info structure
 * @return     status code
 *             - 0 success
 *             - 2 handle is NULL
 * @note       none
 */
uint8_t dht11_info(dht11_info_t *info);

/**
 * @brief     initialize the chip
 * @param[in] *handle points to a dht11 handle structure
 * @return    status code
 *            - 0 success
 *            - 1 bus initialization failed
 *            - 2 handle is NULL
 *            - 3 linked functions is NULL
 *            - 4 reset failed
 * @note      none
 */
uint8_t dht11_init(dht11_handle_t *handle);

/**
 * @brief     close the chip
 * @param[in] *handle points to a dht11 handle structure
 * @return    status code
 *            - 0 success
 *            - 1 bus deinit failed
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t dht11_deinit(dht11_handle_t *handle);

/**
 * @brief      read the temperature and humidity data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *temperature_raw points to a raw temperature buffer
 * @param[out] *temperature_s points to a converted temperature buffer
 * @param[out] *humidity_raw points to a raw humidity buffer
 * @param[out] *humidity_s points to a converted humidity buffer
 * @return     status code
 *             - 0 success
 *             - 1 read temperature humidity failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_temperature_humidity(dht11_handle_t *handle, uint16_t *temperature_raw, float *temperature_s,
                                        uint16_t *humidity_raw, uint8_t *humidity_s);

/**
 * @brief      read the humidity data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *raw points to a raw humidity buffer
 * @param[out] *s points to a converted humidity buffer
 * @return     status code
 *             - 0 success
 *             - 1 read humidity failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_humidity(dht11_handle_t *handle, uint16_t *raw, uint8_t *s);

/**
 * @brief      read the temperature data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *raw points to a raw temperature buffer
 * @param[out] *s points to a converted temperature buffer
 * @return     status code
 *             - 0 success
 *             - 1 read temperature failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_temperature(dht11_handle_t *handle, uint16_t *raw, float *s);

#ifdef __cplusplus
}
#endif

#endif

driver_dht11.c

#include "driver_dht11.h"

/**
 * @brief chip information definition
 */
#define CHIP_NAME                "ASAIR DHT11"         /**< chip name */
#define MANUFACTURER_NAME        "ASAIR"               /**< manufacturer name */
#define SUPPLY_VOLTAGE_MIN       3.3f                  /**< chip min supply voltage */
#define SUPPLY_VOLTAGE_MAX       5.5f                  /**< chip max supply voltage */
#define MAX_CURRENT              1.0f                  /**< chip max current */
#define TEMPERATURE_MIN          -20.0f                /**< chip min operating temperature */
#define TEMPERATURE_MAX          60.0f                 /**< chip max operating temperature */
#define DRIVER_VERSION           2000                  /**< driver version */

/**
 * @brief     reset the chip
 * @param[in] *handle points to a dht11 handle structure
 * @return    status code
 *            - 0 success
 *            - 1 no response
 * @note      none
 * 
 * 重置 DHT11,初始化通信
 */
static uint8_t a_dht11_reset(dht11_handle_t *handle)
{
    uint8_t retry = 0;
    uint8_t res;
    uint8_t value;
    
    /* 将单通信总线拉低,MCU的I/O设置为输出,同时输出低电平 */
    res = handle->bus_write(0);                                      /* set low */
    if (res != 0)                                                    /* check result */
    {
        handle->debug_print("dht11: bus write 0 failed.\n");         /* write failed */
        
        return 1;                                                    /* return error */
    }

    /* 低电平保持时间不能小于18ms(最大不得超过30ms)*/
    handle->delay_ms(20);                                            /* wait 20ms */

    /* 这里给 DHT11 发送起始信号时,为了严格遵守时序要求可以禁用全局中断,但并不是必要操作 */
    handle->disable_irq();                                           /* disable interrupt */

    /* 主机拉低后释放总线,输出1,外部上拉电阻拉高总线,等待 DHT11 拉低作为应答 */
    res = handle->bus_write(1);                                      /* set high */
    if (res != 0)                                                    /* check result */
    {
        handle->enable_irq();                                        /* enable interrupt */
        handle->debug_print("dht11: bus write 1 failed.\n");         /* write failed */
        
        return 1;                                                    /* return error */
    }

    /* DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束(即主控拉低引脚后拉高引脚)*/
    /* 延迟一段时间后 DHT11的DATA引脚处于输出状态 */
    handle->delay_us(30);                                            /* wait 20-40us */

    /* DHT11 会输出83微秒的低电平作为应答信号,此时MCU读取引脚电平状态,判断 DHT11 是否给出响应 */
    res = handle->bus_read((uint8_t *)&value);                       /* read 1 bit */
    if (res != 0)                                                    /* check result */
    {
        handle->enable_irq();                                        /* enable interrupt */
        handle->debug_print("dht11: bus read failed.\n");            /* read failed */
        
        return 1;                                                    /* return error */
    }

    /* 循环等待 83us 内的应答信号,这里略微增加了延迟时间到100us */
    while ((value != 0) && (retry < 100))                            /* wait 40-80us */
    {
        res = handle->bus_read((uint8_t *)&value);                   /* read 1 bit */
        if (res != 0)                                                /* check result */
        {
            handle->enable_irq();                                    /* enable interrupt */
            handle->debug_print("dht11: bus read failed.\n");        /* read failed */
            
            return 1;                                                /* return error */
        }
        retry++;                                                     /* retry times++ */
        handle->delay_us(1);                                         /* delay 1us */
    }

    /* 超时,表明传感器未给出响应,没有正常工作 */
    if (retry >= 100)                                                /* if retry times is over 100 times */
    {
        handle->enable_irq();                                        /* enable interrupt */
        handle->debug_print("dht11: bus no response.\n");            /* no response */
        
        return 1;                                                    /* return error */
    }
    else
    {
        retry = 0;                                                   /* reset retry times */
    }

    /* 走到这里说明 DHT11 已经给出响应信号,紧接着输出87微秒的高电平通知MCU准备接收数据 */
    res = handle->bus_read((uint8_t *)&value);                       /* read 1 bit */
    if (res != 0)                                                    /* check result */
    {
        handle->enable_irq();                                        /* enable interrupt */
        handle->debug_print("dht11: bus read failed.\n");            /* read failed */
        
        return 1;                                                    /* return error */
    }

    /* 循环等待 87us 内的高电平通知信号,这里略微增加了延迟时间到100us */
    while ((!value) && (retry < 100))                                /* wait for 40-80us */
    {
        res = handle->bus_read((uint8_t *)&value);                   /* read 1 bit */
        if (res != 0)                                                /* check result */
        {
            handle->enable_irq();                                    /* enable interrupt */
            handle->debug_print("dht11: bus read failed.\n");        /* read failed */
            
            return 1;                                                /* return error */
        }
        retry++;                                                     /* retry times++ */
        handle->delay_us(1);                                         /* delay 1 us */
    }

    /* 超时,表明传感器未能正常工作拉高总线给出数据 */
    if (retry >= 100)                                                /* if retry times is over 100 times */
    { 
        handle->enable_irq();                                        /* enable interrupt */
        handle->debug_print("dht11: bus no response.\n");            /* no response */
        
        return 1;                                                    /* return error */
    }

    /* 恢复全局中断 */
    handle->enable_irq();                                            /* enable interrupt */
    
    return 0;                                                        /* success return 0 */
}

/**
 * @brief      read one bit
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *value points to a value buffer
 * @return     status code
 *             - 0 success
 *             - 1 read failed
 * @note       none
 */
static uint8_t a_dht11_read_bit(dht11_handle_t *handle, uint8_t *value)
{
    uint8_t retry = 0;
    uint8_t res;
    
     /* DHT11 会输出83微秒的低电平作为应答信号,此时MCU读取引脚电平状态,判断 DHT11 是否给出响应 */
    res = handle->bus_read((uint8_t *)value);                        /* read 1 bit */
    if (res != 0)                                                    /* check result */
    {
        handle->debug_print("dht11: bus read failed.\n");            /* read failed */
        
        return 1;                                                    /* return error */
    }

    /* 循环等待 83us 内的应答信号,这里略微增加了延迟时间到100us */
    while (((*value) != 0) && (retry < 100))                         /* wait 100us */
    {
        res = handle->bus_read((uint8_t *)value);                    /* read 1 bit */
        if (res != 0)                                                /* check result */
        {
            handle->debug_print("dht11: bus read failed.\n");        /* read failed */
            
            return 1;                                                /* return error */
        }
        retry++;                                                     /* retry times++ */
        handle->delay_us(1);                                         /* delay 1 us */
    }

    retry = 0;                                                       /* reset retry times */

    /* 走到这里说明 DHT11 已经给出响应信号,紧接着输出87微秒的高电平通知MCU准备接收数据 */
    res = handle->bus_read((uint8_t *)value);                        /* read 1 bit */
    if (res != 0)                                                    /* check result */
    {
        handle->debug_print("dht11: bus read failed.\n");            /* read failed */
        
        return 1;                                                    /* return error */
    }

    /* 循环等待 87us 内的高电平通知信号,这里略微增加了延迟时间到100us */
    while ((!(*value)) && (retry < 100))                             /* wait 100us */
    {
        res = handle->bus_read((uint8_t *)value);                    /* read 1 bit */
        if (res != 0)                                                /* check result */
        {
            handle->debug_print("dht11: bus read failed.\n");        /* read failed */
            
            return 1;                                                /* return error */
        }
        retry++;                                                     /* retry times++ */
        handle->delay_us(1);                                         /* wait 1 us */
    }

    /* 87us 的数据通知信号发送后
    逻辑 "1" 和 逻辑 "0" 发送前会有 54us 的低电平时刻
    这里延时 40us 用来同步 DHT11 稳定后的高电平数据,根据高电平的时长来判断是 "1" 还是 "0"
    高电平的时间窗口是 23us-27us 在 40us 以内为 "0",高电平的时间窗口是 68us-74us 在 40us 以外为 "1"
    */
    handle->delay_us(40);                                            /* wait 40us */

    /* 读取此时总线上的电平信号 */
    res = handle->bus_read((uint8_t *)value);                        /* read 1 bit */
    if (res != 0)                                                    /* check result */
    {
        handle->debug_print("dht11: bus read failed.\n");            /* read failed */
        
        return 1;                                                    /* return error */
    }
    else
    {
        return 0;                                                    /* success return 0 */
    }
}

/**
 * @brief      read one byte
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *byte points to a byte buffer
 * @return     status code
 *             - 0 success
 *             - 1 read failed
 * @note       none
 */
static uint8_t a_dht11_read_byte(dht11_handle_t *handle, uint8_t *byte)
{
    uint8_t i;
    uint8_t res;
    uint8_t value;
    
    *byte = 0;                                                       /* set byte 0 */
    for (i = 0; i < 8; i++)                                          /* read 8 bits */
    {
        /* DHT11 发送时高位先出 */
        *byte <<= 1;                                                 /* left shift 1 bit */
        res = a_dht11_read_bit(handle, (uint8_t *)&value);           /* read 1 bit */
        if (res != 0)                                                /* check result */
        {
            handle->debug_print("dht11: bus read failed.\n");        /* read failed */
            
            return 1;                                                /* return error */
        }
        *byte |= value;                                              /* set LSB */
    }
    
    return 0;                                                        /* success return 0 */
}

/**
 * @brief      read the humidity data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *raw points to a raw humidity buffer
 * @param[out] *s points to a converted humidity buffer
 * @return     status code
 *             - 0 success
 *             - 1 read humidity failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_humidity(dht11_handle_t *handle, uint16_t *raw, uint8_t *s)
{
    /* 一次传送40位数据 */
    /* 数据格式: 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据 + 8bit校验位。 */
    uint8_t buf[5];
    uint8_t i;
    
    if (handle == NULL)                                                   /* check handle */
    {
        return 2;                                                         /* return error */
    }
    if (handle->inited != 1)                                              /* check handle initialization */
    {
        return 3;                                                         /* return error */
    }
    
    if (a_dht11_reset(handle) == 0)                                       /* reset the chip */
    {
        handle->disable_irq();                                            /* disable interrupt */
        for (i = 0; i < 5; i++)                                           /* read 5 bytes */
        {
            /* 分别读取 5 个字节的数据 */
            if (a_dht11_read_byte(handle, (uint8_t *)&buf[i]) != 0)       /* read each byte */
            {
                handle->enable_irq();                                     /* enable interrupt */
                handle->debug_print("dht11: read byte failed.\n");        /* read failed */
                
                return 1;                                                 /* return error */
            }
        }
        handle->enable_irq();                                             /* enable interrupt */
        
        /* 检查校验位 */
        /* 校验位=湿度高位+湿度低位+温度高位+温度低位 */
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])                /* calculate checksum */
        {
            /* 拿到湿度的原始数据 */
            *raw = (uint16_t)buf[0] << 8 | buf[1];                        /* get raw data */
            /* 注:其中湿度小数部分为0。这里只拿湿度数据的整数部分即可 */
            *s = buf[0];                                                  /* convert raw data to real data */
            
            return 0;                                                     /* success return 0 */
        }
        else
        {
            handle->debug_print("dht11: data check failed.\n");           /* checksum error */
            
            return 1;                                                     /* return error */
        }
    }
    else
    {
        handle->debug_print("dht11: reset failed.\n");                    /* reset failed */
        
        return 1;                                                         /* return error */
    }
}

/**
 * @brief      read the temperature and humidity data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *temperature_raw points to a raw temperature buffer
 * @param[out] *temperature_s points to a converted temperature buffer
 * @param[out] *humidity_raw points to a raw humidity buffer
 * @param[out] *humidity_s points to a converted humidity buffer
 * @return     status code
 *             - 0 success
 *             - 1 read temperature humidity failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_temperature_humidity(dht11_handle_t *handle, uint16_t *temperature_raw, float *temperature_s,
                                        uint16_t *humidity_raw, uint8_t *humidity_s)
{
    uint8_t buf[5];
    uint8_t i;
    
    if (handle == NULL)                                                         /* check handle */
    {
        return 2;                                                               /* return error */
    }
    if (handle->inited != 1)                                                    /* check handle initialization */
    {
        return 3;                                                               /* return error */
    }
    
    if (a_dht11_reset(handle) == 0)                                             /* reset the chip */
    {
        handle->disable_irq();                                                  /* disable interrupt */
        /* 读取 5 个字节的数据 */
        for (i = 0; i < 5; i++)                                                 /* read 5 bytes */
        {
            if (a_dht11_read_byte(handle, (uint8_t *)&buf[i]) != 0)             /* read each byte */
            {
                handle->enable_irq();                                           /* enable interrupt */
                handle->debug_print("dht11: read byte failed.\n");              /* read failed */
                
                return 1;                                                       /* return error */
            }
        }
        handle->enable_irq();                                                   /* enable interrupt */

        /* 检验数据 */
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])                      /* calculate checksum */
        {
            /* 处理温湿度数据,处理方式与单独的功能里一致,已做详细的注释 */
            if (buf[3] > 127)                                                   /* if temperature is below zero */
            {
                *temperature_raw = (uint16_t)buf[2] << 8 | buf[3];              /* get temperature raw data */
                *temperature_s= (float)(-(buf[2] * 10 + 
                                 (buf[3] & ~(1<<7)))) / 10.0f;                  /* convert temperature raw data to temperature real data */
            }
            else
            {
                *temperature_raw = (uint16_t)buf[2] << 8 | buf[3];              /* get temperature raw data */
                *temperature_s= (float)(buf[2]*10 + buf[3]) / 10.0f;            /* convert temperature raw data to temperature real data */
            }
            *humidity_raw = (uint16_t)buf[0] << 8 | buf[1];                     /* get humidity raw */
            *humidity_s = buf[0];                                               /* convert humidity raw data to real data */
            
            return 0;                                                           /* success return 0 */
        }
        else
        {
            handle->debug_print("dht11: data check failed.\n");                 /* checksum error */
            
            return 1;                                                           /* return error */
        }
    }
    else
    {
        handle->debug_print("dht11: reset failed.\n");                          /* reset failed */
        
        return 1;                                                               /* return error */
    }
}

/**
 * @brief      read the temperature data
 * @param[in]  *handle points to a dht11 handle structure
 * @param[out] *raw points to a raw temperature buffer
 * @param[out] *s points to a converted temperature buffer
 * @return     status code
 *             - 0 success
 *             - 1 read temperature failed
 *             - 2 handle is NULL
 *             - 3 handle is not initialized
 * @note       none
 */
uint8_t dht11_read_temperature(dht11_handle_t *handle, uint16_t *raw, float *s)
{
    uint8_t buf[5];
    uint8_t i;
    
    if (handle == NULL)                                                   /* check handle */
    {
        return 2;                                                         /* return error */
    }
    if (handle->inited != 1)                                              /* check handle initialization */
    {
        return 3;                                                         /* return error */
    }
    
    if (a_dht11_reset(handle) == 0)                                       /* reset the chip */
    {
        handle->disable_irq();                                            /* disable interrupt */
        for (i = 0; i < 5; i++)                                           /* read 5 bytes */
        {
            if (a_dht11_read_byte(handle, (uint8_t *)&buf[i]) != 0)       /* read each byte */
            {
                handle->enable_irq();                                     /* enable interrupt */
                handle->debug_print("dht11: read byte failed.\n");        /* read failed */
                
                return 1;                                                 /* return error */
            }
        }
        handle->enable_irq();                                             /* enable interrupt */

        /* 如上操作同读取湿度数据一致,不在说明 */
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])                /* calculate checksum */
        {
            /* 当温度低于0℃时温度数据的低8位的最高位置为1。如果温度低于 0℃ 温度数据的低8位的最高位作为假设的符号位 */
            if (buf[3] > 127)                                      /* if temperature is below zero */
            {
                *raw = (uint16_t)buf[2] << 8 | buf[3];                    /* get temperature raw data */
                /* 整数部分乘于10加上小数部分只要低7位的数据 */
                *s= (float)(-(buf[2] * 10 + (buf[3] & ~(1<<7)))) / 10.0f; /* convert temperature raw data to temperature real data */
            }
            else
            {
                *raw = (uint16_t)buf[2] << 8 | buf[3];                    /* get temperature raw data */
                *s= (float)(buf[2] * 10 + buf[3]) / 10.0f;                /* convert temperature raw data to temperature real data */
            }
            
            return 0;                                                     /* success return 0 */
        }
        else
        {
            handle->debug_print("dht11: data check failed.\n");           /* checksum error */
            
            return 1;                                                     /* return error */
        }
    }
    else
    {
        handle->debug_print("dht11: reset failed.\n");                    /* reset failed */
        
        return 1;                                                         /* return error */
    }
}

/**
 * @brief     initialize the chip
 * @param[in] *handle points to a dht11 handle structure
 * @return    status code
 *            - 0 success
 *            - 1 bus initialization failed
 *            - 2 handle is NULL
 *            - 3 linked functions is NULL
 *            - 4 reset failed
 * @note      none
 */
uint8_t dht11_init(dht11_handle_t *handle)
{
    if (handle == NULL)                                              /* check handle */
    {
        return 2;                                                    /* return error */
    }
    if (handle->debug_print == NULL)                                 /* check debug_print */
    {
        return 3;                                                    /* return error */
    }
    if (handle->bus_init == NULL)                                    /* check bus_init */
    {
        handle->debug_print("dht11: bus_init is null.\n");           /* bus_init is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->bus_deinit == NULL)                                  /* check bus_deinit */
    {
        handle->debug_print("dht11: bus_deinit is null.\n");         /* bus_deinit is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->bus_read == NULL)                                    /* check bus_read */
    {
        handle->debug_print("dht11: bus_read is null.\n");           /* bus_read is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->bus_write == NULL)                                   /* check bus_write */
    {
        handle->debug_print("dht11: bus_write is null.\n");          /* bus_write is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->delay_ms == NULL)                                    /* check delay_ms */
    {
        handle->debug_print("dht11: delay_ms is null.\n");           /* delay_ms is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->delay_us == NULL)                                    /* check delay_us */
    {
        handle->debug_print("dht11: delay_us is null.\n");           /* delay_us is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->enable_irq == NULL)                                  /* check enable_irq */
    {
        handle->debug_print("dht11: enable_irq is null.\n");         /* enable_irq is null */
        
        return 3;                                                    /* return error */
    }
    if (handle->disable_irq == NULL)                                 /* check disable_irq */
    {
        handle->debug_print("dht11: disable_irq is null.\n");        /* disable_irq is null */
        
        return 3;                                                    /* return error */
    }
    
    if (handle->bus_init() != 0)                                     /* initialize bus */
    {
        handle->debug_print("dht11: bus init failed.\n");            /* bus init failed */
        
        return 1;                                                    /* return error */
    }
    if (a_dht11_reset(handle) != 0)                                  /* reset the chip */
    {
        handle->debug_print("dht11: reset failed.\n");               /* reset failed */
        (void)handle->bus_deinit();                                  /* close bus */
        
        return 4;                                                    /* return error */
    }
    handle->inited = 1;                                              /* flag finish initialization */
    
    return 0;                                                        /* success return 0 */
}

/**
 * @brief     close the chip
 * @param[in] *handle points to a dht11 handle structure
 * @return    status code
 *            - 0 success
 *            - 1 bus deinit failed
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t dht11_deinit(dht11_handle_t *handle)
{
    if (handle == NULL)                                        /* check handle */
    {
        return 2;                                              /* return error */
    }
    if (handle->inited != 1)                                   /* check handle initialization */
    {
        return 3;                                              /* return error */
    }
    
    if (handle->bus_deinit() != 0)                             /* close bus */
    {
        handle->debug_print("dht11: deinit failed.\n");        /* deinit failed */
        
        return 1;                                              /* return error */
    }   
    handle->inited = 0;                                        /* flag close */
    
    return 0;                                                  /* success return 0 */
}

/**
 * @brief      get chip's information
 * @param[out] *info points to a dht11 info structure
 * @return     status code
 *             - 0 success
 *             - 2 handle is NULL
 * @note       none
 */
uint8_t dht11_info(dht11_info_t *info)
{
    if (info == NULL)                                               /* check handle */
    {
        return 2;                                                   /* return error */
    }
    
    memset(info, 0, sizeof(dht11_info_t));                          /* initialize dht11 info structure */
    strncpy(info->chip_name, CHIP_NAME, 32);                        /* copy chip name */
    strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32);        /* copy manufacturer name */
    strncpy(info->interface, "GPIO", 8);                            /* copy interface name */
    info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN;                /* set minimal supply voltage */
    info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX;                /* set maximum supply voltage */
    info->max_current_ma = MAX_CURRENT;                             /* set maximum current */
    info->temperature_max = TEMPERATURE_MAX;                        /* set minimal temperature */
    info->temperature_min = TEMPERATURE_MIN;                        /* set maximum temperature */
    info->driver_version = DRIVER_VERSION;                          /* set driver version */
    
    return 0;                                                       /* success return 0 */
}

driver_dht11_interface.h

#ifndef __DRIVER_DHT11_INTERFACE_H__
#define __DRIVER_DHT11_INTERFACE_H__

#include "driver_dht11.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @brief  interface bus init
 * @return status code
 *         - 0 success
 *         - 1 bus init failed
 * @note   none
 */
uint8_t dht11_interface_init(void);

/**
 * @brief  interface bus deinit
 * @return status code
 *         - 0 success
 *         - 1 bus deinit failed
 * @note   none
 */
uint8_t dht11_interface_deinit(void);

/**
 * @brief      interface bus read
 * @param[out] *value points to a value buffer
 * @return     status code
 *             - 0 success
 *             - 1 read failed
 * @note       none
 */
uint8_t dht11_interface_read(uint8_t *value);

/**
 * @brief     interface bus write
 * @param[in] value is the written value
 * @return    status code
 *            - 0 success
 *            - 1 write failed
 * @note      none
 */
uint8_t dht11_interface_write(uint8_t value);

/**
 * @brief     interface delay ms
 * @param[in] ms
 * @note      none
 */
void dht11_interface_delay_ms(uint32_t ms);

/**
 * @brief     interface delay us
 * @param[in] us
 * @note      none
 */
void dht11_interface_delay_us(uint32_t us);

/**
 * @brief interface enable the interrupt
 * @note  none
 */
void dht11_interface_enable_irq(void);

/**
 * @brief interface disable the interrupt
 * @note  none
 */
void dht11_interface_disable_irq(void);

/**
 * @brief     interface print format data
 * @param[in] fmt is the format data
 * @note      none
 */
void dht11_interface_debug_print(const char *const fmt, ...);


#ifdef __cplusplus
}
#endif

#endif

driver_dht11_interface.c

#include "driver_dht11_interface.h"

// static uint32_t GPIOC_IDR_ADDR = (((0x40000000UL + 0x00020000UL) + 0x0800UL) + 0x0010UL);

// static uint32_t GPIOC_ODR_ADDR = (((0x40000000UL + 0x00020000UL) + 0x0800UL) + 0x0014UL); 

/**
 * @brief  interface bus init
 * @return status code
 *         - 0 success
 *         - 1 bus init failed
 * @note   none
 */
uint8_t dht11_interface_init(void)
{
    HAL_GPIO_WritePin(DHT11_Data_GPIO_Port, DHT11_Data_Pin, GPIO_PIN_SET);

    return 0;
}

/**
 * @brief  interface bus deinit
 * @return status code
 *         - 0 success
 *         - 1 bus deinit failed
 * @note   none
 */
uint8_t dht11_interface_deinit(void)
{
    /* gpio deinit */
    HAL_GPIO_DeInit(DHT11_Data_GPIO_Port, DHT11_Data_Pin);

    return 0;
}

/**
 * @brief      interface bus read
 * @param[out] *value points to a value buffer
 * @return     status code
 *             - 0 success
 *             - 1 read failed
 * @note       none
 */
uint8_t dht11_interface_read(uint8_t *value)
{
    *value = HAL_GPIO_ReadPin(DHT11_Data_GPIO_Port, DHT11_Data_Pin);

    return 0;
}

/**
 * @brief     interface bus write
 * @param[in] value is the written value
 * @return    status code
 *            - 0 success
 *            - 1 write failed
 * @note      none
 */
uint8_t dht11_interface_write(uint8_t value)
{
    if (value)
    {
        HAL_GPIO_WritePin(DHT11_Data_GPIO_Port, DHT11_Data_Pin, GPIO_PIN_SET);
    }
    else
    {
        HAL_GPIO_WritePin(DHT11_Data_GPIO_Port, DHT11_Data_Pin, GPIO_PIN_RESET);
    }

    return 0;
}

/**
 * @brief     interface delay ms
 * @param[in] ms
 * @note      none
 */
void dht11_interface_delay_ms(uint32_t ms)
{
    delay_ms(ms);
}

/**
 * @brief     interface delay us
 * @param[in] us
 * @note      none
 */
void dht11_interface_delay_us(uint32_t us)
{
    delay_us(us);
}

/**
 * @brief interface enable the interrupt
 * @note  none
 */
void dht11_interface_enable_irq(void)
{
    /* 内联函数 用于直接操作处理器的中断控制寄存器 开启全局中断 恢复所有已启用的中断 */
    __enable_irq();
}

/**
 * @brief interface disable the interrupt
 * @note  none
 */
void dht11_interface_disable_irq(void)
{
    /* 内联函数 用于直接操作处理器的中断控制寄存器 禁用全局中断 禁用所有已启用的中断请求(不包括异常,如硬故障) */
    __disable_irq();
}

/**
 * @brief     interface print format data
 * @param[in] fmt is the format data
 * @note      none
 */
void dht11_interface_debug_print(const char *const fmt, ...)
{
    printf(fmt);
}

driver_dht11_test.h

#ifndef __DRIVER_DHT11_TEST_H__
#define __DRIVER_DHT11_TEST_H__

#include "driver_dht11_interface.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @brief     read test
 * @param[in] times is the test times
 * @return    status code
 *            - 0 success
 *            - 1 read failed
 * @note      none
 */
uint8_t dht11_read_test(uint32_t times);


#ifdef __cplusplus
}
#endif

#endif

driver_dht11_test.c

#include "driver_dht11_test.h"

static dht11_handle_t gs_handle;        /**< dht11 handle */

/**
 * @brief     read test
 * @param[in] times is the test times
 * @return    status code
 *            - 0 success
 *            - 1 read failed
 * @note      none
 */
uint8_t dht11_read_test(uint32_t times)
{
    uint8_t res;
    uint32_t i;
    uint16_t temperature_raw;
    uint16_t humidity_raw;
    float temperature;
    uint8_t humidity;
    dht11_info_t info;
   
    /* link interface function */
    DRIVER_DHT11_LINK_INIT(&gs_handle, dht11_handle_t);
    DRIVER_DHT11_LINK_BUS_INIT(&gs_handle, dht11_interface_init);
    DRIVER_DHT11_LINK_BUS_DEINIT(&gs_handle, dht11_interface_deinit);
    DRIVER_DHT11_LINK_BUS_READ(&gs_handle, dht11_interface_read);
    DRIVER_DHT11_LINK_BUS_WRITE(&gs_handle, dht11_interface_write);
    DRIVER_DHT11_LINK_DELAY_MS(&gs_handle, dht11_interface_delay_ms);
    DRIVER_DHT11_LINK_DELAY_US(&gs_handle, dht11_interface_delay_us);
    DRIVER_DHT11_LINK_ENABLE_IRQ(&gs_handle, dht11_interface_enable_irq);
    DRIVER_DHT11_LINK_DISABLE_IRQ(&gs_handle, dht11_interface_disable_irq);
    DRIVER_DHT11_LINK_DEBUG_PRINT(&gs_handle, dht11_interface_debug_print);

    /* get dht11 information */
    res = dht11_info(&info);
    if (res != 0)
    {
        dht11_interface_debug_print("dht11: get info failed.\n");
       
        return 1;
    }
    else
    {
        /* print dht11 information */
        dht11_interface_debug_print("dht11: chip is %s.\n", info.chip_name);
        // dht11_interface_debug_print("dht11: manufacturer is %s.\n", info.manufacturer_name);
        // dht11_interface_debug_print("dht11: interface is %s.\n", info.interface);
        // dht11_interface_debug_print("dht11: driver version is %d.%d.\n", info.driver_version / 1000, (info.driver_version % 1000) / 100);
        // dht11_interface_debug_print("dht11: min supply voltage is %0.1fV.\n", info.supply_voltage_min_v);
        // dht11_interface_debug_print("dht11: max supply voltage is %0.1fV.\n", info.supply_voltage_max_v);
        // dht11_interface_debug_print("dht11: max current is %0.2fmA.\n", info.max_current_ma);
        // dht11_interface_debug_print("dht11: max temperature is %0.1fC.\n", info.temperature_max);
        // dht11_interface_debug_print("dht11: min temperature is %0.1fC.\n", info.temperature_min);
    }
    
    /* start basic read test */
    dht11_interface_debug_print("dht11: start read test.\n");
    
    /* dht11 init */
    res = dht11_init(&gs_handle);
    if (res != 0)
    {
        dht11_interface_debug_print("dht11: init failed.\n");
       
        return 1;
    }
    
    /* delay 2000 ms for read */
    dht11_interface_delay_ms(2000);
    for (i = 0; i < times; i++)
    {
        /* read temperature and humidity */
        res = dht11_read_temperature_humidity(&gs_handle, (uint16_t *)&temperature_raw, (float *)&temperature, (uint16_t *)&humidity_raw, (uint8_t *)&humidity);
        if (res != 0)
        {
            dht11_interface_debug_print("dht11: read failed.\n");
            (void)dht11_deinit(&gs_handle);
           
            return 1;
        }
    
        /* print result */
        dht11_interface_debug_print("dht11: temperature_raw: %dC.\n", temperature_raw);
        dht11_interface_debug_print("dht11: humidity_raw: %dC.\n", humidity_raw);
        dht11_interface_debug_print("dht11: temperature: %.01fC.\n", temperature);
        dht11_interface_debug_print("dht11: humidity: %d%%.\n", humidity);

        /* delay 2000 ms*/
        dht11_interface_delay_ms(2000);
    }

    /* finish basic read test and exit */
    dht11_interface_debug_print("dht11: finish read test.\n");
    (void)dht11_deinit(&gs_handle);
    
    return 0;
}

总结

《HAL快速入门与项目实战(基于DshanMCU-F407)_V1.0》中已经有对DHT11模块的详细讲解,这里对驱动程序进行了简单的复写。

能力有限,有错误地方欢迎指正。