用HAL库改写江科大的stm32入门例子-补充DHT11

 DHT11引脚

实验目的:

读取环境温湿度 通过串口传给电脑。 会根据时序编程。了解单总线。

整体步骤:

step1:接好线.

step2:cubeMX创建项目.

step3:copy 这个模块的驱动

硬件介绍:

这种4引脚的要接入上拉电阻

同样可以测量温湿度的还有 DHT20、DHT22 等,都是大同小异。

DHT11 虽然可以同时测量温湿度,但是测量范围是打不过专业测温传感器的,比如 ds18b20 测量的温度范围就有 -55°C ~ 125°C,而 DHT11 只有 0~50℃。

DHT11采用单总线数据格式,即单个数据引脚端口完成输入输出双向传输。其数据包由5个字节(40Bit)组成。数据分小数和整数部分,一次完整的数据传输为40bit,高位先出。数据格式如下图示


根据以上数据,即可算出温度和湿度的值,计算方法如下:

湿度 = byte4.byte3
温度 = byte2.byte1
校验 = byte4 + byte3 + byte2 + byte1
 

 整体工作时序

DHT11 整体工作时序为:主机发送开始信号、DHT11 响应输出、主机接收 40bit 数据(湿度数据+温度数据+校验值),结束信号(可选)。具体过程如下:

  1. 总线空闲状态为高电平,主机拉低总线等待 DHT11 响应, 主机把总线拉低必须大于 18ms,保证 DHT11 能检测到起始信号;
  2. 主机发送开始信号结束后,拉高总线电平并延时等待 20-40us 后,读取 DHT11 的响应信号;
  3. DHT11 接收到主机的开始信号后,等待微处理器开始信号结束,发送 80us 低电平响应信号;
  4. DHT11 发送 80us 高电平准备发送数据;
  5. DHT11 发送 40bit 数据(湿度数据+温度数据+校验值)。

 起始及响应信号

总流程讲完介绍一下细分流程:

首先主机拉低总线至少 18ms,然后再拉高总线,延时 20~40us,此时起始信号(有时也叫复位信号)发送完毕。

DHT11 检测到复位信号后,触发一次采样,并拉低总线 80us 表示响应信号,告诉主机数据已经准备好了。DHT11 之后拉高总线 80us,然后开始传输数据。如果检测到响应信号为高电平,则 DHT11 初始化失败,请检查线路是否连接正常。

3.2.3 读时序

DHT11 开始传输数据。每 1bit 数据都以 50us 低电平开始,告诉主机开始传输一位数据了。DHT11 以高电平的长短定义数据位是 0 还是 1:当 50us 低电平过后拉高总线,高电平持续 26~28us 表示 0,高电平持续 70us 表示数据 1。

当最后 1bit 数据传送完毕后,DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。

位数据0表示方式:

以 50us 低电平开始,高电平持续 26~28us 表示 0。

位数据1表示方式:

以 50us 低电平开始,高电平持续 70us 表示 1。

3.3 DHT11数据格式

DHT11 的 DATA 传输一次完整的数据为 40bit,按照高位在前,低位在后的顺序传输。

数据格式为:8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位,一共 5 字节(40bit)数据。

正常情况下,前四个字节的和刚好与校验位相等,通过这种机制可以保证数据传输的准确性。

设置data引脚,我这里用的是PB12。

由于要用到串口发送测量到的数据,设置一下串口:

设置定时器,控制精确延时的秒数:

为精确延时微秒:

代码是:

void delay_us(uint16_t us){
	uint16_t differ = 0xffff-us-5;				
	__HAL_TIM_SET_COUNTER(&htim1,differ);	//设定TIM7计数器起始值
	HAL_TIM_Base_Start(&htim1);		//启动定时器	
	
	while(differ < 0xffff-5){	//判断
		differ = __HAL_TIM_GET_COUNTER(&htim1);		//查询计数器的计数值
	}
	HAL_TIM_Base_Stop(&htim1);
}

 增加2个文件:

dht11.h

#ifndef __DHT11_H
#define __DHT11_H

#include "stm32f1xx.h"

#define DHT11_DQ_IN !HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)  


void DHT11_IO_IN(void);

void DHT11_IO_OUT(void);

void DHT11_Rst(void);

uint8_t DHT11_Check(void);

uint8_t DHT11_Read_Bit(void);

uint8_t DHT11_Read_Byte(void);

uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi);
  	 
uint8_t DHT11_Init(void);
#endif 

 dht11.c:

#include "stm32f1xx.h"
#include "tim.h"
#include "dht11.h"

  


void DHT11_IO_IN(void){		//IO口方向设置为输入
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_12;
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
	HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}

void DHT11_IO_OUT(void){	//IO口方向设置为输出
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_12;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}

void DHT11_Rst(void){                 
	DHT11_IO_OUT(); 	//设置为输出
	//DHT11_DQ_OUT_LOW; 	//拉低
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET); 
	HAL_Delay(20);    	//至少18ms
	//DHT11_DQ_OUT_HIGH; 	//拉高
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);   //IO->DHT11:随后拉高电平20us
	delay_us(30);     	//至少20~40us
}

