#申请原创# @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屏幕,可以做个简单地温湿度监测器
|