功能:
基于STM32的简易户外计时系统1硬件组成1) 核心控制器:STM32F103C6 2) 提醒模块:蜂鸣器 LED 3) 显示模块:LCD1602显示屏 4) 输入模块:按键 5) 温湿度模块:DHT11 2核心功能1)计时功能:使用TIM来实现精确的计时与倒计时。 2)提醒功能:在倒计时结束的时候,LED与蜂鸣器同时启动提醒倒计时结束。 3)控制功能:一个按键控制正计时功能的启停,一个按键设置倒计时时间与控制倒计时开始。 4)启停功能:启动按键实现系统的一键启停。 5)探测户外环境功能:使用DHT11获取环境的温湿度,在LCD上显示,为户外活动提供参考。
main.c
#include "stm32f10x.h"
#include "stdio.h"
#include "led.h"
#include "key.h"
#include "LCD1602.h"
#include "tim.h"
#include "delay.h"
#include "dht11.h"
#include "buzzer.h"
#include "main.h"
#include "usart.h"
#include "stm32f1xx_hal_msp.h"
// 全局变量
int time_able=0; // 系统总控制,0-停止 1-运行
int time_set = 10; // 倒计时默认设定值(秒)
int time_ing_down = 10; // 倒计时剩余值(秒)
int time_ing_up = 0; // 正计时累计值(秒)
int time_lms = 0; // 毫秒累计,1ms+1次
int time_led = 0; // LED闪烁定时(毫秒)
int up_run_flag = 0; // 正计时启停标志,0-停止 1-运行
int down_run_flag = 0; // 倒计时启停标志,0-停止 1-运行
// 温湿度相关变量
u8 temperature = 0; // 温度值(℃)
u8 humidity = 0; // 湿度值(%)
u32 dht11_read_timer = 0; // DHT11读取计时器(1ms递增)
u32 dht11_last_read_time = 0; // 上次读取DHT11的时间戳
char display_buffer[17]; // 显示缓冲区
// 中断测试变量
volatile u32 interrupt_count = 0; // 中断计数器
// LED和蜂鸣器控制变量
volatile u32 alarm_countdown = 0; // 蜂鸣器倒计时
volatile u8 alarm_triggered = 0; // 蜂鸣器触发标志
// 按键3相关变量
volatile u8 key3_pressed = 0; // 按键3按下标志
volatile u32 key3_hold_time = 0; // 按键3按住时间(ms)
volatile u32 key3_last_change = 0; // 上次改变倒计时值的时间(ms)
// 定时器2中断服务函数,1ms执行一次
void tim2_IRQ(void)
{
// 清除并检查定时器2更新中断标志,继续
// if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
// {
time_lms++;
// dht11_read_timer++;
// 系统总控制启动时的计时逻辑
if(time_able == 1)
{
// ---------------- 倒计时逻辑 ----------------
if(down_run_flag == 1 && time_ing_down > 0)
{
if(time_lms >= 10) // 累计1000ms=1秒
{
time_lms = 0;
time_ing_down--;
dht11_read_timer--;
// 倒计时结束,启动LED和蜂鸣器提醒
if(time_ing_down == 0)
{
time_led = 10; // LED亮100ms(0.1秒)
alarm_triggered = 1; // 触发蜂鸣器标志
alarm_countdown = 14; // 蜂鸣器响1.4秒(3次)
down_run_flag = 0; // 倒计时停止
time_ing_down=10;
}
}
}
// ---------------- 正计时逻辑 ----------------
if(up_run_flag == 1)
{
if(time_lms >= 10) // 累计1000ms=1秒
{
time_lms = 0;
time_ing_up++;
dht11_read_timer++;
if(time_ing_up >= 10) time_ing_up = 99; // 上限保护
}
}
}
else
{
// 系统停止时,毫秒计数器清零,防止残留
time_lms = 0;
up_run_flag = 0;
down_run_flag = 0;
time_ing_up = 0;
time_ing_down = 10;
time_led = 0;
LED_OFF();
}
// LED闪烁逻辑
if(time_led > 0)
{
LED_ON(); // time_led>0时LED亮
time_led--;
}
else
{
LED_OFF(); // time_led=0时LED灭
}
// 蜂鸣器提醒逻辑(非阻塞)
if(alarm_countdown > 0)
{
alarm_countdown--;
// 每40ms为一个周期:前20ms响,后20ms停
if(alarm_countdown % 4 < 2)
{
BUZZER_ON();
}
else
{
BUZZER_OFF();
}
}
else
{
BUZZER_OFF();
// 重置标志
if(time_led == 0)
{
alarm_triggered = 0;
}
}
// 清除中断标志,继续
// TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// }
}
int main(void)
{
// 外设初始化
delay_init(); // 延时函数初始化
KEY_Init(); // 按键初始化
LED_Init(); // LED初始化
Buzzer_Init(); // 蜂鸣器初始化
LCD_init(); // LCD初始化
DHT11_Init(); // DHT11初始化
tim2_init(100, 7200-1); // 定时器2初始化,1ms中断
// LCD初始化显示
LCD1602_showstring(0, 0, "UP:000s DN:010s"); // 第一行:计时
// LCD1602_showstring(0, 1, "T:00 C H:00 %"); // 第二行:温湿度
while (1)
{
// ---------------- 按键处理逻辑 ----------------
// 按键1:系统全局启停控制,启停
if(KEY1 == 0)
{
Delay_ms(20); // 消抖
if(KEY1 == 0)
{
time_able = !time_able; // 切换启停状态
if(time_able == 0) // 停止时,清零所有状态
{
up_run_flag = 0;
down_run_flag = 0;
time_ing_up = 0;
time_ing_down = 10;
time_led = 0;
LED_OFF();
}
while(KEY1 == 0); // 等待按键释放
}
}
// 按键2:正计时启停,系统运行时才有效
if(KEY2 == 0 && time_able == 1)
{
Delay_ms(20); // 消抖
if(KEY2 == 0)
{
up_run_flag = !up_run_flag; // 切换正计时启停
if(up_run_flag == 1 && time_ing_up == 0)
{
time_ing_up = 0; // 正计时重置为0
}
while(KEY2 == 0); // 等待按键释放
}
}
// 按键3:长按调节倒计时时间,松开开始倒计时,系统运行时才有效
if(KEY3 == 0 && time_able == 1)
{
Delay_ms(20); // 消抖
if(KEY3 == 0)
{
if(key3_pressed == 0) // 刚按下
{
key3_pressed = 1;
key3_hold_time = 0;
key3_last_change = 0;
down_run_flag = 0; // 暂停倒计时
}
}
}
// 按键3处理逻辑
if(key3_pressed == 1)
{
// 在主循环中按键按住时间每10ms增加一次
key3_hold_time += 10;
// 长按每秒增加倒计时时间
if(key3_hold_time - key3_last_change >= 100) // 每秒增加
{
key3_last_change = key3_hold_time;
time_set++;
if(time_set > 99) time_set = 99; // 上限999秒
time_ing_down = time_set; // 更新显示值
}
// 按键释放检测
if(KEY3 == 1)
{
if(key3_hold_time < 50) // 短按(小于500ms)
{
// 如果倒计时正在运行,则暂停;如果暂停,则开始
if(down_run_flag == 1)
{
down_run_flag = 0; // 暂停倒计时
}
else
{
down_run_flag = 1; // 开始倒计时
time_ing_down = time_set; // 使用当前设定值
}
}
else // 长按(大于500ms),松开开始倒计时
{
down_run_flag = 1; // 开始倒计时
time_ing_down = time_set; // 使用当前设定值
}
// 重置按键状态
key3_pressed = 0;
key3_hold_time = 0;
key3_last_change = 0;
}
}
// ---------------- LCD显示逻辑 ----------------
if(time_able == 1)
{
// 正计时显示,第一行,列3
LCD1602_shownum(3, 0, time_ing_up, 3);
// 倒计时显示,第一行,列11
LCD1602_shownum(11, 0, time_ing_down, 3);
}
// ---------------- DHT11温湿度读取逻辑(每2秒读取一次)----------------
if(dht11_read_timer - dht11_last_read_time >= 20) // 2000ms = 2秒
{
uint8_t temp, humi;
DHT11_Read_Data(&temp, &humi);
if(1) //DHT11_Read_Data(&temp, &humi) 读取成功
{
temperature = temp;
humidity = humi;
// 使用sprintf格式化显示字符串
sprintf(display_buffer, "T:%2d C H:%2d%%", temperature, humidity);
LCD1602_showstring(0, 1, display_buffer);
// LCD1602_shownum(2, 1, temperature, 2);
// LCD1602_shownum(8, 1, humidity, 2);
}
// 如果读取失败,保留上次的值,不更新显示
dht11_last_read_time = dht11_read_timer;
}
// 同时在time_able==1时也更新温湿度显示(确保显示不消失)
if(time_able == 1)
{
sprintf(display_buffer, "T:%2d C H:%2d%%", temperature, humidity);
LCD1602_showstring(0, 1, display_buffer);
// LCD1602_shownum(2, 1, temperature, 2);
// LCD1602_shownum(9, 1, humidity, 2);
}
Delay_ms(5); // 减少CPU占用,提高响应速度
}
}
|