实验课程

THIS NAME

实验课程

当前位置: 首页 >> 实验课程 >> 正文

嵌入式Cortex-M应用-温度检测实验

发布日期:2024-08-19    作者:陆其美     来源:     点击:

温度检测实验

一、实验目的

1.串行总线的使用方法

2.stm32串口1的复习

3.DHT11温湿度传感器的使用

二、实验内容

利用STM32F103C8T6GPIO获取dht11温湿度传感器采集到的温度信息并通过stm32的串口1打印出来。

三、实验原理及说明

1、串行总线的使用方法

DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:

一次完整的数据传输为40bit,高位先出。

数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和。

数据传送正确时校验和数据等于8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

用户MCU发送一次开始信号后, DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后, DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号, DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。

2stm32串口1复习

stm32串口1使用PA10作为RX端接收数据,使用PA9作为TX端发送数据。详细内容可参考前面章节。

3DHT11传感器介绍

DHT11是一个温湿度传感器,有三个需要连接的外设引脚,除了VSS和GND,传输数据的data引脚需要和stm32单片机的PB2引脚进行串行单向数据传输。详细信息如下图所示。

undefined

四、实验设备

一套stm32开发板,头歌实验平台

五、实验步骤

1.1 双击打开软件 stm32cubemx。

undefined

1.2 开始创建工程,本次实训采用的开发板MCU型号为STM32F103C8T6,所以直接根据MCU配置工程,打开软件后选择 access to mcu selector。

undefined

1.3 搜索芯片STM32F103C8T6,并选择芯片型号 STM32F103C8T6 ,并点击“start project”创建工程。

undefined

1.4 芯片选择完成后,进入配置界面,配置分为如下几类:

l System Core 用于配置MCU核心功能,如时钟,中断,调试接口等;

l Analog 用于配置MCU的ADC功能;

l Timers 用于配置MCU的定时器;

l Connectivity 用于配置MCU外设接口,如SPI,USART,CAN等;

l Computing 用于配置MCU的CRC校验

l Middleware 用于配置MCU的中间件,如文件系统,实时操作系统等; 学院可以根据实际需要,选择相应的功能配置,过程如下: 展开“system core”标签,找到“SYS"选项,在右边选择如图所示配置调试接口为JTAG 5脚接口,如果是其他接口,按照需要选择,配置完成后,右边的MCU预览图相应管脚会显示为绿色。

undefined

1.5 切换到”RCC“标签,配置系统时钟,本实验用到的开发板主时钟使用8MHz晶振,备份域时钟使用32.768kHz时钟,分别接在MCU的相应引脚上,所以在配置的时候HSE(高速外部时钟)选择使用外部晶振(crystal),LSE(低速外部时钟)选择使用外部晶振(crystal),具体如图所示。

undefined

1.6 选择GPIO,在PB2上选择GPIO_Out输出,因为是单向传输,而它的数据传输方向根据需求而实时改变,这里暂时设置为输出模式。设置初始初始状态为高电平,传输速率为高速,引脚简称DHT11_DA.具体如图所示。

undefined

1.7 切换到“Connectivity”标签,在实验过程中需要使用串口打印信息,所以需要配置串口功能,此处选择USART1,配置为异步通信,其他参数(奇偶校验,波特率等)使用默认即可,按照如图所示配置“USART1”

undefined

1.8 配置系统时钟为72M,点击电脑确认键并编译环境。

undefined

1.9 配置工程命名为DHT11并生成代码,具体如图所示。

undefined

1.10 为项目添加一个C语言源文件,命名为“retarget.c”,如图所示

undefined

在文件中添加如下代码:

/*

* retarget.c

*

*  Created on: 2021��10��20��

*      Author: Administrator

*/

#include <_ansi.h>

#include <_syslist.h>

#include <errno.h>

#include <sys/time.h>

#include <sys/times.h>

#include <limits.h>

#include <signal.h>

#include <../Inc/retarget.h>

#include <stdint.h>

#include <stdio.h>

#if !defined(OS_USE_SEMIHOSTING)

#define STDIN_FILENO  0

