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