STM32L431CubeMX使用DHT11读取环境温度与湿度并通过串口打印
一、开发平台
·小熊派(STM32L431)
·DHT11数字温湿度传感器
·keil5
·cubemx
·使用HAL库
软件下载
1、keil5
在官网下载(注意下载正确版本,STM32属于MDK-Arm):https://www.keil.com/download/product/
2、CubeMx
在官网下载:https://www.st.com/zh/development-tools/stm32cubemx.html
二、DHT11介绍
用户单片机发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信采集。
DHT11接线:
DHT11 | STM32 |
---|---|
VCC | 5V |
GND | GND |
DATA | PC9 |
三、新建工程步骤
1、CubeMx
1、打开CubeMx,选择芯片类型
我这里用的是小熊派(STM32L431RCT)
配置RCC为外部高速时钟。
配置串口1,串口配置按默认来就可以了。
因为我的DHT11接在PC9引脚上,所以配置引脚PC9为GPIO_OUTPUT,并把标签改为DHT11,方便后续的编程。
对PC9引脚进行配置
配置时钟树,STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可
最后点击Genrate code
至此工程建立完毕,点击open project,自动打开keil5
2、Keil5
1、点击Build,等待工程编译完成,0 error后点击工程文件管理,添加hareware文件夹,将驱动文件添加进去。
2、点击魔术棒,添加include路径,添加dht11.h所在文件夹路径,再次编译。
添加重定向printf代码
四、代码部分
1、dht11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include "main.h"
#include "tim.h"
#include "gpio.h"
#include "stm32l4xx_hal.h"
#define DHT11_DQ_OUT_HIGH HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin,GPIO_PIN_SET)
#define DHT11_DQ_OUT_LOW HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin,GPIO_PIN_RESET)
#define DHT11_DQ_IN HAL_GPIO_ReadPin(DHT11_GPIO_Port,DHT11_Pin)
extern uint16_t temperature;
extern uint16_t humidity;
extern char temp,humi;
void delay_us(uint16_t us);
//IO方向设置
void DHT11_IO_IN(void);
void DHT11_IO_OUT(void);
uint8_t DHT11_Init(void);//初始化DHT11
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi);//读取温湿度
uint8_t DHT11_Read_Byte(void);//读出一个字节
uint8_t DHT11_Read_Bit(void);//读出一个位
uint8_t DHT11_Check(void);//检测是否存在DHT11
void DHT11_Rst(void);//复位DHT11
#endif
2、dht11.c
#include "dht11.h"
uint16_t temperature;
uint16_t humidity;
char temp,humi;
//微秒延时
void delay_us(uint16_t us)
{
uint16_t differ = 0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim7,differ); //设定TIM1计数器起始值
HAL_TIM_Base_Start(&htim7); //启动定时器
while(differ < 0xffff-5){ //判断
differ = __HAL_TIM_GET_COUNTER(&htim7); //查询计数器的计数值
}
HAL_TIM_Base_Stop(&htim7);
}
//IO方向设置
void DHT11_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DHT11_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
}
void DHT11_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = DHT11_Pin;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_GPIO_Port,&GPIO_InitStructure);
}
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //设置为输出
DHT11_DQ_OUT_LOW; //拉低DQ
HAL_Delay(20); //拉低至少18ms
DHT11_DQ_OUT_HIGH; //DQ=1
delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void)
{
uint8_t retry=0;
DHT11_IO_IN(); //设置为输出
while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void)
{
uint8_t retry=0;
while(DHT11_DQ_IN&&retry<100)//等待变为低电平
{
retry++;
delay_us(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待变高电平
{
retry++;
delay_us(1);
}
delay_us(40);//等待40us
if(DHT11_DQ_IN)return 1;
else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
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;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)
{
uint8_t buf[5];
uint8_t i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
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;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
uint8_t DHT11_Init(void)
{
DHT11_Rst();
return DHT11_Check();
}
3、printf重定向
添加在usart.c中
/* USER CODE BEGIN 1 */
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
/* 堵塞判断串口是否发送完成 */
while((USART1->ISR & 0X40) == 0);
/* 串口发送完成,将该字符发送 */
USART1->TDR = (uint8_t) ch;
return ch;
}
#endif
/* USER CODE END 1 */
4、mian.c
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include "stdio.h"
/* USER CODE END Includes */
int main(void)
{
/* USER CODE BEGIN 1 */
/* 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_TIM7_Init();
/* USER CODE BEGIN 2 */
while(DHT11_Init()) //初始化DHT11
{
printf("DHT11 初始化失败!\r\n");
HAL_Delay(500);
}
printf("DHT11 初始化成功!\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
uint8_t res = DHT11_Read_Data(&temperature,&humidity); //设置缓存区
if(res == 0) //判断是否读取到温湿度数据
{
DHT11_Read_Data(&temperature,&humidity); //读取温湿度数据
printf("DHT11 Temperature = %d.%d ℃\r\n",temperature>>8,temperature&0xff);
printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
五、运行效果
下载程序后通过串口助手可以看到
至此,本实验完成。