#define STDOUT_FILENO 1

#define STDERR_FILENO 2

UART_HandleTypeDef *gHuart;

void RetargetInit(UART_HandleTypeDef *huart)  {

 gHuart = huart;

 /* Disable I/O buffering for STDOUT  stream, so that

  * chars are sent out as soon as they are  printed. */

 setvbuf(stdout, NULL, _IONBF, 0);

}

int _isatty(int fd) {

 if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)

   return 1;

 errno = EBADF;

 return 0;

}

int _write(int fd, char* ptr, int len) {

 HAL_StatusTypeDef hstatus;

 if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {

   hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);

   if (hstatus == HAL_OK)

     return len;

   else

     return EIO;

 }

 errno = EBADF;

 return -1;

}

int _close(int fd) {

 if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)

   return 0;

 errno = EBADF;

 return -1;

}

int _lseek(int fd, int ptr, int dir) {

 (void) fd;

 (void) ptr;

 (void) dir;

 errno = EBADF;

 return -1;

}

int _read(int fd, char* ptr, int len) {

 HAL_StatusTypeDef hstatus;

 if (fd == STDIN_FILENO) {

   hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);

   if (hstatus == HAL_OK)

     return 1;

   else

     return EIO;

 }

 errno = EBADF;

 return -1;

}

int _fstat(int fd, struct stat* st) {

 if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {

   st->st_mode = S_IFCHR;

   return 0;

 }

 errno = EBADF;

 return 0;

}

#endif //#if !defined(OS_USE_SEMIHOSTING)

1.11 为项目添加一个C语言头文件,命名为“retarget.h”,如图所示

/*

* retarget.h

*

*  Created on: 2021��10��20��

*      Author: Administrator

*/

#ifndef INC_RETARGET_H_

#define INC_RETARGET_H_

#include "stm32f1xx_hal.h"

#include "stdio.h"

#include <sys/stat.h>

void RetargetInit(UART_HandleTypeDef  *huart);

int _isatty(int fd);

int _write(int fd, char* ptr, int len);

int _close(int fd);

int _lseek(int fd, int ptr, int dir);

int _read(int fd, char* ptr, int len);

int _fstat(int fd, struct stat* st);

#endif /* INC_RETARGET_H_ */

1.12 为项目添加一个C语言头文件,命名为“usart.h”,代码所示

/*

* usart1.h

*

*  Created on: Oct 20, 2021

*      Author: Administrator

*/

#ifndef INC_USART_H_

#define INC_USART_H_

#include "stm32f1xx_hal.h" //HAL库文件声明

#include <string.h>//用于字符串处理的库

#include "../inc/retarget.h"//用于printf函数串口重映射

extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体

extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体

extern UART_HandleTypeDef huart3;//声明USART2的HAL库结构体

#define USART1_REC_LEN  200//定义USART1最大接收字节数

#define USART2_REC_LEN  200//定义USART1最大接收字节数

#define USART3_REC_LEN  200//定义USART1最大接收字节数

extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符

extern uint16_t USART1_RX_STA;//接收状态标记

extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存

extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符

extern uint16_t USART2_RX_STA;//接收状态标记

extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存

extern uint8_t RS485orBT;//当RS485orBT标志位为1时是RS485模式,为0时是蓝牙模式