uint8_t DHT11_Check(void){   
	uint8_t retry=0;
	DHT11_IO_IN();    // 把引脚设置为输入模式
	while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1&&retry<100){	//等待拉低40~80us 
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
	while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==0&&retry<100){ //拉低40~80us 
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;	//检测到DHT11返回0
}

uint8_t DHT11_Read_Bit(void){
 	uint8_t retry=0;
	while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1&&retry<100){	//等待变为低电平
		retry++;
		delay_us(1);
	}
	retry=0;
	while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==0&&retry<100){	//等待变为高电平
		retry++;
		delay_us(1);
	}
	delay_us(40);	//高电平下等待40us
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1)return 1;    // 经过上面的等待 还是高电平的话,那说明是1,因为高电平要持续70微秒
	else return 0;		   
}

uint8_t DHT11_Read_Byte(void){        
	uint8_t i,dat;
	dat=0;
	for (i=0;i<8;i++){
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}

uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi){        
 	uint8_t buf[5];
	uint8_t i;
	DHT11_Rst();
	if(DHT11_Check()==0){   // dth11 正常相应了,则开始读取dht11的数据
		for(i=0;i<5;i++){
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){
			*humi=(buf[0]<<8) + buf[1];
			*temp=(buf[2]<<8) + buf[3];
		}
	}else return 1;
	return 0;	    
}
  	 
uint8_t DHT11_Init(void){
    GPIO_InitTypeDef GPIO_Initure;	//PB12的初始化已经在cubemx中完成,可以忽略此段初始化代码
    __HAL_RCC_GPIOB_CLK_ENABLE();			
    GPIO_Initure.Pin=GPIO_PIN_12;           
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  
    GPIO_Initure.Pull=GPIO_PULLUP;         
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);    
    DHT11_Rst();
	return DHT11_Check();
}

 main函数中测试代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "DHT11.h"
/* 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 */
uint8_t Data[5]={0x01,0x02,0x03,0x04,0x05};   //Data存储读取的温湿度信息

/* 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 */
int fputc(int ch, FILE *f)
 
{
 
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
 
  return ch;
 
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
  uint16_t temperature;
  uint16_t humidity;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  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_USART1_UART_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	  if(DHT11_Init()){
    //printf("DHT11 Checked failed!!!\r\n");
              

		HAL_UART_Transmit(&huart1,(uint8_t *)Data+0,1,HAL_MAX_DELAY);    //湿度
			HAL_Delay(500);
  }
		//Data[1]=0x12;
  //HAL_UART_Transmit(&huart1,(uint8_t *)Data+1,1,HAL_MAX_DELAY);    //湿度

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    DHT11_Read_Data(&temperature,&humidity);
    printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
    printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);       
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    HAL_Delay(500);

		
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

代码说明:

reset代码的依据如图(有mcu向DHT传递信号,先拉低,再拉高):

  check代码的依据的时序图对照:

数据发送时序:首先主机发送开始信号,即拉低数据线保持t1(至少18ms)时间,接着拉高数据线t2(20 ~ 40us)时间;然后读取DHT11的响应,正常的话DHT11会拉低数据线并保持t3(40 ~ 50us)时间作为响应信号,接着DHT11拉高数据线并保持t4(40 ~ 50us)时间后,开始传输数据.

要读取五次数据: 

如何判断传递的数据是0 还是1:

 

printf重定向:

int fputc(int ch, FILE *f)
 
{
 
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
 
  return ch;
 
}

参考:STM32 printf重定向(串口输出)

  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
DHT11是一种数字温湿度传感器,可以通过STM32的GPIO口读取其数据。下面是使用HAL库获取DHT11数据的步骤: 1. 配置GPIO口为输出模式,并将输出电平置为高电平,等待至少18ms。 2. 将GPIO口置为输入模式,并等待DHT11的响应信号(低电平持续至少80us,高电平持续至少80us)。 3. 接收40位数据,每一位数据的持续时间为50us,通过判断数据持续时间的长短来判断数据位是0还是1。 以下是示例代码,供参考: ```c #include "stm32f1xx_hal.h" #define DHT11_PIN GPIO_PIN_0 #define DHT11_PORT GPIOA void DHT11_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = DHT11_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); } void DHT11_ReadData(uint8_t *data) { uint8_t i, j, byteIndex = 0; uint8_t bits[5] = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = DHT11_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET); HAL_Delay(18); HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); HAL_Delay(40); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct); if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET) { while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET) ; while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) ; for (i = 0; i < 40; i++) { while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET) ; j = 0; while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) { j++; HAL_Delay(1); } if (j > 25) bits[byteIndex] |= (1 << (7 - i % 8)); if (i % 8 == 7) byteIndex++; } if ((uint8_t)(bits[0] + bits[1] + bits[2] + bits[3]) == bits[4]) { data[0] = bits[0]; data[1] = bits[2]; } } } ``` 在主函数中,可以使用以下代码读取DHT11数据: ```c uint8_t dht11_data[2] = {0}; DHT11_Init(); DHT11_ReadData(dht11_data); ``` 读取到的数据中,dht11_data[0]为湿度值,dht11_data[1]为温度值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值