1、开发环境、硬件、功能概述
开发环境:Keil uVision5 + STM32F103C8T6核心板
硬件模块:DHT11温湿度传感器、I2C接口LCD1602显示屏(也包含有四位传输模式的方式驱动lcd1602)、独立按键模块
功能概述:实时显示温湿度数据,通过三个按键(PA3切换四个阈值)支持四个阈值的按键调节(Proteus中lcd用的四位数据模式传输的数据)
2、工程结构解析
2.1. 头文件依赖关系
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
#include "DHT11.h"
#include "lcd.h"
#include "key.h"
#include "string.h"
#include "stdio.h"
#include "lcd1602_i2c.h"
3、核心数据结构
DHT11_Data g_dht11_data = {0}; // 全局存储传感器数据
// 定义阈值结构体
typedef struct {
int temp_low;
int temp_high;
int humidity_low;
int humidity_high;
} Thresholds;
Thresholds thresholds = {20, 30, 40, 80}; // 默认阈值
// 当前编辑的阈值索引
uint8_t editing_index = 0;
// 函数声明
void DisplayThresholds(void);
void EditThreshold(int *value, int increment);
extern uint8_t current_mode;
4、主函数逻辑分解
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 初始化延时函数
DelayInit();
// 初始化四位模式LCD
// LCD_GPIO_Init();
// LCD_Init();
// 初始化i2_c_LCD
LCD1602_I2C_Init(I2C1);
LCD1602_PrintStr("chu");
// 初始化按键GPIO和中断
KEY_GPIO_Init();
KEY_EXTI_Init();
// 初始化DHT11
while(DHT11_Init())
{
LCD1602_PrintStr("no");
Delay_ms(1000);
}
while(1)
{
// 读取温湿度数据
DHT11_ReadData(&g_dht11_data);
// 检查是否有按键事件
KeyEvent event = get_key_event();
if(event != NO_EVENT)
{
switch(event)
{
case EVENT_MODE:
// 切换到下一个编辑项
editing_index = (editing_index + 1) % 4;
break;
case EVENT_INCREASE:
// 增加当前编辑的阈值
if(editing_index == 0) EditThreshold(&(thresholds.temp_low), 1);
else if(editing_index == 1) EditThreshold(&(thresholds.temp_high), 1);
else if(editing_index == 2) EditThreshold(&(thresholds.humidity_low), 1);
else if(editing_index == 3) EditThreshold(&(thresholds.humidity_high), 1);
break;
case EVENT_DECREASE:
// 减少当前编辑的阈值
if(editing_index == 0) EditThreshold(&(thresholds.temp_low), -1);
else if(editing_index == 1) EditThreshold(&(thresholds.temp_high), -1);
else if(editing_index == 2) EditThreshold(&(thresholds.humidity_low), -1);
else if(editing_index == 3) EditThreshold(&(thresholds.humidity_high), -1);
break;
default:
break;
}
}
DisplayThresholds();
Delay_ms(100); // 简单延时,避免过于频繁的刷新
}
}
5、 数据显示与阈值编辑函数实现
// 温度显示格式:"T:25.0 H30 L20"
snprintf(line1, sizeof(line1), "T:%d.%d H%02d L%02d",
g_dht11_data.temp_int, g_dht11_data.temp_decimal,
thresholds.temp_high, thresholds.temp_low);
// 湿度显示格式:"H:50.0% H80 L30"
snprintf(line2, sizeof(line2), "H:%d.%d H%02d L%02d",
g_dht11_data.humidity_int, g_dht11_data.humidity_decimal,
thresholds.humidity_high, thresholds.humidity_low);
void EditThreshold(int *value, int increment)
{
*value += increment;
// 边界保护逻辑
*value = (*value < 0) ? 0 : (*value > 9999) ? 9999 : *value;
}
6、总结
在用Proteus仿真初始化单总线读取dht11时,也就是这里DHT11_Init(),检测不到dht11。可能是单总线协议对us级时序要求十分严格(我用的系统滴答定时器延时的)。也可能我对Proteus不熟悉设置有问题,但是连接实物实验没有问题。实物跟仿真还是有差距的。 需要源码的可以在我资源下载。
// DHT11初始化检测
while(DHT11_Init()){
LCD1602_PrintStr("no"); // 传感器异常提示
Delay_ms(1000);
}
需要源码的可以在我资源下载。