话不多说,先上DHT22的时序图。
DHT22响应
即1. 总线先输出低电平(至少500us),之后总线再输出高电平(20~40us)。
2. DHT22接受到信号之后,发出响应,首先拉低总线80us,之后再次拉高总线80us之后开始数据传输。
DHT22开始传输数据
数据传输过程如图
首先DHT22会拉低总线50us,之后开始拉高总线进行数据传输,当高电平持续70us时,代表数据“1”,26~28us时代表数据“0”,之后重复,直至数据传输完成。
DHT22数据格式
此时要注意的是传感器输出的温湿度值要除以10才得到真正的温湿度值
之后我们根据时序图开始编写代码
/****************************************************************
title:DHT22.h
****************************************************************/
#ifndef __DHT22_H
#define __DHT22_H
#include "gd32f4xx.h"
#include "systick.h"
//宏定义,DHT22的GPIO口和引脚
#define DHT22_Pin GPIO_PIN_4
#define DHT22_GPIO GPIOA
#define DHT22_RCU RCU_GPIOA
//DHT22作为从机发送给主机信号,所以是读取DHT11的GPIO口和引脚的输入状态
#define DHT22_Input gpio_input_bit_get(DHT22_GPIO,DHT22_Pin)
//主机发送开始信号。拉低数据线,然后拉高数据线t2时间,然后读取DHT22的响应。
#define DHT22_Low gpio_bit_reset(DHT22_GPIO,DHT22_Pin)
#define DHT22_High gpio_bit_set(DHT22_GPIO,DHT22_Pin)
//初始化DHT11的IO口
void DHT22_Init(void);
//主机需要发送开始信号,然后读取数据。
//这是配置DHT11的输入输出模式
//cmd = 1,配置为输出模式
//cmd = 0,配置为输入模式
void DHT22_Read_Out_Input(uint8_t cmd);
//复位DHT22
void DHT22_Rst(void);
//等待DHT22的回应
//返回1:未检测到DHT22的存在
//返回0:存在 出现由低到高的变化即可
uint8_t DHT22_Check(void) ;
//从DHT22读取一个位
//返回值:1/0
uint8_t DHT22_Read_Bit(void) ;
//从DHT22读取一个字节
//返回值:读到的数据
uint8_t DHT22_Read_Byte(void) ;
//从DHT22读取一次数据
//temp:温度值(范围:-40--80°)
//humi:湿度值(范围:0%--99.9%)
//返回值:0,正常;1,读取失败
uint8_t DHT22_Read_Data(float *temp,float *humi) ;
#endif
/***************************************************
title:DHT22.c
***************************************************/
#include "gd32f4xx.h"
#include "DHT22.h"
#include "systick.h"
//初始化DHT22的IO口
void DHT22_Init(void)
{
rcu_periph_clock_enable(DHT22_RCU);//开启时钟
gpio_mode_set(DHT22_GPIO,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,DHT22_Pin);
gpio_output_options_set(DHT22_GPIO,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,DHT22_Pin);
}
//主机需要发送开始信号,然后读取数据。
//这是配置DHT22的输入输出模式
//cmd = 1,配置为输出模式
//cmd = 0,配置为输入模式
void DHT22_Read_Out_Input(uint8_t cmd)
{
if(cmd == 1)
{
gpio_mode_set(DHT22_GPIO,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,DHT22_Pin);
gpio_output_options_set(DHT22_GPIO,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,DHT22_Pin);
}
else
{
gpio_mode_set(DHT22_GPIO,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,DHT22_Pin);
}
}
//复位DHT22
void DHT22_Rst(void)
{
DHT22_Read_Out_Input(1); //SET OUTPUT
DHT22_Low; //拉低DQ
delay_1ms(1); //拉低至少500us,此处1ms
DHT22_High; //DQ=1
delay_1us(30); //主机拉高20~40us(这里是我自定义修改的函数,原函数库中是没有1us的延时函数的)
}
//等待DHT22的回应
//返回1:未检测到DHT22的存在
//返回0:存在 出现由低到高的变化即可
uint8_t DHT22_Check(void)
{
uint8_t retry=0;
DHT22_Read_Out_Input(0); //SET INPUT
while (DHT22_Input==SET&&retry<100)//DHT22会拉低80us左右
{
retry++;
delay_1us(1);
}
if(retry>=100)return 1;
else retry=0;
while (DHT22_Input==RESET&&retry<100)//DHT22拉低后会再次拉高80us左右
{
retry++;
delay_1us(1);
}
if(retry>=100)return 1;
return 0;
}
//从DHT22读取一个位
//返回值:1/0
uint8_t DHT22_Read_Bit(void)
{
uint8_t retry=0;
while(DHT22_Input==SET&&retry<100)//等待变为低电平
{
retry++;
delay_1us(1);
}
retry=0;
while(DHT22_Input==RESET&&retry<100)//等待变高电平
{
retry++;
delay_1us(1);
}
delay_1us(40);//等待40us
if(DHT22_Input==SET)return 1;
else return 0;
}
//从DHT22读取一个字节
//返回值:读到的数据
uint8_t DHT22_Read_Byte(void)
{
uint8_t i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT22_Read_Bit();
}
return dat;
}
//从DHT22读取一次数据
//temp:温度值(范围:-40--80°)
//humi:湿度值(范围:0%--99.9%)
//返回值:0,正常;1,读取失败
uint8_t DHT22_Read_Data(float *temp,float *humi)
{
uint8_t buf[5];
uint8_t i;
DHT22_Rst();
if(DHT22_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT22_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=((float)((buf[0]<<8)+buf[1]))/10;
*temp=((float)((buf[2]<<8)+buf[3]))/10;
}
}else return 1;
return 0;
}
/***********************************************
title:main.c
*********************************************************/
/*!
\file main.c
\brief led spark with systick
\version 2016-08-15, V1.0.0, firmware for GD32F4xx
\version 2018-12-12, V2.0.0, firmware for GD32F4xx
\version 2020-09-30, V2.1.0, firmware for GD32F4xx
\version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/
/*
Copyright (c) 2022, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "sys.h"
#include "bsp_usart.h"
#include "DHT22.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
float temp,humi;
systick_config();//滴答定时器分频
led_gpio_config();//led初始化
usart_gpio_config(9600);//串口初始化,并且设置波特率为9600
DHT22_Init();//DHT22初始化
DHT22_Rst();//DHT22复位
delay_1ms(1000);
while(1)
{
if(DHT22_Read_Data(&temp,&humi)==0)
{
printf("temp=%.2f,humi=%.2f/n",temp,humi);
}
}
}