当前位置:   article > 正文

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

江科大 hal

 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。

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

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

为精确延时微秒:

代码是:

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

 增加2个文件:

dht11.h

  1. #ifndef __DHT11_H
  2. #define __DHT11_H
  3. #include "stm32f1xx.h"
  4. #define DHT11_DQ_IN !HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)
  5. void DHT11_IO_IN(void);
  6. void DHT11_IO_OUT(void);
  7. void DHT11_Rst(void);
  8. uint8_t DHT11_Check(void);
  9. uint8_t DHT11_Read_Bit(void);
  10. uint8_t DHT11_Read_Byte(void);
  11. uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi);
  12. uint8_t DHT11_Init(void);
  13. #endif

 dht11.c:

  1. #include "stm32f1xx.h"
  2. #include "tim.h"
  3. #include "dht11.h"
  4. void DHT11_IO_IN(void){ //IO口方向设置为输入
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. GPIO_InitStructure.Pin = GPIO_PIN_12;
  7. GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
  8. HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
  9. }
  10. void DHT11_IO_OUT(void){ //IO口方向设置为输出
  11. GPIO_InitTypeDef GPIO_InitStructure;
  12. GPIO_InitStructure.Pin = GPIO_PIN_12;
  13. GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  14. GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  15. HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
  16. }
  17. void DHT11_Rst(void){
  18. DHT11_IO_OUT(); //设置为输出
  19. //DHT11_DQ_OUT_LOW; //拉低
  20. HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
  21. HAL_Delay(20); //至少18ms
  22. //DHT11_DQ_OUT_HIGH; //拉高
  23. HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET); //IO->DHT11:随后拉高电平20us
  24. delay_us(30); //至少20~40us
  25. }
  26. uint8_t DHT11_Check(void){
  27. uint8_t retry=0;
  28. DHT11_IO_IN(); // 把引脚设置为输入模式
  29. while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1&&retry<100){ //等待拉低40~80us
  30. retry++;
  31. delay_us(1);
  32. };
  33. if(retry>=100)return 1;
  34. else retry=0;
  35. while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==0&&retry<100){ //拉低40~80us
  36. retry++;
  37. delay_us(1);
  38. };
  39. if(retry>=100)return 1;
  40. return 0; //检测到DHT11返回0
  41. }
  42. uint8_t DHT11_Read_Bit(void){
  43. uint8_t retry=0;
  44. while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1&&retry<100){ //等待变为低电平
  45. retry++;
  46. delay_us(1);
  47. }
  48. retry=0;
  49. while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==0&&retry<100){ //等待变为高电平
  50. retry++;
  51. delay_us(1);
  52. }
  53. delay_us(40); //高电平下等待40us
  54. if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)==1)return 1; // 经过上面的等待 还是高电平的话,那说明是1,因为高电平要持续70微秒
  55. else return 0;
  56. }
  57. uint8_t DHT11_Read_Byte(void){
  58. uint8_t i,dat;
  59. dat=0;
  60. for (i=0;i<8;i++){
  61. dat<<=1;
  62. dat|=DHT11_Read_Bit();
  63. }
  64. return dat;
  65. }
  66. uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi){
  67. uint8_t buf[5];
  68. uint8_t i;
  69. DHT11_Rst();
  70. if(DHT11_Check()==0){ // dth11 正常相应了,则开始读取dht11的数据
  71. for(i=0;i<5;i++){
  72. buf[i]=DHT11_Read_Byte();
  73. }
  74. if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){
  75. *humi=(buf[0]<<8) + buf[1];
  76. *temp=(buf[2]<<8) + buf[3];
  77. }
  78. }else return 1;
  79. return 0;
  80. }
  81. uint8_t DHT11_Init(void){
  82. GPIO_InitTypeDef GPIO_Initure; //PB12的初始化已经在cubemx中完成,可以忽略此段初始化代码
  83. __HAL_RCC_GPIOB_CLK_ENABLE();
  84. GPIO_Initure.Pin=GPIO_PIN_12;
  85. GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
  86. GPIO_Initure.Pull=GPIO_PULLUP;
  87. GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;
  88. HAL_GPIO_Init(GPIOB,&GPIO_Initure);
  89. DHT11_Rst();
  90. return DHT11_Check();
  91. }

 main函数中测试代码:

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2024 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "tim.h"
  22. #include "usart.h"
  23. #include "gpio.h"
  24. #include "stdio.h"
  25. /* Private includes ----------------------------------------------------------*/
  26. /* USER CODE BEGIN Includes */
  27. #include "DHT11.h"
  28. /* USER CODE END Includes */
  29. /* Private typedef -----------------------------------------------------------*/
  30. /* USER CODE BEGIN PTD */
  31. /* USER CODE END PTD */
  32. /* Private define ------------------------------------------------------------*/
  33. /* USER CODE BEGIN PD */
  34. /* USER CODE END PD */
  35. /* Private macro -------------------------------------------------------------*/
  36. /* USER CODE BEGIN PM */
  37. /* USER CODE END PM */
  38. /* Private variables ---------------------------------------------------------*/
  39. /* USER CODE BEGIN PV */
  40. uint8_t Data[5]={0x01,0x02,0x03,0x04,0x05}; //Data存储读取的温湿度信息
  41. /* USER CODE END PV */
  42. /* Private function prototypes -----------------------------------------------*/
  43. void SystemClock_Config(void);
  44. /* USER CODE BEGIN PFP */
  45. /* USER CODE END PFP */
  46. /* Private user code ---------------------------------------------------------*/
  47. /* USER CODE BEGIN 0 */
  48. int fputc(int ch, FILE *f)
  49. {
  50. HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  51. return ch;
  52. }
  53. /* USER CODE END 0 */
  54. /**
  55. * @brief The application entry point.
  56. * @retval int
  57. */
  58. int main(void)
  59. {
  60. /* USER CODE BEGIN 1 */
  61. uint16_t temperature;
  62. uint16_t humidity;
  63. /* USER CODE END 1 */
  64. /* MCU Configuration--------------------------------------------------------*/
  65. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  66. HAL_Init();
  67. /* USER CODE BEGIN Init */
  68. /* USER CODE END Init */
  69. /* Configure the system clock */
  70. SystemClock_Config();
  71. /* USER CODE BEGIN SysInit */
  72. /* USER CODE END SysInit */
  73. /* Initialize all configured peripherals */
  74. MX_GPIO_Init();
  75. MX_USART1_UART_Init();
  76. MX_TIM1_Init();
  77. /* USER CODE BEGIN 2 */
  78. if(DHT11_Init()){
  79. //printf("DHT11 Checked failed!!!\r\n");
  80. HAL_UART_Transmit(&huart1,(uint8_t *)Data+0,1,HAL_MAX_DELAY); //湿度
  81. HAL_Delay(500);
  82. }
  83. //Data[1]=0x12;
  84. //HAL_UART_Transmit(&huart1,(uint8_t *)Data+1,1,HAL_MAX_DELAY); //湿度
  85. /* USER CODE END 2 */
  86. /* Infinite loop */
  87. /* USER CODE BEGIN WHILE */
  88. while (1)
  89. {
  90. DHT11_Read_Data(&temperature,&humidity);
  91. printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
  92. printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);
  93. HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
  94. HAL_Delay(500);
  95. /* USER CODE END WHILE */
  96. /* USER CODE BEGIN 3 */
  97. }
  98. /* USER CODE END 3 */
  99. }
  100. /**
  101. * @brief System Clock Configuration
  102. * @retval None
  103. */
  104. void SystemClock_Config(void)
  105. {
  106. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  107. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  108. /** Initializes the RCC Oscillators according to the specified parameters
  109. * in the RCC_OscInitTypeDef structure.
  110. */
  111. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  112. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  113. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  114. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  115. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  116. {
  117. Error_Handler();
  118. }
  119. /** Initializes the CPU, AHB and APB buses clocks
  120. */
  121. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  122. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  123. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  124. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  125. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  126. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  127. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  128. {
  129. Error_Handler();
  130. }
  131. }
  132. /* USER CODE BEGIN 4 */
  133. /* USER CODE END 4 */
  134. /**
  135. * @brief This function is executed in case of error occurrence.
  136. * @retval None
  137. */
  138. void Error_Handler(void)
  139. {
  140. /* USER CODE BEGIN Error_Handler_Debug */
  141. /* User can add his own implementation to report the HAL error return state */
  142. __disable_irq();
  143. while (1)
  144. {
  145. }
  146. /* USER CODE END Error_Handler_Debug */
  147. }
  148. #ifdef USE_FULL_ASSERT
  149. /**
  150. * @brief Reports the name of the source file and the source line number
  151. * where the assert_param error has occurred.
  152. * @param file: pointer to the source file name
  153. * @param line: assert_param error line source number
  154. * @retval None
  155. */
  156. void assert_failed(uint8_t *file, uint32_t line)
  157. {
  158. /* USER CODE BEGIN 6 */
  159. /* User can add his own implementation to report the file name and line number,
  160. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  161. /* USER CODE END 6 */
  162. }
  163. #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重定向:

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/655667
推荐阅读
相关标签
  

闽ICP备14008679号