extern uint8_t  USART3_RX_BUF[USART3_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符

extern uint16_t USART3_RX_STA;//接收状态标记

extern uint8_t USART3_NewData;//当前串口中断接收的1个字节数据的缓存

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明

#endif /* INC_USART_H_ */

1.13 为项目添加一个C语言源文件,命名为“dht11.c”,代码所示

#include "dht11.h"

#include "main.h"

void DHT11_IO_OUT (void){ //端口变为输出

   GPIO_InitTypeDef GPIO_InitStruct = {0};

   GPIO_InitStruct.Pin = DHT11_DA_Pin;

   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

   GPIO_InitStruct.Pull = GPIO_NOPULL;

   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

void DHT11_IO_IN (void){ //端口变为输入

   GPIO_InitTypeDef GPIO_InitStruct = {0};

   GPIO_InitStruct.Pin = DHT11_DA_Pin;

   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

   GPIO_InitStruct.Pull = GPIO_PULLUP;

   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

void DHT11_RST (void){ //DHT11端口复位,发出起始信号(IO发送)

   DHT11_IO_OUT();

   HAL_GPIO_WritePin(GPIOB,DHT11_DA_Pin, GPIO_PIN_RESET);

   HAL_Delay(20); //拉低至少18ms

   HAL_GPIO_WritePin(GPIOB,DHT11_DA_Pin, GPIO_PIN_SET);

   delay_us(30); //主机拉高20~40us

}

uint8_t Dht11_Check(void){ //等待DHT11回应,返回1:未检测到DHT11,返回0:成功(IO接收)

   uint8_t retry=0;

   DHT11_IO_IN();//IO到输入状态

   while (HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)&&retry<100){//DHT11会拉低40~80us

       retry++;

       delay_us(1);

   }

   if(retry>=100)return 1; else retry=0;

   while (!HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)&&retry<100){//DHT11拉低后会再次拉高40~80us

       retry++;

       delay_us(1);

   }

   if(retry>=100)return 1;

   return 0;

}

uint8_t Dht11_ReadBit(void){ //从DHT11读取一个位 返回值:1/0

   uint8_t retry=0;

   while(HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)&&retry<100){//等待变为低电平

       retry++;

       delay_us(1);

   }

   retry=0;

   while(!HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)&&retry<100){//等待变高电平

       retry++;

       delay_us(1);

   }

   delay_us(40);//等待40us    //用于判断高低电平,即数据1或0

   if(HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin))return 1; else return 0;

}

uint8_t Dht11_ReadByte(void){  //从DHT11读取一个字节  返回值:读到的数据

   uint8_t i,dat;

   dat=0;

   for (i=0;i<8;i++){

       dat<<=1;

       dat|=Dht11_ReadBit();

   }

   return dat;

}

uint8_t DHT11_Init (void){    //DHT11初始化

   DHT11_RST();//DHT11端口复位,发出起始信号

   return Dht11_Check(); //等待DHT11回应

}

uint8_t DHT11_ReadData(uint8_t *h){ //读取一次数据//湿度值(十进制,范围:20%~90%) ,温度值(十进制,范围:0~50°),返回值:0,正常;1,失败

   uint8_t buf[5];

   uint8_t i;

   DHT11_RST();//DHT11端口复位,发出起始信号

   if(Dht11_Check()==0){ //等待DHT11回应

       for(i=0;i<5;i++){//读取5位数据

           buf[i]=Dht11_ReadByte(); //读出数据

       }

       if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){    //数据校验

           *h=buf[0]; //将湿度值放入指针1

           h++;

           *h=buf[2]; //将温度值放入指针2

       }

   }else return 1;

   return 0;

}

1.14 为项目添加一个C语言源文件,命名为“delay.c”,代码所示

/*

* delay.c

*

*  Created on: Oct 21, 2021

*      Author: Administrator

*/

#include "delay.h"

void delay_us(uint32_t us)

{

   uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us);

   while (delay--);

}

1.15 为项目添加一个C语言头文件,命名为“delay.h”,代码所示

/*

* delay.h

*

*  Created on: Oct 21, 2021

*      Author: Administrator

*/

#ifndef DELAY_DELAY_H_

#define DELAY_DELAY_H_

#include "stm32f1xx_hal.h"

void delay_us(uint32_t us);

#endif /* DELAY_DELAY_H_ */

1.16 在main函数添加以下代码所示。

/* USER CODE BEGIN Header */

/**

 ******************************************************************************

 * @file           : main.c

 * @brief          : Main program body

 ******************************************************************************

 * @attention

 *

 * Copyright (c) 2023 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 "usart.h"

#include "retarget.h"

#include "delay.h"

#include "dht11.h"

RTC_HandleTypeDef hrtc;

UART_HandleTypeDef huart1;

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_USART1_UART_Init(void);

static void MX_RTC_Init(void);

int main(void)

{

     uint8_t DHT11_BUF[2]={0};

     HAL_Init();

     SystemClock_Config();

     MX_GPIO_Init();

   //  MX_RTC_Init();

     MX_USART1_UART_Init();

     RetargetInit(&huart1);

     HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);

     HAL_Delay(500);

     DHT11_Init();

     HAL_Delay(1500);

     DHT11_ReadData(DHT11_BUF);

         while (1)

     {

        /*代码填写处*/

     }

}

