赞
踩
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 数据(湿度数据+温度数据+校验值),结束信号(可选)。具体过程如下:
总流程讲完介绍一下细分流程:
首先主机拉低总线至少 18ms,然后再拉高总线,延时 20~40us,此时起始信号(有时也叫复位信号)发送完毕。
DHT11 检测到复位信号后,触发一次采样,并拉低总线 80us 表示响应信号,告诉主机数据已经准备好了。DHT11 之后拉高总线 80us,然后开始传输数据。如果检测到响应信号为高电平,则 DHT11 初始化失败,请检查线路是否连接正常。
DHT11 开始传输数据。每 1bit 数据都以 50us 低电平开始,告诉主机开始传输一位数据了。DHT11 以高电平的长短定义数据位是 0 还是 1:当 50us 低电平过后拉高总线,高电平持续 26~28us 表示 0,高电平持续 70us 表示数据 1。
当最后 1bit 数据传送完毕后,DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。
位数据0表示方式:
以 50us 低电平开始,高电平持续 26~28us 表示 0。
位数据1表示方式:
以 50us 低电平开始,高电平持续 70us 表示 1。
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;
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。