update code

This commit is contained in:
aiden
2026-05-27 15:00:59 +08:00
parent 85f0d9e863
commit e4d2616bb9
8 changed files with 1573 additions and 234 deletions
@@ -21,7 +21,7 @@
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.createflash.249191345" name="Create flash image" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.createflash" value="true" valueType="boolean"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.createlisting.243120876" name="Create extended listing" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.createlisting" value="true" valueType="boolean"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.printsize.1566043258" name="Print size" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.addtools.printsize" value="true" valueType="boolean"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level.1801001334" name="Optimization Level" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level" value="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level.optimize" valueType="enumerated"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level.1801001334" name="Optimization Level" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level" value="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.level.more" valueType="enumerated"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.messagelength.651682061" name="Message length (-fmessage-length=0)" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.messagelength" value="true" valueType="boolean"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.signedchar.1219903449" name="'char' is signed (-fsigned-char)" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.signedchar" value="true" valueType="boolean"/>
<option id="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.functionsections.168524687" name="Function sections (-ffunction-sections)" superClass="ilg.gnumcueclipse.managedbuild.cross.riscv.option.optimization.functionsections" value="true" valueType="boolean"/>
@@ -67,6 +67,7 @@ extern "C"
void bode_plot_param_read_from_flash(struct bode_plot_param_t *param, uint32_t addr);
extern struct bode_plot_param_t bode_plot_param;
extern struct bode_plot_param_t pfc_vloop_bode_plot_param;
#ifdef __cplusplus
}
@@ -32,8 +32,8 @@ extern "C"
#define YN_MAX (PFC_DUTY_MAX << 14)
#define YN_MIN (PFC_DUTY_MIN << 14)
// VBUS 參數
#define VBUS_SET 360 // unit: volt (Transformer N = 14)
#define VBUS_SET_H (VBUS_SET + 20) // burst mode in, 在過零區判斷
#define VBUS_SET 340 // unit: volt (Transformer N = 14)
#define VBUS_SET_H (VBUS_SET + 30) // burst mode in, 在過零區判斷
#define VBUS_SET_L (VBUS_SET - 20) // burst mode out, 在過零區判斷
// #define VBUS_SET_H2 370 // for skip mode
#define VBUS_OVP 410 // 420V 電容
@@ -9,6 +9,7 @@
#define TICK_1000_MS 1000
struct bode_plot_param_t bode_plot_param;
struct bode_plot_param_t pfc_vloop_bode_plot_param;
static int bode_plot_param_write_to_flash(const struct bode_plot_param_t *param, uint32_t addr);
@@ -129,7 +129,7 @@ void gpio_config()
// PA7(iac), PA10(vbus), PA13(vac) // PA11(cr), PA12(vfb)-->GPIO
//-----------------//
GPIO_InitTypeDef GPIO_InitADC;
GPIO_InitADC.GPIO_Pin = GPIO_Pin_07 | GPIO_Pin_10 | GPIO_Pin_13 | GPIO_Pin_11; // PA11(cr)
GPIO_InitADC.GPIO_Pin = GPIO_Pin_07 | GPIO_Pin_10 | GPIO_Pin_13; // | GPIO_Pin_11; // PA11(cr)
GPIO_InitADC.GPIO_Mode = GPIO_Mode_ANAL;
GPIO_Init(GPIOA, &GPIO_InitADC);
@@ -192,7 +192,7 @@ void adc_config(void)
// ----------------------------------------------
// vcr = PA11 = ADC_Channel_05 (未使用)
// vfb = PA12 = ADC_Channel_06 (使用 GPIO)
init1.SelChannels = ADC_Channel_04 | ADC_Channel_07 | ADC_Channel_09;
init1.SelChannels = ADC_Channel_04 | ADC_Channel_07 | ADC_Channel_09 | ADC_Channel_05;
// init1.SelChannels = ADC_Channel_09 ;// OP_O 指定到 PA7 時,ADC 需要用 CH_09 讀取
init1.ClkPrescaler = ADC_ClkDiv_4; // 60M/4 = 15M,接近 1MSPS (1us 轉換時間), 最快速度
init1.DataAlign = ADC_DataAlign_Right;
@@ -1,5 +1,4 @@
#include "main.h"
#include "app.h"
#include "init.h"
@@ -10,7 +9,7 @@
#define DATA_LOG 0
#define DATA_MONITOR 0
#define DEBOUNCE_TIME 20
#define BUF_SIZE 100 // > 300 記憶體不夠用(4組) > 700 記憶體不夠用(2組)
#define BUF_SIZE 300 // > 300 記憶體不夠用(4組) > 700 記憶體不夠用(2組)
#define CR_1P1Z_B0_Q14 6313
#define CR_1P1Z_B1_Q14 -5113
@@ -63,13 +62,15 @@ typedef enum
SystemState_t sys_state = STATE_INIT;
uint8_t is_zero_crossing = 0;
uint8_t burst_mode_active = 0;
uint8_t skip_mode_active = 0;
uint8_t llc_running = 0;
uint8_t pfc_running = 0;
static uint8_t last_is_zero_crossing = 0;
uint8_t is_brown_in = 0; // 0: 關機/保護中, 1: 正常工作
uint8_t ff_active = 0;
static volatile int32_t print1, print2;
static volatile int64_t print3;
// static volatile int32_t print1, print2;
// static volatile int64_t print3;
static uint16_t iac = 0;
static uint16_t vac = 0;
@@ -111,28 +112,30 @@ uint8_t keyInput;
//-----------------------------------------------
uint8_t power_on_cmd = 0;
uint8_t temp_off = 0;
uint32_t msg_timer;
uint16_t vbus_volt, vac_volt;
int32_t tx_buf1[BUF_SIZE];
int64_t tx_buf2[BUF_SIZE];
int32_t tx_buf2[BUF_SIZE];
// uint16_t tx_buf3[BUF_SIZE];
// uint16_t tx_buf4[BUF_SIZE];
uint16_t buf_idx = 0;
uint8_t is_full = 0;
uint16_t count_down = 60000; // for data log
uint16_t count_down = 2000; // for data log
uint16_t i_ff;
uint32_t vac_avg1, vac_avg2, vac_avg3;
uint32_t vbus_avg = 0;
uint32_t vcr_avg;
static volatile uint16_t vac_pk1, vac_pk2;
uint8_t hi_line = 0; // 0=110V, 1=220V
uint8_t vbus_ready = 0;
uint16_t hi_cnt, lo_cnt;
uint32_t static digital_vcomp = (LLC_PERIOD_MAX - LLC_PERIOD_MIN) << LLC_COMP_GAIN_BIT;
uint32_t static digital_vcomp = (LLC_PERIOD_MAX - LLC_PERIOD_MIN)
<< LLC_COMP_GAIN_BIT;
int16_t fb_enent;
uint16_t llc_period_ss = LLC_SS_MIN;
uint16_t llc_run_arr = LLC_PERIOD_MIN;
uint16_t llc_arr_cmp = 0;
uint8_t v_loop_cnt = 0;
uint8_t v_loop_cnt2 = 0;
uint16_t brownout_cnt = 0;
uint8_t volatile tim0_trigger = 0;
@@ -286,15 +289,18 @@ void Power_Off()
//===================================================================================
void llc_set_period(uint16_t val)
{
if (val > LLC_PERIOD_MAX) val = LLC_PERIOD_MAX; // 可以小,不能過大
if (val > LLC_PERIOD_MAX)
val = LLC_PERIOD_MAX; // 可以小,不能過大
EPWM->ARR = val;
EPWM->CCR1 = val >> 1;
}
//===================================================================================
void pfc_set_duty(uint16_t val)
{
if (val > PFC_DUTY_MAX) val = PFC_DUTY_MAX;
if (val < PFC_DUTY_MIN) val = PFC_DUTY_MIN;
if (val > PFC_DUTY_MAX)
val = PFC_DUTY_MAX;
if (val < PFC_DUTY_MIN)
val = PFC_DUTY_MIN;
TIM2->CCR1 = val;
}
//===================================================================================
@@ -318,78 +324,6 @@ void pfc_pwm_disable()
REG_CLR_BITS(TIM2->CCER, TIM_CCER_CC1E_Msk);
}
//======================================================================================
void Vol_Loop_PFC_1P1Z(void) // TEST OK
{
// 1. 計算誤差
int32_t vbus_err_n = (int32_t)vbus_set - (int32_t)vbus_avg;
// --- 策略 A:動態增益調整 ---
int32_t b0 = 135;
int32_t b1 = -134;
if (vbus_err_n > 30 || vbus_err_n < -30)
{
// 大誤差時(通常是剛啟動或大跳載),強化參數加快反應
// b0 = 250;
// b1 = -240;
b0 = 180; // 稍微調降強增益的力道
b1 = -175;
}
// --- 策略 B:接近目標時微調零點 (抗過衝) ---
else if (vbus_err_n < 20 && vbus_err_n > -20)
{
// 當誤差縮小時,稍微減小 b0 與 b1 的差值,降低積分衝力
b0 = 120;
b1 = -119; // 如果不能用浮點數,請維持 120 / -119,增加阻尼感
}
// 2. 差分方程計算
int64_t acc = (int64_t)b0 * vbus_err_n;
acc += (int64_t)b1 * vbus_err_1;
acc += ((int64_t)16384 * vbus_comp_1) >> 14; // 16384 = 1 >> 14
int32_t y_n = (int32_t)acc;
#if 0 // 有問題
// --- 策略 C:軟限制抗過衝 (Soft Clamping) ---
// 預設最大限制 (Duty 300 << 14)
int32_t current_max_limit = 4915200; // duty 300
// 如果電壓誤差已經很小(例如剩 15V 就到達),甚至已經發生過衝 (err < 0)
// 我們強制壓低 Duty 的允許上限,防止積分器帶著大 Duty 衝過頭
if (vbus_err_n < 15)
{
// 這裡的 3276800 對應 Duty 200,您可以根據 800W 穩態時的 Duty 大約位置來設定
// 核心目標是:不讓 Duty 在接近目標時還維持在 300 這麼高
current_max_limit = 3276800; // duty 200
}
// 如果發生明顯過衝 (電壓高於目標 5V 以上)
if (vbus_err_n < -5)
{
current_max_limit = 1638400; // 強制壓低到 Duty 100 快速拉回
}
#endif
// 3. 輸出限幅執行
if (y_n > YN_MAX)
y_n = YN_MAX;
else if (y_n < YN_MIN)
y_n = YN_MIN;
// 4. 更新狀態變數
vbus_err_1 = vbus_err_n;
vbus_comp_1 = y_n;
// 5. 輸出 Duty >> 14
if (sys_state == STATE_PFC_SOFT_START) // 緩啟動期間直接控制 DUTY
TIM2->CCR1 = (vbus_comp_1 >> 14); // 0~540
// 6. 輸出 comp >> 9 (變大 32 倍) (MAX ~ 18000) (540*32=17280)差不多,>> 9 應該是對的
if (sys_state == STATE_RUN_NORMAL) // 正常工作時間輸出 COMP 值
vbus_comp2 = (vbus_comp_1 >> 9);
}
//==========================================================================
// Cr 1P1Z 回授,做負載驟變補償,執行頻率 10KHZ
// 抓取 vcr 的動態變化趨勢,並在穩態時回歸平靜
void Load_Loop_1P1Z(void)
@@ -419,29 +353,118 @@ void Load_Loop_1P1Z(void)
cr_feed_forward_output_q14 = y0;
}
//==========================================================================
void Vol_Loop_PFC_1P1Z(void) // TEST OK
{
// 1. 計算誤差
int32_t vbus_err_n = (int32_t)vbus_set - (int32_t)vbus_avg;
// --- 策略 A:動態增益調整 ---
// int32_t b0 = 135;
// int32_t b1 = -134;
int32_t b0 = 180;
int32_t b1 = -175;
// if (vbus_err_n > 30 || vbus_err_n < -30)
if (vbus_err_n > 80 || vbus_err_n < -80) // ~ 20V
{
// 大誤差時(通常是剛啟動或大跳載),強化參數加快反應
b0 = 250;
b1 = -240;
// b0 = 180; // 稍微調降強增益的力道
// b1 = -175;
}
// --- 策略 B:接近目標時微調零點 (抗過衝) ---
else if (vbus_err_n < 20 && vbus_err_n > -20) // ~ 5V
{
// 當誤差縮小時,稍微減小 b0 與 b1 的差值,降低積分衝力
b0 = 120;
b1 = -119; // 如果不能用浮點數,請維持 120 / -119,增加阻尼感
}
// 2. 差分方程計算
int64_t acc = (int64_t)b0 * vbus_err_n;
acc += (int64_t)b1 * vbus_err_1;
acc += ((int64_t)16384 * vbus_comp_1) >> 14; // 16384 = 1 >> 14
int32_t y_n = (int32_t)acc;
// 3. 輸出限幅執行
if (y_n > YN_MAX)
y_n = YN_MAX;
else if (y_n < YN_MIN)
y_n = YN_MIN;
// 4. 更新狀態變數
vbus_err_1 = vbus_err_n;
vbus_comp_1 = y_n;
// 5. 輸出 Duty >> 14
// if (sys_state == STATE_PFC_SOFT_START || sys_state == STATE_RUN_SKIP) // 緩啟動期間直接控制 DUTY
TIM2->CCR1 = (vbus_comp_1 >> 14); // 0 ~ 540
// 6. 輸出 comp >> 9 (變大 32 倍) (MAX ~ 18000) (540*32=17280)差不多,>> 9 應該是對的
// if (sys_state == STATE_RUN_NORMAL) // 正常工作時間輸出 COMP 值
vbus_comp2 = (vbus_comp_1 >> 9);
}
//=============================================================
static void Vol_Loop_PFC_1P1Z_UI(void) // ZERO: 120HZ, POLE:0.1HZ, G:10
{
// 1. 計算誤差
int32_t vbus_err_0 = (int32_t)vbus_set - (int32_t)vbus_avg;
// 2. 2P2Z 運算 (Fixed-point Q14)
struct bode_plot_param_t *vloop_p = &pfc_vloop_bode_plot_param;
int64_t acc1 = (int64_t)vloop_p->b0 * vbus_err_0 + (int64_t)vloop_p->b1 * vbus_err_1;
int64_t acc2 = (-((int64_t)vloop_p->a1 * vbus_comp_1)) >> 14;
acc1 += acc2;
int32_t y_n = acc1;
// 限制極限值
if (y_n > YN_MAX)
y_n = YN_MAX; // 540 << 14
else if (y_n < YN_MIN)
y_n = YN_MIN; // 12 << 14
// 更新狀態變數 (儲存原始計算值以保留積分能量)
vbus_err_1 = vbus_err_0;
// 重要:vbus_comp_1 儲存 local_temp,確保下一個週期的 a1, a2 運算正確
vbus_comp_1 = y_n;
// 5. 輸出 Duty >> 14
if (sys_state == STATE_PFC_SOFT_START || sys_state == STATE_RUN_SKIP) // 緩啟動期間直接控制 DUTY
TIM2->CCR1 = (vbus_comp_1 >> 14); // 0 ~ 540
// 6. 輸出 comp >> 9 (變大 32 倍) (MAX ~ 18000) (540*32=17280)差不多,>> 9 應該是對的
if (sys_state == STATE_RUN_NORMAL) // 正常工作時間輸出 COMP 值
vbus_comp2 = (vbus_comp_1 >> 9);
}
//========================================================================
__attribute__((always_inline)) static inline void Cur_Loop_PFC_2P2Z(void) // 優化後 3.65us
{
if (sys_state != STATE_RUN_NORMAL) return;
if (sys_state != STATE_RUN_NORMAL)
return;
if (is_zero_crossing == 1) return; // 凍結積分,改善過零後上升緣的突波
// if (is_zero_crossing == 1) return; // 凍結積分,改善過零後上升緣的突波
// 1. 取得回授與計算誤差
int32_t local_vbus_comp2 = vbus_comp2;
int32_t local_vac_avg1 = vac_avg1;
// 電流採樣處理
int32_t local_iac = 3840 - iac; // OPA 電路的關係,實際值為 CURR_OFFSET - ADC
if (local_iac < 0) local_iac = 0; // 避免負值
int32_t local_iac = 3840 - iac; // OPA 電路的關係,實際值為 CURR_OFFSET - ADC
if (local_iac < 0)
local_iac = 0; // 避免負值
// 計算電流給定值
// int32_t local_iac_set = (local_vac_avg1 * local_vbus_comp2) / 5700;
int32_t local_iac_set = (local_vac_avg1 * local_vbus_comp2) >> 12; // >> 12 = / 4096
int32_t local_iac_set = (local_vac_avg1 * local_vbus_comp2) >> 13; // >> 13 = / 8192 (解析度較高)
int32_t local_iac_err_0 = local_iac_set - local_iac; // err = set - meas
// print1 = local_iac_err_0;
// print2 = local_iac_set;
// 2. 2P2Z 運算 (Fixed-point Q14)
#if 1
struct bode_plot_param_t *bplot_p = &bode_plot_param;
@@ -468,17 +491,16 @@ __attribute__((always_inline)) static inline void Cur_Loop_PFC_2P2Z(void) // 優
iac_comp_2 = iac_comp_1;
iac_comp_1 = y_n;
// 4. 硬體 Duty 限幅與輸出
#if 0
uint16_t local_duty = (uint16_t)(y_n >> 14);
#else
uint16_t local_duty = 0;
int32_t ff_term;
if (vac_avg1 > 0) ff_term = ((uint32_t)(vbus_avg - vac_avg1) * PFC_DUTY_MAX) / vbus_avg;
// if (vac_avg1 > 0) ff_term = ((uint32_t) (2300 - vac_avg1) * PFC_DUTY_MAX) / 2300; // 2500=300V(不需要太高), 2300 會振??
// 低一點中間不會有尖波,且輸出功率小一點
local_duty = (uint16_t)((y_n >> 14) + ff_term);
#endif
// local_duty = (uint16_t)(y_n >> 14);
// 4. 硬體 Duty 限幅與輸出
if (local_duty > PFC_DUTY_MAX)
local_duty = PFC_DUTY_MAX; // MAX = 540
else if (local_duty < PFC_DUTY_MIN)
@@ -528,7 +550,8 @@ void Vol_Loop_LLC(void) // 測試可工作
else
{
// 如果 GPIO 長時間沒翻轉,說明離目標還很遠
if (stable_timer < 1000) stable_timer++;
if (stable_timer < 1000)
stable_timer++;
}
// 3. 根據翻轉頻率決定步長
@@ -539,7 +562,8 @@ void Vol_Loop_LLC(void) // 測試可工作
current_step = 0; // 設為 0 表示進入死區,完全停止震盪
// 為了防止永久卡死,當連續相同狀態一段時間後再恢復調整
if (stable_timer > 50) toggle_cnt = 0;
if (stable_timer > 50)
toggle_cnt = 0;
}
else
{
@@ -565,8 +589,10 @@ void Vol_Loop_LLC(void) // 測試可工作
// 5. 計算並更新 ARR (原本的邏輯)
uint32_t new_arr = LLC_PERIOD_MIN + (digital_vcomp >> LLC_COMP_GAIN_BIT);
if (new_arr > LLC_PERIOD_MAX) new_arr = LLC_PERIOD_MAX;
if (new_arr < LLC_PERIOD_MIN) new_arr = LLC_PERIOD_MIN;
if (new_arr > LLC_PERIOD_MAX)
new_arr = LLC_PERIOD_MAX;
if (new_arr < LLC_PERIOD_MIN)
new_arr = LLC_PERIOD_MIN;
if (EPWM->ARR != new_arr)
{
@@ -588,7 +614,7 @@ __INTERRUPT void isr_adc_handle(void)
iac = ADC0->DAT9_b.DATA; // PA7, AIN9
vac = ADC0->DAT7_b.DATA; // PA13, AIN7
vbus = ADC0->DAT4_b.DATA; // PA10, AIN4
vcr = ADC0->DAT5_b.DATA; // PA11, AIN5
// vcr = ADC0->DAT5_b.DATA; // PA11, AIN5
Cur_Loop_PFC_2P2Z(); // current loop
@@ -615,11 +641,12 @@ void reset_pid_parameters(void)
//==============================================================================
void Handle_UART_Monitor(void)
{
static uint32_t msg_timer = 0;
if (sys_get_tick() - msg_timer >= 1000) // msg_out = 1, print
{
// printf("%d %d %d\r\n", vac_pk1, vac_pk2, is_brown_in);
// printf("%d %d %d %d %d %d", power_on_cmd, sys_state, vbus_comp2, print1, print2, print3);
printf("%d %d %d", power_on_cmd, sys_state, vbus_comp2);
msg("%d %d %d %d\r\n", power_on_cmd, sys_state, vbus_comp2, vbus_avg);
// 電壓環輸出最大 COMP,但是電流環輸出最小 DUTY
msg_timer = sys_get_tick();
}
@@ -646,7 +673,8 @@ void Vac_Peak_Detector(void)
{
is_zero_crossing = 0;
last_is_zero_crossing = 0;
if (vac > vac_pk1) vac_pk1 = vac; // 只有比目前紀錄大才更新,確保 vac_pk1 停在波峰
if (vac > vac_pk1)
vac_pk1 = vac; // 只有比目前紀錄大才更新,確保 vac_pk1 停在波峰
}
else
{
@@ -661,12 +689,14 @@ void Vac_Peak_Detector(void)
if (is_brown_in == 0)
{
// 目前處於關閉狀態,檢查是否達到啟動門檻
if (vac_pk2 >= VOLT_BROWN_IN) is_brown_in = 1; // 執行 Brown-in
if (vac_pk2 >= VOLT_BROWN_IN)
is_brown_in = 1; // 執行 Brown-in
}
else
{
// 目前處於啟動狀態,檢查是否低於欠壓門檻
if (vac_pk2 < VOLT_BROWN_OUT) is_brown_in = 0; // 執行 Brown-out
if (vac_pk2 < VOLT_BROWN_OUT)
is_brown_in = 0; // 執行 Brown-out
}
vac_pk1 = 0; // 交接完後立即清零,為下半周做準備
@@ -704,16 +734,195 @@ static void uart_rx_task(void)
int main(void)
{
struct bode_plot_param_t *bplot_p = &bode_plot_param;
struct bode_plot_param_t *vloop_p = &pfc_vloop_bode_plot_param;
// 基礎硬體底層設定 (HIRC 60MHz, GPIO, ADC 採樣率 1Msps) [cite: 55, 127, 184]
SYS_Config();
// PFC 電流環參數
bode_plot_param_read_from_flash(bplot_p, FLASH_PROG_ADDR_USER_CALI);
vbus_comp2 = 3000;
sys_state = STATE_RUN_NORMAL;
pfc_pwm_enable();
pfc_running = 1;
/*********************************************************************/
/* PFC 電壓環參數*/
vloop_p->a2 = 0;
vloop_p->b2 = 0;
// 120HZ, 0.1Hz, 100G
vloop_p->b0 = 139;
vloop_p->b1 = -129;
vloop_p->a1 = -16383;
/*********************************************************************/
/* PFC 電流環參數*/
// bplot_p->b0 = 12368803;
// bplot_p->b1 = -19162610;
// bplot_p->b2 = 7037429;
// bplot_p->a1 = -20921;
// bplot_p->a2 = 4545;
/*********************************************************************/
#if 0 // 單測 PFC 電壓環 (OK)
while(1)
{
if (tim0_trigger == 1) // 100KHZ
{
tim0_trigger = 0;
// --- 1. 高速信號濾波 (簡易位移算法減少算力消耗) ---
vac_avg1 = (vac_avg1 - (vac_avg1 >> 3)) + (vac >> 3); // for current loop
vbus_avg = (vbus_avg - (vbus_avg >> 4)) + (vbus >> 4); // for voltage loop
vcr_avg = (vcr_avg - (vcr_avg >> 3)) + (vcr >> 3);
if (vbus > vbus_ovp) Power_Off(); // ovp
Vac_Peak_Detector();
if (power_on_cmd == 1)
{
if (pfc_running == 0)
{
pfc_pwm_enable();
pfc_running = 1;
}
if (++v_loop_cnt >= 10) // 10KHZ
{
//Vol_Loop_PFC_1P1Z_UI();
Vol_Loop_PFC_1P1Z();
v_loop_cnt = 0;
}
}
}
Key1_Scan();
//Handle_UART_Monitor();
if (is_full == 1)
{
sys_delay(10);
Handle_UART_Log();
}
}
#endif
#if 1 // 單測 PFC 電流環 (OK)
while (1)
{
uart_rx_task();
if (tim0_trigger == 1) // 100KHZ
{
tim0_trigger = 0;
// --- 1. 高速信號濾波 (簡易位移算法減少算力消耗) ---
vac_avg1 = (vac_avg1 - (vac_avg1 >> 3)) + (vac >> 3); // for current loop
vbus_avg = (vbus_avg - (vbus_avg >> 4)) + (vbus >> 4); // for voltage loop
// vcr_avg = (vcr_avg - (vcr_avg >> 3)) + (vcr >> 3);
if (vbus > vbus_ovp) Power_Off(); // ovp
Vac_Peak_Detector();
if (power_on_cmd == 1)
{
if (is_zero_crossing == 1)
{
sys_state = STATE_RUN_NORMAL;
// --- 關鍵修正:重新初始化電壓環內部狀態 ---
// 給予一個極小的初始 COMP 值,讓它從輕載慢慢往上爬
// vbus_comp_1 = (10 << 14); // 假設從一個極小的係數開始
vbus_err_1 = 0; // 清除誤差歷史
// vbus_comp2 = (vbus_comp_1 >> 9); // 讓電流環拿到的初始值是 10
vbus_comp2 = 3000;
// vset / 5700
// vbus_comp2: 3000, 275V / 0.25A = 68W
// vbus_comp2: 4000, 314V / 0.25A = 78W
// vbus_comp2: 5000, 360V / 0.25A = 90W
// vset >> 13 ( / 8192)
// vbus_comp2: 3000, 256V / 0.25A = 64W
// vbus_comp2: 4000, 267V / 0.25A = 66W
// vbus_comp2: 5000, 293V / 0.25A = 73W
// vbus_comp2: 2000, 298V / 0.25A = 75W ?? 波形不對
// vbus_comp2: 1000, 398V / 0.25A = 75W ??
}
else if (sys_state == STATE_RUN_NORMAL)
{
if (pfc_running == 0)
{
pfc_pwm_enable();
pfc_running = 1;
}
}
}
}
Key1_Scan();
}
#endif
#if 0 // 測試 PFC 電壓環 + 電流環 (OK)
TIM2->CCR1 = 12; // min duty
sys_state = STATE_PFC_SOFT_START;
Vac_Peak_Detector();
pfc_running = 0;
while(1)
{
if (tim0_trigger == 1) // 100KHZ
{
tim0_trigger = 0;
// --- 1. 高速信號濾波 (簡易位移算法減少算力消耗) ---
vac_avg1 = (vac_avg1 - (vac_avg1 >> 3)) + (vac >> 3); // for current loop
vbus_avg = (vbus_avg - (vbus_avg >> 4)) + (vbus >> 4); // for voltage loop
if (vbus > vbus_ovp) Power_Off(); // ovp
Vac_Peak_Detector();
if (power_on_cmd == 1)
{
if (sys_state == STATE_PFC_SOFT_START)
{
if (pfc_running == 0) {
pfc_pwm_enable();
pfc_running = 1;
}
if (++v_loop_cnt >= 10) // 10KHZ
{
Vol_Loop_PFC_1P1Z_UI();
v_loop_cnt = 0;
}
if (vbus_avg > vbus_set_l && is_zero_crossing == 1)
{
sys_state = STATE_RUN_NORMAL;
// --- 關鍵修正:重新初始化電壓環內部狀態 ---
// 給予一個極小的初始 COMP 值,讓它從輕載慢慢往上爬
vbus_comp_1 = (10 << 14); // 假設從一個極小的係數開始
vbus_err_1 = 0; // 清除誤差歷史
vbus_comp2 = (vbus_comp_1 >> 9); // 讓電流環拿到的初始值是 10
}
}
else if (sys_state == STATE_RUN_NORMAL)
{
if (pfc_running == 0) {
pfc_pwm_enable();
pfc_running = 1;
}
if (++v_loop_cnt >= 10) // 10KHZ
{
Vol_Loop_PFC_1P1Z_UI();
v_loop_cnt = 0;
}
}
}
}
Key1_Scan();
//Handle_UART_Monitor();
}
#endif
// main loop
while (1)
@@ -728,144 +937,213 @@ int main(void)
// 高速信號濾波 (簡易位移算法減少算力消耗) ---
vac_avg1 = (vac_avg1 - (vac_avg1 >> 3)) + (vac >> 3); // for current loop
vbus_avg = (vbus_avg - (vbus_avg >> 4)) + (vbus >> 4); // for voltage loop
vcr_avg = (vcr_avg - (vcr_avg >> 3)) + (vcr >> 3);
// 系統安全監控 (軟體第二道防護)
// vbus ovp
if (vbus > vbus_ovp)
{
sys_state = STATE_FAULT;
msg("%d %d %d %d \r\n", power_on_cmd, sys_state, vbus_comp_1, vbus_comp2);
// 1 6 196608, >> 9 = 384
Power_Off();
} // vbus ovp
if (vac_pk2 > 2600)
{
sys_state = STATE_FAULT;
Power_Off();
} // vac over voltage
if (power_on_cmd == 0 && pfc_running == 1) Power_Off();
}
// vac over voltage
/*
if (vac_pk2 > 2600)
{
sys_state = STATE_FAULT;
Power_Off();
}
// vac brown out
if (vac_pk2 < VOLT_BROWN_OUT && pfc_running == 1)
{
sys_state = STATE_FAULT;
Power_Off();
}
*/
Vac_Peak_Detector(); // VAC 峰值偵測
if (sys_get_tick() > 100 && power_on_cmd == 1 && is_zero_crossing == 1)
#if 1
// --- 2. 核心狀態機邏輯 -----------------------------------------------------------------------
switch (sys_state)
{
sys_state = STATE_RUN_NORMAL;
if (pfc_running == 0)
{
pfc_pwm_enable();
pfc_running = 1;
}
}
case STATE_INIT: // 0
// 等待約 100ms,並按下按鍵
if (sys_get_tick() > 100 && power_on_cmd == 1)
{
sys_state = STATE_STANDBY;
}
break;
#if 0
// --- 2. 核心狀態機邏輯 -----------------------------------------------------------------------
switch (sys_state)
{
case STATE_INIT: // 0
// 等待約 100ms,並按下按鍵
if (sys_get_tick() > 100 && power_on_cmd == 1) {
sys_state = STATE_STANDBY;
}
break;
case STATE_STANDBY: // 1
// Brown-in 判斷
if (is_brown_in == 1)
{
sys_state = STATE_PFC_SOFT_START; // 先進 PFC SS
TIM2->CCR1 = PFC_DUTY_MIN;
}
break;
case STATE_STANDBY: // 1
// Brown-in 判斷
if (is_brown_in == 1) {
sys_state = STATE_PFC_SOFT_START; // 先進 PFC SS
TIM2->CCR1 = PFC_DUTY_MIN;
}
break;
case STATE_PFC_SOFT_START: // 2
if (pfc_running == 0)
{
pfc_pwm_enable();
pfc_running = 1;
}
case STATE_PFC_SOFT_START: // 2
// 若 vbus < 320 做 pre-charge
if (vbus_avg < vbus_set_l)
{
if (pfc_running == 0) {
pfc_pwm_enable();
pfc_running = 1;
}
if (++v_loop_cnt >= 10) {
Vol_Loop_PFC_1P1Z();
v_loop_cnt = 0;
}
}
else
{
//pfc_pwm_disable(); // 測試 OK
//pfc_running = 0;
// PFC 不關閉,在 LLC SS 期間進閉環
// sys_state = STATE_PAUSE; // 先暫停,測試用
// sys_state = STATE_LLC_SOFT_START;
// 準備 LLC 軟啟動參數 (起點頻率 2倍諧振頻率)
//llc_period_ss = LLC_SS_MIN; // 已經放大 4 倍
sys_state = STATE_RUN_NORMAL; // 直接接電流環
// 重要動作
vbus_comp_1 = (10 << 14); // 假設從一個極小的係數開始
vbus_err_1 = 0; // 清除誤差歷史
}
break;
if (++v_loop_cnt >= 10) // 10KHZ
{
Vol_Loop_PFC_1P1Z_UI();
v_loop_cnt = 0;
}
case STATE_RUN_NORMAL: // 4
//if (pfc_running == 0) {
// pfc_pwm_enable();
// pfc_running = 1;
//}
if (vbus_avg > vbus_set_l)
{
sys_state = STATE_LLC_SOFT_START;
llc_period_ss = LLC_SS_MIN;
pfc_pwm_disable();
pfc_running = 0;
TIM2->CCR1 = PFC_DUTY_MIN;
// --- 關鍵修正:重新初始化電壓環內部狀態 ---
// 給予一個極小的初始 COMP 值,讓它從輕載慢慢往上爬
// vbus_comp_1 = (10 << 14); // 假設從一個極小的係數開始
// vbus_err_1 = 0; // 清除誤差歷史
// vbus_comp2 = (vbus_comp_1 >> 9); // 讓電流環拿到的初始值是 10
}
break;
if (++v_loop_cnt >= 10) {
// 先算前饋,再算主環,最後疊加
//Load_Loop_1P1Z(); // Cr 前饋
Vol_Loop_PFC_1P1Z(); // PFC 電壓環
//Vol_Loop_PFC();
//Vol_Loop_LLC(); // LLC 電壓環
v_loop_cnt = 0;
}
case STATE_LLC_SOFT_START: // 3
// LLC 軟啟動:頻率由高往低掃描 (掃向 1倍諧振頻率)
llc_period_ss++;
llc_ss_cnt++;
llc_set_period(llc_period_ss >> 2); // 放大 4 倍,要除 4 回來
break;
if (llc_running == 0)
{
llc_pwm_enable();
llc_running = 1;
}
case STATE_RUN_SKIP: // 5
// 電壓外環計算 (10kHz)
if (++v_loop_cnt >= 10) {
//Vol_Loop_PFC(); // KP / KI 要快
//Vol_Loop_LLC();
v_loop_cnt = 0;
}
/* 有問題
// Brown-out 判斷
if (vac_pk2 < VAC_BROWN_OUT) {
brownout_cnt++;
if (brownout_cnt > BROWNOUT_DELAY) {
Power_Off();
sys_state = STATE_STANDBY;
}
}
else {
brownout_cnt = 0;
}
*/
/* 先不做
// --- BURST / SKIP 邏輯 (帶滯後區間) ---
// 只在過零點判斷
if (is_zero_crossing == 1) {
if (vbus_avg > vbus_set_h) { // 上限觸發停機
pfc_pwm_disable();
burst_mode_active = 1;
}
else if (vbus_avg < vbus_set_l && burst_mode_active == 1) { // 下限觸發回復
reset_pid_parameters();
pfc_pwm_enable();
burst_mode_active = 0;
}
}
*/
break;
if (llc_ss_cnt >= LLC_SS_COUNT && is_zero_crossing == 1)
{
sys_state = STATE_RUN_NORMAL;
// sys_state = STATE_PAUSE; // 測試用
// 重要動作 =====================================
vbus_comp_1 = YN_MIN; // 假設從一個極小的係數開始
vbus_comp2 = (vbus_comp_1 >> 9);
vbus_err_1 = 0; // 清除誤差歷史
iac_err_2 = 0;
iac_err_1 = 0;
iac_comp_2 = YN_MIN;
iac_comp_1 = YN_MIN;
// msg("%d %d %d %d \r\n", power_on_cmd, sys_state, vbus_comp_1, vbus_comp2);
// 1 4 196608, = 12 << 14
// E LOAD 抽太慢,導致 OVP ?? (是的)
}
break;
case STATE_FAULT: // 5
// 立即封鎖所有輸出
pfc_pwm_disable();
llc_pwm_disable();
// 記錄故障代碼,等待手動重置
break;
case STATE_RUN_NORMAL: // 4
if (pfc_running == 0)
{
pfc_pwm_enable();
pfc_running = 1;
}
case STATE_PAUSE: // 6
break;
/*
if (vbus_avg > vbus_set_h) {
TIM2->ARR = 1200; // 沒變??
msg("1\r\n");
}
else if (vbus_avg < vbus_set) {
TIM2->ARR = 600;
msg("2\r\n");
}
*/
} // switch case
if (++v_loop_cnt >= 10)
{
// 先算前饋,再算主環,最後疊加
// Load_Loop_1P1Z(); // Cr 前饋
Vol_Loop_PFC_1P1Z_UI(); // PFC 電壓環
// Vol_Loop_LLC(); // LLC 電壓環
v_loop_cnt = 0;
}
/*
if (++v_loop_cnt2 >= 15) {
Vol_Loop_LLC(); // LLC 電壓環
v_loop_cnt2 = 0;
}
*/
break;
case STATE_RUN_SKIP: // 5
// SKIP 時電壓環控制DUTY
/*
if (++v_loop_cnt >= 10) // 10KHZ
{
Vol_Loop_PFC_1P1Z();
v_loop_cnt = 0;
}
*/
// 1638400 >> 14 = 100 duty
// if (vbus_comp2 > 3000 && is_zero_crossing == 1) // back to normal run
if (vbus_avg < vbus_set_l && is_zero_crossing == 1) // back to normal run
{
sys_state = STATE_RUN_NORMAL;
// sys_state = STATE_PAUSE; // 測試用
// 重要動作 =====================================
vbus_comp_1 = YN_MIN; // 假設從一個極小的係數開始
vbus_comp2 = (vbus_comp_1 >> 9);
vbus_err_1 = 0; // 清除誤差歷史
iac_err_2 = 0;
iac_err_1 = 0;
iac_comp_2 = YN_MIN;
iac_comp_1 = YN_MIN;
}
/* 有問題
// Brown-out 判斷
if (vac_pk2 < VAC_BROWN_OUT) {
brownout_cnt++;
if (brownout_cnt > BROWNOUT_DELAY) {
Power_Off();
sys_state = STATE_STANDBY;
}
}
else {
brownout_cnt = 0;
}
*/
/* 先不做
// --- BURST / SKIP 邏輯 (帶滯後區間) ---
// 只在過零點判斷
if (is_zero_crossing == 1) {
if (vbus_avg > vbus_set_h) { // 上限觸發停機
pfc_pwm_disable();
burst_mode_active = 1;
}
else if (vbus_avg < vbus_set_l && burst_mode_active == 1) { // 下限觸發回復
reset_pid_parameters();
pfc_pwm_enable();
burst_mode_active = 0;
}
}
*/
break;
case STATE_FAULT: // 6
// 立即封鎖所有輸出
pfc_pwm_disable();
llc_pwm_disable();
// 記錄故障代碼,等待手動重置
break;
case STATE_PAUSE: // 7
break;
} // switch case
#endif
} // if tim0_trigger