/**

 * @brief System Clock Configuration

 * @retval None

 */

void SystemClock_Config(void)

{

 RCC_OscInitTypeDef RCC_OscInitStruct = {0};

 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

 /** Initializes the RCC Oscillators according to the specified parameters

 * in the RCC_OscInitTypeDef structure.

 */

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;

 RCC_OscInitStruct.HSEState = RCC_HSE_ON;

 RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;

 RCC_OscInitStruct.HSIState = RCC_HSI_ON;

 RCC_OscInitStruct.LSIState = RCC_LSI_ON;

 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;

 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_PLLCLK;

 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

 {

   Error_Handler();

 }

 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;

 PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;

 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)

 {

   Error_Handler();

 }

}

/**

 * @brief RTC Initialization Function

 * @param None

 * @retval None

 */

static void MX_RTC_Init(void)

{

 /* USER CODE BEGIN RTC_Init 0 */

 /* USER CODE END RTC_Init 0 */

 /* USER CODE BEGIN RTC_Init 1 */

 /* USER CODE END RTC_Init 1 */

 /** Initialize RTC Only

 */

 hrtc.Instance = RTC;

 hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;

 hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;

 if (HAL_RTC_Init(&hrtc) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN RTC_Init 2 */

 /* USER CODE END RTC_Init 2 */

}

/**

 * @brief USART1 Initialization Function

 * @param None

 * @retval None

 */

static void MX_USART1_UART_Init(void)

{

 /* USER CODE BEGIN USART1_Init 0 */

 /* USER CODE END USART1_Init 0 */

 /* USER CODE BEGIN USART1_Init 1 */

 /* USER CODE END USART1_Init 1 */

 huart1.Instance = USART1;

 huart1.Init.BaudRate = 115200;

 huart1.Init.WordLength = UART_WORDLENGTH_8B;

 huart1.Init.StopBits = UART_STOPBITS_1;

 huart1.Init.Parity = UART_PARITY_NONE;

 huart1.Init.Mode = UART_MODE_TX_RX;

 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

 huart1.Init.OverSampling = UART_OVERSAMPLING_16;

 if (HAL_UART_Init(&huart1) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN USART1_Init 2 */

 /* USER CODE END USART1_Init 2 */

}

/**

 * @brief GPIO Initialization Function

 * @param None

 * @retval None

 */

static void MX_GPIO_Init(void)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */

 __HAL_RCC_GPIOC_CLK_ENABLE();

 __HAL_RCC_GPIOD_CLK_ENABLE();

 __HAL_RCC_GPIOB_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(DHT11_DA_GPIO_Port, DHT11_DA_Pin, GPIO_PIN_SET);

 /*Configure GPIO pin : DHT11_DA_Pin */

 GPIO_InitStruct.Pin = DHT11_DA_Pin;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

 HAL_GPIO_Init(DHT11_DA_GPIO_Port, &GPIO_InitStruct);

}

/* 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 */

任务代码

前面已经移植了dht11传感器的驱动代码,现在需要补充Core->src->main函数里面的while循环代码,当初始化DHT11之后,需要通过DHT11_ReadData读取到温度值,已知DHT11_ReadData函数一次性读取两个字节,第二个字节才是温度值,任务要求是使用前面定义的DHT11_BUF来接收温度值,读取到温度值后需要每隔1s通过串口打印出温度值。

undefined

测试说明

stm32首先采集到温湿度传感器的数据,然后通过串口1发送出来,利用串口助手即可查看stm32接受到的温度数据。

undefined

上一条:模拟电子技术-运算放大器的线性应用 下一条:模拟电子技术-射极跟随器

关闭