|
|
各位帖友大家好,本人是一枚刚学stm32的萌新。一直修改PWM的有关参数,就是无法达到想要的呼吸灯效果。
想要的呼吸灯效果:LED6和LED7交接闪烁。LED6从暗到亮时,LED7从亮到暗;紧接着LED6从亮到暗,LED7从暗到亮。
目前存在的问题:1、两盏灯之间交接得太慢:LED6从暗到亮,要过很久LED7才会从亮到暗。2、单个灯的呼吸效果不明显,一下子就从暗到亮。
以下是代码,不胜感激!
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h" // 包含led.h,使用LED_ON_OFF函数
#include "rtc.h"
#include "smg.h"
#include "timer.h"
#include "beep.h"
#include "exti.h" // 包含exti.h,使用其中定义的类型
#include "key.h"
#include "test.h"
#include "adc.h"
#include "string.h"
/************************************************
STM32F103RC Fall Detection System
Functions: 1.Normal state: digital tube displays RTC time, LED6 and LED7 breathing light
2.Fall detected (KEY2 pressed): buzzer sounds, LED0-LED7 flowing light
3.KEY0 confirms safety, sends "Safe", stops buzzer;
KEY1 confirms unsafe, sends "Unsafe", buzzer beeps every 3 seconds
4.After receiving "SOS received" via serial port, LED0-LED7 all light up and buzzer sounds
************************************************/
// 全局变量定义 - 现在使用exti.h中定义的SystemState类型
SystemState system_state = STATE_NORMAL; // System state
u8 LED_Shift = 0xFF; // LED display control
u8 smg_wei = 0; // Digital tube bit selection
u8 num = 0; // Digital tube display value
u16 breath_count = 0; // Breathing light counter
u8 breath_dir = 0; // Breathing light direction (0-brighten, 1-dim)
u16 flow_count = 0; // Flowing light counter
u8 flow_index = 0; // Flowing light index
u16 beep_count = 0; // Buzzer counter
u8 all_led_on = 0; // All LEDs on flag
u8 all_led_timer = 0; // All LEDs on timer
u8 sos_beep_flag = 0; // SOS buzzer flag
u8 sos_beep_timer = 0; // SOS buzzer timer
u16 unsafe_timeout = 0; // Unsafe state timeout counter
u16 safe_timeout = 0; // Safe state timeout counter
u16 fall_timeout = 0; // Fall detected state timeout counter
u16 brightness = 0; // 亮度值 0-1000
// Digital tube segment codes
// 0,1,2,3,4,5,6,7,8,9,dot,all off
u8 smg_num[] = {0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6, 0x01, 0x00};
// 超时时间定义 (单位: 50ms)
#define FALL_STATE_TIMEOUT 60 // 摔倒状态30秒超时 (50ms * 60 = 3s)
#define SAFE_STATE_TIMEOUT 40 // 安全状态20秒超时 (50ms * 40 = 2s)
#define UNSAFE_STATE_TIMEOUT 120 // 不安全状态60秒超时 (50ms * 120 = 6s)
#define LED6_PWM_VAL TIM3->CCR1 // PC6
#define LED7_PWM_VAL TIM3->CCR2 // PC7
// Function declarations
void Display_Time(void);
void Breath_LED(void);
void Flow_LED(void);
void USART_ProcessCommand(u8* buf, u16 len);
void Set_RTC_To_Beijing_Time(void);
void Reset_To_Normal_State(void);
void TIM3_PWM_Init(u16 arr, u16 psc);
// 主函数
int main(void) {
// 系统初始化
Stm32_Clock_Init(9); // 系统时钟设置
delay_init(72); // 延时初始化
uart_init(72, 115200); // 串口初始化
LED_Init(); // LED初始化
BEEP_Init(); // 蜂鸣器初始化
LED_SMG_Init(); // 数码管初始化
EXTIX_Init(); // 外部中断初始化(在exti.c中定义)
TIM3_PWM_Init(999, 71);
// RTC初始化
while(RTC_Init()) {
printf("RTC Init Failed!\r\n");
delay_ms(800);
printf("RTC Retry Init...\r\n");
}
// 设置RTC为北京时间
Set_RTC_To_Beijing_Time();
// 初始化定时器
TIM3_Init(19, 7199); // 定时器3初始化,2ms中断一次
TIM2_Init(499, 7199); // 定时器2初始化,50ms中断一次
printf("Fall Detection System Init Complete!\r\n");
printf("Normal: Digital tube shows time, LED6/LED7 breathing\r\n");
printf("Press KEY2 to simulate fall, KEY0 for safe, KEY1 for unsafe\r\n");
printf("Current RTC Time: %d-%d-%d %02d:%02d:%02d\r\n",
calendar.w_year, calendar.w_month, calendar.w_date,
calendar.hour, calendar.min, calendar.sec);
printf("Timeout settings: Fall(30s), Safe(20s), Unsafe(60s)\r\n");
// 初始状态:所有LED灭
LED_ON_OFF(0xFF);
// 主循环
while(1) {
// 处理串口接收
if(USART_RX_STA & 0x8000) {
u16 len = USART_RX_STA & 0x3FFF;
USART_RX_BUF[len] = '\0';
USART_ProcessCommand(USART_RX_BUF, len);
USART_RX_STA = 0;
}
// 处理LED全亮状态(5秒后自动恢复)
if(all_led_on) {
all_led_timer++;
if(all_led_timer > 2500) { // 5秒后恢复
all_led_on = 0;
all_led_timer = 0;
sos_beep_flag = 0; // 停止SOS蜂鸣器
if(system_state == STATE_NORMAL) {
LED_ON_OFF(0xFF); // 恢复为全灭
}
}
}
//处理呼吸灯
if(system_state == STATE_NORMAL || system_state == STATE_CONFIRMED_SAFE){
if(breath_dir == 0) {
brightness += 3;
if(brightness >= 999) {
breath_dir = 1; // 改变方向
printf("Switch to direction 1\r\n");
}
}
else {
brightness -= 3;
if(brightness <= 0) {
breath_dir = 0; // 改变方向
printf("Switch to direction 0\r\n");
}
}
LED6_PWM_VAL = brightness;
LED7_PWM_VAL = 999 - brightness;
delay_ms(10);
}
}
}
// 重置到正常状态
void Reset_To_Normal_State(void) {
system_state = STATE_NORMAL;
BEEP = 1; // 停止蜂鸣器
LED_ON_OFF(0xFF); // 恢复LED状态
fall_timeout = 0;
safe_timeout = 0;
unsafe_timeout = 0;
beep_count = 0;
sos_beep_flag = 0;
sos_beep_timer = 0;
brightness = 0;
breath_dir = 0;
LED6_PWM_VAL = 0;
LED7_PWM_VAL = 0;
printf("Timeout: Returning to normal state\r\n");
}
// 设置RTC为北京时间
void Set_RTC_To_Beijing_Time(void) {
// 这里需要根据实际时间设置,示例设置为2024年1月1日 12:00:00
// 在实际使用中,可以通过串口命令来设置准确的时间
RTC_Set(2024, 1, 1, 12, 0, 0);
printf("RTC set to Beijing time: 2024-01-01 12:00:00\r\n");
printf("Use serial command 'SETTIME:YYYY-MM-DD HH:MM:SS' to set exact time\r\n");
}
// TIM2中断处理函数 - 用于处理蜂鸣器周期性响铃和超时恢复
void TIM2_IRQHandler(void) {
if(TIM2->SR & 0X0001) { // 溢出中断
// 状态超时处理
switch(system_state) {
case STATE_FALL_DETECTED:
// 摔倒状态30秒后自动恢复
fall_timeout++;
if(fall_timeout >= FALL_STATE_TIMEOUT) {
Reset_To_Normal_State();
printf("Fall state timeout (30s), auto recovery\r\n");
}
break;
case STATE_CONFIRMED_SAFE:
// 安全状态20秒后自动恢复
safe_timeout++;
if(safe_timeout >= SAFE_STATE_TIMEOUT) {
Reset_To_Normal_State();
printf("Safe state timeout (20s), auto recovery\r\n");
}
break;
case STATE_CONFIRMED_UNSAFE:
//不安全状态60秒后自动恢复
unsafe_timeout++;
if(unsafe_timeout >= UNSAFE_STATE_TIMEOUT) {
Reset_To_Normal_State();
printf("Unsafe state timeout (60s), auto recovery\r\n");
break;
}
// 不安全状态下,蜂鸣器每1秒响200ms
beep_count++;
BEEP = (beep_count % 20 >= 4); // 前4次中断响(200ms),后16次中断静音(800ms)
break;
default:
// 正常状态,不做超时处理
break;
}
// SOS蜂鸣器处理 (快速响鸣)
if(sos_beep_flag) {
sos_beep_timer++;
if(sos_beep_timer % 2 == 0) { // 每1秒切换一次
BEEP = !BEEP; // 蜂鸣器快速切换
}
}
// 更新RTC时间
RTC_Get();
}
TIM2->SR &= ~(1 << 0); // 清除中断标志位
}
// TIM3中断处理函数 - 用于处理LED显示、数码管刷新等
void TIM3_IRQHandler(void) {
if(TIM3->SR & 0X0001) { // 溢出中断
// 数码管显示(所有状态都显示时间)
Display_Time();
// 根据系统状态执行不同的LED操作
switch(system_state) {
case STATE_NORMAL:
// 正常状态:LED6和LED7呼吸灯交替亮暗
//Breath_LED();
break;
case STATE_FALL_DETECTED:
// 检测到摔倒:LED0-LED7流水灯闪烁,蜂鸣器持续响
Flow_LED();
BEEP = 0; // 蜂鸣器持续响
break;
case STATE_CONFIRMED_SAFE:
// 确认安全:LED6和LED7呼吸灯交替亮暗
//Breath_LED();
BEEP = 1; // 停止蜂鸣器
break;
case STATE_CONFIRMED_UNSAFE:
// 确认不安全:LED0-LED7流水灯闪烁
Flow_LED();
// 蜂鸣器由TIM2控制每3秒响一次
break;
}
// 所有LED全亮标志处理
if(all_led_on) {
LED_ON_OFF(0x00); // 所有LED全亮
}
}
TIM3->SR &= ~(1 << 0); // 清除中断标志位
}
// 数码管显示时间
void Display_Time(void) {
switch(smg_wei) {
case 0: num = smg_num[calendar.hour / 10]; break; // Hour tens
case 1: num = smg_num[calendar.hour % 10]; break; // Hour units
case 2: num = 0x01; break; // Colon (using dot from segment codes)
case 3: num = smg_num[calendar.min / 10]; break; // Minute tens
case 4: num = smg_num[calendar.min % 10]; break; // Minute units
case 5: num = 0x01; break; // Colon
case 6: num = smg_num[calendar.sec / 10]; break; // Second tens
case 7: num = smg_num[calendar.sec % 10]; break; // Second units
}
LED_Write_Data(num, smg_wei); // Write data
LED_Refresh(); // Refresh display
smg_wei = (smg_wei + 1) % 8; // Cycle through bit selection
}
// 流水灯效果(LED0-LED7依次闪烁)
void Flow_LED(void) {
flow_count++;
if(flow_count >= 20) { // Adjust flowing speed
flow_count = 0;
// Use bit operation to light current LED
LED_Shift = ~(1 << flow_index); // Light current LED
LED_ON_OFF(LED_Shift);
flow_index = (flow_index + 1) % 8; // Cycle through LEDs
}
}
// 串口命令处理函数
void USART_ProcessCommand(u8* buf, u16 len) {
// Compare received command with "SOS received"
const char* cmd = "SOS received";
if(len == strlen(cmd)) {
if(strncmp((char*)buf, cmd, len) == 0) {
// LED0 to LED7 all on and buzzer sounds
all_led_on = 1;
all_led_timer = 0;
sos_beep_flag = 1; // 启动SOS蜂鸣器
sos_beep_timer = 0;
// Output confirmation message to serial
printf("All LEDs ON and Buzzer activated\r\n");
}
}
// 处理设置时间命令
if(len >= 7 && strncmp((char*)buf, "SETTIME:", 8) == 0) {
// 命令格式: SETTIME:2024-01-01 12:00:00
int year, month, day, hour, min, sec;
if(sscanf((char*)buf + 8, "%d-%d-%d %d:%d:%d",
&year, &month, &day, &hour, &min, &sec) == 6) {
RTC_Set(year, month, day, hour, min, sec);
printf("RTC time set to: %d-%02d-%02d %02d:%02d:%02d\r\n",
year, month, day, hour, min, sec);
} else {
printf("Invalid time format. Use: SETTIME:YYYY-MM-DD HH:MM:SS\r\n");
}
}
// 处理重置命令
if(len == 6 && strncmp((char*)buf, "RESET", 5) == 0) {
Reset_To_Normal_State();
printf("System manually reset to normal state\r\n");
}
}
void TIM3_PWM_Init(u16 arr, u16 psc)
{
// 1. 开启时钟
RCC->APB1ENR |= 1 << 1; // TIM3时钟使能
RCC->APB2ENR |= 1 << 4; // GPIOC时钟使能
RCC->APB2ENR |= 1 << 0; // AFIO时钟使能
// 2. 配置GPIO为复用推挽输出
// PC6 - TIM3_CH1 (完全重映射)
GPIOC->CRL &= 0xF0FFFFFF; // 清除PC6配置位
GPIOC->CRL |= 0x0B000000; // 50MHz, 复用推挽输出
// PC7 - TIM3_CH2 (完全重映射)
GPIOC->CRL &= 0x0FFFFFFF; // 清除PC7配置位
GPIOC->CRL |= 0xB0000000; // 50MHz, 复用推挽输出
// 3. 完全重映射:TIM3_CH1->PC6, TIM3_CH2->PC7
AFIO->MAPR &= 0xFFFFF3FF; // 清除MAPR的[11:10]
AFIO->MAPR |= 3 << 10; // 完全重映射 (11)
// 4. 配置TIM3时基
TIM3->ARR = arr; // 自动重装载值
TIM3->PSC = psc; // 预分频器
// 5. 配置通道1 (PC6)
TIM3->CCMR1 |= 6 << 4; // OC1M=110, PWM模式1
TIM3->CCMR1 |= 1 << 3; // OC1PE=1, 预装载使能
TIM3->CCER |= 1 << 0; // CC1E=1, 输出使能
TIM3->CCR1 = 500; // 初始占空比50%
// 6. 配置通道2 (PC7)
TIM3->CCMR1 |= 6 << 12; // OC2M=110, PWM模式1
TIM3->CCMR1 |= 1 << 11; // OC2PE=1, 预装载使能
TIM3->CCER |= 1 << 4; // CC2E=1, 输出使能
TIM3->CCR2 = 500; // 初始占空比50%
// 7. 使能定时器
TIM3->CR1 |= 1 << 7; // ARPE=1, 自动重装载预装载使能
TIM3->CR1 |= 1 << 0; // CEN=1, 使能计数器
printf("TIM3 PWM Initialized: PC6(TIM3_CH1), PC7(TIM3_CH2)\r\n");
}
|
|