一、DHT11时序
采集范围:温度0-50°±2°,湿度:20-90%RH。
采用单总线双向串行通信协议,每次采集都要由单片机发起开始信号,然后DHT11会向单片机发送响应并开始传输40位数据帧,高位在前。数据格式为:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位,温湿度小数部分默认为0,即单片机采集的数据都是整数,校验位为4个字节的数据相加取结果的低8位数据作为校验和:
时序图:
二、DHT11驱动程序编写
选择引脚
选择一个引脚,我这里选择PA5,然后生成代码。
把H文件放在对应目录,然后编译。
三、主要代码
main.c
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "DHT11.h"
#include "string.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern uint8_t Data[5];
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
/* USER CODE BEGIN 3 */
while (1)
{
/* USER CODE END WHILE */
if (DHT_Read())
{
char buffer[50];
int temperature = Data[2];
int humidity = Data[0];
snprintf(buffer, sizeof(buffer), "temp: %d, humi: %d", temperature, humidity);
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
}
HAL_Delay(3000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
dht11.c
#include "stm32f1xx.h"
#include "tim.h"
#include "DHT11.h"
uint8_t Data[5]={0x00,0x00,0x00,0x00,0x00};//存储温湿度
//微妙延时
void Delay_us(uint16_t us)
{
uint16_t dif=0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim1,dif);//设置TIM1计数器起始值
HAL_TIM_Base_Start(&htim1);//启动
while(dif<0xffff-5)
{
dif=__HAL_TIM_GET_COUNTER(&htim1);//查询计数
}
HAL_TIM_Base_Stop(&htim1);
}
void DHT_GPIO_SET_OUTPUT(void)//输出
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void DHT_GPIO_SET_INPUT(void)//输入
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
uint8_t DHT_Read_Byte(void)//读取一位信号
{
uint8_t ReadData=0;//存放8bit数据
uint8_t temp; //临时存放信号电平
uint8_t retry=0; //
uint8_t i;
for(i=0;i<8;i++)//一次读取8位
{
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0&&retry<100)//等待DHT11输出高电平
{
Delay_us(1);
retry++;
}
retry=0;
Delay_us(40);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1)
{
temp=1;
}
else
temp=0;
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
ReadData<<=1;//左移
ReadData |=temp;
}
return ReadData;
}
//DHT11读取温湿度程序
uint8_t DHT_Read(void)
{
uint8_t retry=0;
uint8_t i;
DHT_GPIO_SET_OUTPUT();//IO设置为输出模式
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);//拉低电平18ms
HAL_Delay(18);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//拉高电平20us
Delay_us(20);
DHT_GPIO_SET_INPUT();
Delay_us(20);
//如果检测到低电平,说明DHT11有响应
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0)
{
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;
//一次传输40位,一次返回8位,共读取5次
for(i=0;i<5;i++)
{
Data[i]=DHT_Read_Byte();
}
Delay_us(50);
}
//校验
uint32_t sum=Data[0]+Data[1]+Data[2]+Data[3];
if((sum)==Data[4])
return 1;
else
return 0;
}
dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f1xx.h"
void Delay_us(uint16_t us);
void DHT_GPIO_SET_OUTPUT(void);
void DHT_GPIO_SET_INPUT(void);
uint8_t DHT_Read_Byte(void);
uint8_t DHT_Read(void);
uint8_t DHT_Read_Data(uint8_t* temp , uint8_t* humi);
#endif
四、结果显示
将代码调试运行后,烧录到板子上,打开串口调试助手,结果如下: