STM32F407温湿度检测与数据上传
本文介绍了一种基于DHT11温湿度传感器的检测系统设计。系统通过DHT11采集环境温湿度数据,STM32F407单片机处理数据后,通过蓝牙模块实现远程传输。文中详细阐述了DHT11的工作原理、引脚定义、通信时序,并提供了完整的代码实现,包括初始化、数据读取、校验算法等关键功能。系统采用开漏输出模式,配合精确的微秒级延时控制,确保数据采集的可靠性。
前言
本系统旨在设计一款基于DHT11温湿度传感器的检测装置,并通过蓝牙技术将数据上传,实现对环境温湿度的实时监测与远程数据传输。
DHT11产品概述
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传 感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高 的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测 温元件,并与一个高性能8位单片机相连接。
接口说明
建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使 用合适的上拉电阻

电源引脚
DHT11的供电电压为3- 5.5V。传感器上电后,要等待1s以越过不稳定状态在此期间无需发送任何指令。电源引脚( VDD, GND)之间可增加一个100nF的电容,用以去耦滤波。
DHT11引脚说明
| Pin | 名称 | 注释 |
| 1 | VDD | 供电3- 5. 5VDC |
| 2 | DATA | 串行数据,单总线 |
| 3 | NC | 空脚,请悬空 |
| 4 | GND | 接地,电源负极 |
代码部分
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
extern UART_HandleTypeDef huart2;
extern uint8_t dht11_data[5];
/* 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 */
HAL_Init();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
DWT_Delay_Init();
/* USER CODE BEGIN 2 */
printf("SystemCoreClock: %lu Hz\r\n", SystemCoreClock); // 打印 SystemCoreClock 的值
printf("DWT->CTRL = 0x%08lX\r\n", DWT->CTRL);
DHT11_Init(); // 初始?? DHT11
printf("DHT11 Test Start...\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint8_t success = 0;
for (int i = 0; i < 3; i++) {
if (DHT11_Read_Data(&temperature, &humidity) == 0) {
success = 1;
break;
}
HAL_Delay(100); // 间隔 100ms 重试
}
if (success)
{
uint8_t UserNo = 1;
uint8_t DevNo = 1;
uint8_t RoomNo = 1;
printf("$DT1$%d|%d|%d|%d.%d|%d.%d#\r\n",
UserNo, DevNo, RoomNo,
dht11_data[2], dht11_data[3],
dht11_data[0], dht11_data[1]);
}
HAL_Delay(2000); // 每2秒采集一次数据
}
/* USER CODE END 3 */
}
dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/* DHT11 引脚定义 */
#define DHT11_PORT GPIOG
#define DHT11_PIN GPIO_PIN_9
extern uint8_t dht11_data[5];
/* 函数声明 */
uint8_t DHT11_Init(void);
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity);
void DHT11_GPIO_Init(void);
void DHT11_Print_Data(void); // 新增:打印数据到串口的函数
void DWT_Delay_Init(void);
/* 返回值定义 */
#define DHT11_OK 0 // 读取成功
#define DHT11_ERROR 1 // 读取失败
#define DHT11_TIMEOUT 2 // 超时错误
#define DHT11_CHECK_ERROR 3 // 校验错误
#ifdef __cplusplus
}
#endif
#endif /* __DHT11_H */
dht11.c
/* 设置 GPIO 为输入模式 */
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // 使用内部上拉
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
void DHT11_GPIO_Init(void)
{
__HAL_RCC_GPIOG_CLK_ENABLE(); // 确保端口时钟打开
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
void dht11_start(void)
{
DHT11_Mode_Out_OD(); // 添加这行,设置为开漏输出模式
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
HAL_Delay(20); // 拉低至少18ms
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
delay_us(30); // 拉高20 - 40μs
DHT11_Mode_IPU(); // 添加这行,切换为输入上拉模式
delay_us(5);
}
uint8_t dht11_wait_response(void)
{
uint16_t timeout = 0;
// 等待传感器拉低
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
delay_us(1);
timeout++;
if (timeout > 300)
return 1; // 超时
}
timeout = 0;
// 等待传感器拉高
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
{
delay_us(1);
timeout++;
if (timeout > 300)
return 1; // 超时
}
return 0;
}
/* 设置 GPIO 为开漏输出模式 */
static void DHT11_Mode_Out_OD(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP; // 使用内部上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); // 确保在输出模式下释放总线
}
uint8_t DHT11_Init(void)
{
// 初始化 DWT 用于微秒延时
// 确保 SystemCoreClock 已经被正确设置
DHT11_GPIO_Init();
if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
// 上电后等待1秒越过不稳定状态
HAL_Delay(1000);
return DHT11_OK;
}
/* 读取一个位 */
static uint8_t DHT11_ReadBit(void)
{
uint16_t timeout = 0;
// 等待高电平
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
{
delay_us(2);
timeout++;
if (timeout > 500)
return 0; // 超时
}
delay_us(60); // 等待40μs
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
// 等待高电平结束
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
{
delay_us(2);
timeout++;
if (timeout > 500)
return 0; // 超时
}
return 1;
}
else
{
return 0;
}
}
/* 读取一个字节 */
static uint8_t DHT11_ReadByte(void)
{
uint8_t byte = 0;
uint8_t i;
for (i = 0; i < 8; i++)
{
byte <<= 1;
byte |= DHT11_ReadBit();
}
return byte;
}
/* 读取温湿度数据 */
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity)
{
uint8_t i;
uint8_t checksum;
memset(dht11_data, 0, sizeof(dht11_data));
dht11_start();
if (dht11_wait_response())
return 1; // 响应超时
for (i = 0; i < 5; i++)
{
dht11_data[i] = DHT11_ReadByte();
}
checksum = dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3];
if (checksum != dht11_data[4])
return 1; // 校验和错误
*temperature = dht11_data[2];
*humidity = dht11_data[0];
return 0;
}
void DWT_Delay_Init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
/* 精确微秒延时函数 */
static void delay_us(uint32_t us)
{
uint32_t start_cycles = DWT->CYCCNT;
uint32_t required_cycles = us * (SystemCoreClock / 1000000);
// 等待直到经过所需的周期数
while ((DWT->CYCCNT - start_cycles) < required_cycles);
}
DWT->CYCCNT 是 Cortex-M 的 数据观察器周期计数器(Data Watchpoint and Trace Cycle Counter),可用于实现高精度微秒延时。
数据发送
数据发送是由串口2进行数据发送,可选择USB转TTL模块或HC-05蓝牙模块进行数据发送,接线时需要遵循交叉接线。

蓝牙模块接线时需注意VCC接3.3V
通电后发现蓝牙模块持续快速闪烁,打开手机或电脑蓝牙与其进行配对
运行结果

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)