基于STM32_HAL库的温湿度检测系统
一、项目需求
使用DHT11温湿度传感器检测当前温湿度,当温度达到设定值时打开风扇,并通过LCD1602屏幕显示当前实时温湿度和风扇状态,并把当前的温湿度值和风扇状态上传手机到BLE助手。
二、硬件连接
项目用到的模块:STM32F103C8T6最小系统板、LCD1602屏幕、DHT11温湿度传感器、HC-08蓝牙模块、继电器模块。
LCD1602 to MCU:【D0-D7👉PA0-PA7】【RS👉PB1】【RW👉PB2】【EN👉PB10】
DHT11 to MCU:【data👉PB7】
HC-08 to MCU:【RXD👉PA9】【TXD👉PA10】
继电器 to MCU:【IN👉PB6】
三、项目实现
3.1 CubeMX配置:
-
配置Debug
-
打开RCC配置时钟,将高速时钟配置成Crystal/Ceramic Resonator
-
点击配置时钟选项,把时钟配置成高速外部时钟HSE,并且通过PLLCLK倍频到72MHZ,按下回车之后就为芯片内部的功能分配好了对应的时钟频率。
-
打开左侧的USART1,首先将串口配置成异步通信模式,对波特率、数据位、奇偶校验位、停止位等进行配置。
-
我们对LCD1602的GPIO和继电器的GPIO进行配置,把它们全部配置成GPIO_Output模式,因为DHT11我们需要既有输入又有输出,所以在这里先不配置,等到代码中实现。
-
接着对我们的工程进行配置,配置完成之后点击右上角的 GENERATE CODE 生成工程
3.2 代码实现:
dht11.c
#include "dht11.h"
uint8_t datas[5];
/* DHT11 GPIO初始化 */
void DHT_GPIO_Init(uint32_t mode)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = mode;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void delay_us(uint16_t cnt)
{
uint8_t i;
while(cnt)
{
for (i = 0; i < 10; i++){
}
cnt--;
}
}
void DHT11_Start()
{
DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);
DHT_HIGH;
DHT_LOW;
HAL_Delay(30);
DHT_HIGH;
DHT_GPIO_Init(GPIO_MODE_INPUT);
while(DHT_VALUE);
while(!DHT_VALUE);
while(DHT_VALUE);
}
/* 读取DHT温湿度 */
void Read_Data_From_DHT(void)
{
int i;
int j;
char tmp;
char flag;
DHT11_Start();
DHT_GPIO_Init(GPIO_MODE_INPUT);
for(i=0; i<5; i++){
for(j=0; j<8; j++){
while(!DHT_VALUE);
delay_us(40);
if(DHT_VALUE == 1){
flag = 1;
while(DHT_VALUE);
}else{
flag = 0;
}
tmp = tmp << 1;
tmp |= flag;
}
datas[i] = tmp;
}
}
dht11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include "gpio.h"
#define DHT_HIGH HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)
void Read_Data_From_DHT(void);
#endif
lcd1602.c
#include "lcd1602.h"
/* LCD1602写命令 */
void Write_Cmd_Func(uint8_t cmd)
{
RS_LOW;
RW_LOW;
EN_LOW;
GPIOA->ODR = cmd;
HAL_Delay(5);
EN_HIGH;
HAL_Delay(5);
EN_LOW;
}
/* LCD1602写数据 */
void Write_Data_Func(uint8_t dataShow)
{
RS_HIGH;
RW_LOW;
EN_LOW;
GPIOA->ODR = dataShow;
HAL_Delay(5);
EN_HIGH;
HAL_Delay(5);
EN_LOW;
}
/* LCD1602初始化 */
void LCD1602_Init(void)
{
HAL_Delay(15); // 延时 15ms
Write_Cmd_Func(0x38); // 写指令 38H(不检测忙信号)
HAL_Delay(5); // 延时 5ms
Write_Cmd_Func(0x38); // 写指令 38H:显示模式设置
Write_Cmd_Func(0x08); // 写指令 08H:显示关闭
Write_Cmd_Func(0x01); // 写指令 01H:显示清屏
Write_Cmd_Func(0x06); // 写指令 06H:显示光标移动设置
Write_Cmd_Func(0x0c); // 写指令 0CH:显示开及光标设置
}
/* LCD1602显示 */
void LCD1602_showLine(char row, char col, char *string)
{
switch(row){
case 1:
Write_Cmd_Func(0x80+col);
while(*string != '\0'){
Write_Data_Func(*string);
string++;
}
break;
case 2:
Write_Cmd_Func(0x80+0x40+col);
while(*string != '\0'){
Write_Data_Func(*string);
string++;
}
break;
}
}
lcd1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "gpio.h"
#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_PIN GPIO_PIN_1
#define RW_PIN GPIO_PIN_2
#define EN_PIN GPIO_PIN_10
#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_Port, RS_PIN, GPIO_PIN_SET)
#define RS_LOW HAL_GPIO_WritePin(RS_GPIO_Port, RS_PIN, GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_Port, RW_PIN, GPIO_PIN_SET)
#define RW_LOW HAL_GPIO_WritePin(RW_GPIO_Port, RW_PIN, GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_Port, EN_PIN, GPIO_PIN_SET)
#define EN_LOW HAL_GPIO_WritePin(EN_GPIO_Port, EN_PIN, GPIO_PIN_RESET)
void LCD1602_Init(void);
void LCD1602_showLine(char row, char col, char *string);
#endif
gpio.c
#include "gpio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pins : PA0 PA1 PA2 PA3
PA4 PA5 PA6 PA7 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB1 PB2 PB10 PB6 */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
usart.c
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
#include <stdio.h>
int fputc(int ch, FILE *f)
{
unsigned char temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,0xffff);
return ch;
}
/* USER CODE END 0 */
UART_HandleTypeDef huart1;
/* USART1 init function */
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 = 9600;
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 */
}
main.c
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "lcd1602.h"
#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 */
extern uint8_t datas[5];
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
char message[16];
/* 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();
/* USER CODE BEGIN 2 */
LCD1602_Init(); // LCD初始化
LCD1602_showLine(1, 13, "FS:");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Read_Data_From_DHT(); // 读取DHT温湿度
if(datas[2] >= 27){ // 如果温度达到27℃打开风扇
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
printf("风扇已打开\r\n"); // 风扇状态上传到BLE-APP
LCD1602_showLine(2,13, "ON "); // LCD显示风扇状态
}else{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
LCD1602_showLine(2,13, "OFF");
}
memset(message, 0, sizeof(message));
sprintf(message,"Temp = %d.%d",datas[2], datas[3]);
LCD1602_showLine(1, 0, message); // LCD显示当前温度
memset(message, 0, sizeof(message));
sprintf(message,"Humi = %d.%d",datas[0], datas[1]);
LCD1602_showLine(2, 0, message); // LCD显示当前湿度
printf("Temp = %d.%d℃ ",datas[2], datas[3]); // 上传当前温度到BLE-APP
printf("Humi = %d.%d\r\n",datas[0], datas[1]); // 上传当前湿度到BLE-APP
HAL_Delay(1000); // 1s读取一次
}
/* USER CODE END 3 */
}
代码写完之后我们编译并且烧录进我们的单片机,就实现了我们的效果: