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

📅 2026/7/15 16:00:52
用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 数据湿度数据温度数据校验值结束信号可选。具体过程如下总线空闲状态为高电平主机拉低总线等待 DHT11 响应, 主机把总线拉低必须大于 18ms保证 DHT11 能检测到起始信号主机发送开始信号结束后拉高总线电平并延时等待 20-40us 后读取 DHT11 的响应信号DHT11 接收到主机的开始信号后等待微处理器开始信号结束发送 80us 低电平响应信号DHT11 发送 80us 高电平准备发送数据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); #endifdht11.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 retry0; DHT11_IO_IN(); // 把引脚设置为输入模式 while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)1retry100){ //等待拉低40~80us retry; delay_us(1); }; if(retry100)return 1; else retry0; while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)0retry100){ //拉低40~80us retry; delay_us(1); }; if(retry100)return 1; return 0; //检测到DHT11返回0 } uint8_t DHT11_Read_Bit(void){ uint8_t retry0; while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)1retry100){ //等待变为低电平 retry; delay_us(1); } retry0; while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)0retry100){ //等待变为高电平 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; dat0; for (i0;i8;i){ dat1; 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(i0;i5;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.PinGPIO_PIN_12; GPIO_Initure.ModeGPIO_MODE_OUTPUT_PP; GPIO_Initure.PullGPIO_PULLUP; GPIO_Initure.SpeedGPIO_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 *)Data0,1,HAL_MAX_DELAY); //湿度 HAL_Delay(500); } //Data[1]0x12; //HAL_UART_Transmit(huart1,(uint8_t *)Data1,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,temperature8,temperature0xff); printf(DHT11 Humidity %d.%d%%\r\n,humidity8,humidity0xff); 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时间接着拉高数据线t220 ~ 40us时间然后读取DHT11的响应正常的话DHT11会拉低数据线并保持t340 ~ 50us时间作为响应信号接着DHT11拉高数据线并保持t440 ~ 50us时间后开始传输数据.要读取五次数据如何判断传递的数据是0 还是1printf重定向int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xffff); return ch; }参考STM32 printf重定向串口输出