|
|
各位帖友大家好,本人是一枚剛學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");
}
|
|