#include "charge.h" #include "os.h" #include "bsp_charge.h" #include "bsp_battery.h" #include "gd32F30x.h" #include "sensor_tmp75.h" #include "gd32f303r_eval.h" #include /* 充电任务优先级 */ #define TASK_FSBB_CHARGE_PRIO 6 /* 充电任务堆栈大小 */ #define TASK_FSBB_CHARGE_STK_SIZE (256) static OS_TCB TaskFSBBChargeTCB; /* 充电任务控制块 */ static CPU_STK TaskFSBBChargeStk[TASK_FSBB_CHARGE_STK_SIZE]; /* 充电任务堆栈 */ static void Task_FSBB_Charge(void *p_arg); /* 充电任务函数声明 */ extern FsbbStatus_t fsbb_status ; extern uint32_t g_system_tick; extern GlobalVariableDef GlobalVariable; /** @brief 电源状态全局变量(由 TIMER7 ISR + 充电逻辑更新) */ volatile PowerStatus_t g_powerStatus; extern void delay_us(unsigned int i); /* 微秒延时函数 */ extern Filter FilterBuffer[]; /* 滤波缓冲区 */ extern uint8_t UPdataState; /* 升级状态标志 */ /** * @brief TIMER7 ISR 多级分频控制结构体 * @details 在 400kHz 中断中实现多级分频: * sys: 400000:1 → 1Hz (g_system_tick++) * volt: 4000:1 → 100Hz (电压采样 + 状态机 + 电压控制 + 模式选择 + 保护检查) * curr: 400:1 → 1kHz (电流采样 + dynamic_charge + current_control_loop) */ typedef struct { volatile uint32_t sys; /* 系统节拍分频 (0~399999, 需32位) */ volatile uint16_t volt; /* 电压采样分频 (0~4000) */ volatile uint16_t curr; /* 电流采样分频 (0~400) */ } Timer7Divider_t; static Timer7Divider_t t7_div = {0}; /* TIMER7 分频计数器 */ /* TIMER7 @400kHz 边沿对齐, 更新中断周期=2.5us, 1秒=400000次 */ #define T7_DIV_SYS 399999U /* g_system_tick++ 每 1s (400000:1) */ #define T7_DIV_VOLT 4000U /* 电压采样 100Hz (4000:1) */ #define T7_DIV_CURR 400U /* 电流采样 1kHz (400:1) */ /** * @brief 创建充电任务 * @param 无 * @return 无 * @note 在uC/OS-III中创建充电任务,优先级为6 */ void app_task_charge(void) { OS_ERR err; /* 创建充电任务 */ OSTaskCreate((OS_TCB *)&TaskFSBBChargeTCB, (CPU_CHAR *)"Task FSBB Charge", (OS_TASK_PTR )Task_FSBB_Charge, (void *)0u, (OS_PRIO )TASK_FSBB_CHARGE_PRIO, (CPU_STK *)&TaskFSBBChargeStk[0u], (CPU_STK_SIZE )TaskFSBBChargeStk[TASK_FSBB_CHARGE_STK_SIZE / 10u], (CPU_STK_SIZE )TASK_FSBB_CHARGE_STK_SIZE, (OS_MSG_QTY )0u, (OS_TICK )0u, (void *)0u, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); } /** * @brief 根据NTC电阻值计算温度 * @param R_NTC NTC热敏电阻值(单位:kΩ) * @param Temp 输出温度值指针 * @return 无 * @note 使用分段线性插值法计算温度 */ void GetTempFromRntc(float R_NTC, float * Temp) { if (R_NTC <= 4.8f) { *Temp = -9.7509f * R_NTC + 90.173f; } else if (R_NTC > 4.8f && R_NTC <= 10.0f) { *Temp = -3.7804f * R_NTC + 61.663f; } else if (R_NTC > 10.0f && R_NTC <= 14.3f) { *Temp = -2.0663 * R_NTC + 45.304f; } else if (R_NTC > 14.3f && R_NTC <= 22.4f) { *Temp = -1.2697f * R_NTC + 33.619f; } else if (R_NTC > 22.4f && R_NTC <= 28.5f) { *Temp = -0.884f * R_NTC + 25.169f; } else { *Temp = -0.3557f * R_NTC + 7.3795f; } } /** * @brief ADC1采集电池NTC温度(通道14) * @param 无 * @return ADC采样值 * @note 使用ADC1的通道14采集电池NTC温度 */ float BspBattery_GetNtc(void) { adc_regular_channel_config(ADC1, 0U, ADC_CHANNEL_14, ADC_SAMPLETIME_13POINT5); adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL); /* 等待转换结束标志 */ while(!adc_flag_get(ADC1, ADC_FLAG_EOC)); /* 清除转换结束标志 */ adc_flag_clear(ADC1, ADC_FLAG_EOC); /* 返回常规通道采样值 */ return (adc_regular_data_read(ADC1)); } /** * @brief 获取电池温度 * @param Temp 输出温度值指针 (°C) * @return 0-成功 * @note 通过ADC采集NTC电压 → 计算电阻值 → 分段线性插值查表 */ int GetBatteryTemp(float * Temp) { int is_OK = 0; float Rntc,adc; adc = BspBattery_GetNtc(); /* 采集NTC的ADC值 */ Rntc = adc * 10000.0f / (4096.0f - adc) / 1000.0f; /* 计算NTC电阻值(kΩ) */ GetTempFromRntc(Rntc, Temp); /* 根据电阻值查表得到温度 */ return is_OK; } /** * @brief 采集负载NTC温度(通道10) * @param 无 * @return ADC采样值 * @note 使用ADC1的通道10采集负载NTC温度 */ float BspLoad_GetNtc(void) { adc_regular_channel_config(ADC1, 0U, ADC_CHANNEL_10, ADC_SAMPLETIME_13POINT5); adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL); /* 等待转换结束标志 */ while(!adc_flag_get(ADC1, ADC_FLAG_EOC)); /* 清除转换结束标志 */ adc_flag_clear(ADC1, ADC_FLAG_EOC); /* 返回常规通道采样值 */ return (adc_regular_data_read(ADC1)); } /** * @brief 采集负载零电流参考值(通道13,PC0: CS_IOUT_ZERO) * @param 无 * @return ADC采样值 * @note 用于负载电流测量的零点校准 */ float BspLoad_zero_GetNtc(void) //PC0 CS_IOUT_ZERO { adc_regular_channel_config(ADC1, 0U, ADC_CHANNEL_13, ADC_SAMPLETIME_13POINT5); adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL); /* 等待转换结束标志 */ while(!adc_flag_get(ADC1, ADC_FLAG_EOC)); /* 清除转换结束标志 */ adc_flag_clear(ADC1, ADC_FLAG_EOC); /* 返回常规通道采样值 */ return (adc_regular_data_read(ADC1)); } /** * @brief 获取负载电流 * @param 无 * @return 负载电流值(单位:A) * @note 通过零电流参考值和负载电流采样值计算实际负载电流 * 电流计算公式:((adc_load - adc_zero)/4096)*3.3/0.132 */ float Load_GetI(void) //PC0 CS_IOUT_ZERO { float adc_zero = 0; /* 零电流参考ADC值 */ float adc_load = 0; /* 负载电流ADC值 */ float temp = 0; /* 计算结果 */ adc_zero = BspLoad_zero_GetNtc(); /* 采集零电流参考值 */ adc_load = BspLoad_GetNtc(); /* 采集负载电流值 */ if(adc_load > adc_zero) { /* 计算实际负载电流:ADC差值/4096 * 3.3V基准 / 0.132采样电阻 */ temp = (((adc_load - adc_zero)/4096)*3.3)/0.132; } else { temp = 0; } return temp; } /** * @brief 充电初始化 * @note 初始化BSP充电模块,设置初始状态为空闲, * 电流参考 = PRE_IREF,目标电压 = VBAT_TARGET (29.4V) */ void ChargeInit(void) { BspCharge_Init(); /* BSP充电模块初始化 */ fsbb_status.charge_state = CHARGE_STATE_STANDY; } /** * @brief 启动充电 * @note 使能PWM输出,打开充电MOS引脚 */ void Charge_Start(void) { BspCharge_EnablePwmOutput(); /* 使能充电输出 */ BspCharge_TurnOnMosfet(); /* 打开充电MOS引脚 */ } /** * @brief 停止充电 * @note 关闭充电输出,关闭充电MOS引脚 */ void Charge_Stop(void) { BspCharge_DisablePwmOutput(); /* 关闭充电输出 */ BspCharge_TurnOffMosfet(); /* 关闭充电MOS引脚 */ } /** * @brief 设置充电模式 * @param mode 充电模式状态值 * @return 无 */ void ChargeSetMode(ChargeState_t mode) { fsbb_status.charge_state = mode; } /** * @brief 获取充电状态 * @param 无 * @return 当前充电状态 */ uint8_t ChargeGetState(void) { return fsbb_status.charge_state ; } extern PI_t voltagePI, currentPI; /** * @brief PV电源输入控制(带滞回) * @details 根据PV电压自动控制PV电源输入开关: * - Vpv > VIN_ENABLE_VOL + 4000mV (16V) 时打开 * - Vpv < VIN_ENABLE_VOL (12V) 时关闭 * 4000mV 滞回防止光伏波动导致频繁开关 */ static void PvInputEnableWithHysteresis(void) { if (g_powerStatus.vpv > (VIN_ENABLE_VOL + 4000)) { gpio_bit_write(GPIOC, GPIO_PIN_12, RESET); /* 打开PV电源输入 */ } else if (g_powerStatus.vpv < VIN_ENABLE_VOL) { gpio_bit_write(GPIOC, GPIO_PIN_12, SET); /* 关闭PV电源输入 */ } } /** * @brief 输入源选择(DC优先,PV备用) * @details 优先使用DC电源计算VIN,DC电压不足时自动切换为PV供电 */ static void SelectInputSource(void) { if (g_powerStatus.vdc > VIN_ENABLE_VOL) { g_powerStatus.vin = g_powerStatus.vdc; g_powerStatus.input_source = INPUT_SOURCE_DC; } else { g_powerStatus.vin = g_powerStatus.vpv; g_powerStatus.input_source = INPUT_SOURCE_PV; } } /** * @brief 电池低温加热控制(带滞回) * @details 通过NTC检测电池温度,自动控制加热: * - Temp < 5°C → 打开加热 * - Temp > 8°C → 关闭加热 * 3°C 滞回防止频繁开关 */ static void BatteryHeaterEnableWithHysteresis(void) { if (g_powerStatus.bat_temp < 5.0f) { gpio_bit_write(GPIOC, GPIO_PIN_8, SET); /* 打开加热 */ } else if (g_powerStatus.bat_temp > 8.0f) { gpio_bit_write(GPIOC, GPIO_PIN_8, RESET); /* 关闭加热 */ } } void FilterParamAdd(void) { if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_V_DC].num ) { FilterBuffer[FILTER_V_DC].num = 0; } FilterBuffer[FILTER_V_DC].buffer[FilterBuffer[FILTER_V_DC].num] = BspCharge_GetVdc(); FilterBuffer[FILTER_V_DC].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_V_PV].num ) { FilterBuffer[FILTER_V_PV].num = 0; } FilterBuffer[FILTER_V_PV].buffer[FilterBuffer[FILTER_V_PV].num] = BspCharge_GetVpv(); FilterBuffer[FILTER_V_PV].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_V_BAT].num ) { FilterBuffer[FILTER_V_BAT].num = 0; } FilterBuffer[FILTER_V_BAT].buffer[FilterBuffer[FILTER_V_BAT].num] = BspCharge_GetVbat(); FilterBuffer[FILTER_V_BAT].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_T_BAT].num ) { FilterBuffer[FILTER_T_BAT].num = 0; } FilterBuffer[FILTER_T_BAT].buffer[FilterBuffer[FILTER_T_BAT].num] = g_powerStatus.bat_temp; FilterBuffer[FILTER_T_BAT].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_T_PCB].num ) { FilterBuffer[FILTER_T_PCB].num = 0; } FilterBuffer[FILTER_T_PCB].buffer[FilterBuffer[FILTER_T_PCB].num] = g_powerStatus.pcb_temp; FilterBuffer[FILTER_T_PCB].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_I_BAT].num ) { FilterBuffer[FILTER_I_BAT].num = 0; } FilterBuffer[FILTER_I_BAT].buffer[FilterBuffer[FILTER_I_BAT].num] = BspCharge_GetIout(); FilterBuffer[FILTER_I_BAT].num++; if( FILTER_BUFFER_MAX <= FilterBuffer[FILTER_I_LOAD].num ) { FilterBuffer[FILTER_I_LOAD].num = 0; } FilterBuffer[FILTER_I_LOAD].buffer[FilterBuffer[FILTER_I_LOAD].num] = Load_GetI(); FilterBuffer[FILTER_I_LOAD].num++; } /* */ void chargeRunStopMangement(void) { static uint8_t last_charge_state = CHARGE_STATE_STANDY; /* 根据状态机变化控制充电硬件启停 */ if (fsbb_status.charge_state != CHARGE_STATE_STANDY && last_charge_state == CHARGE_STATE_STANDY) { Charge_Start(); /* 从待机进入活跃充电状态:启动硬件 */ } else if (fsbb_status.charge_state == CHARGE_STATE_STANDY && last_charge_state != CHARGE_STATE_STANDY) { Charge_Stop(); /* 从活跃状态回到待机:关闭硬件 */ } last_charge_state = fsbb_status.charge_state; } /** * @brief 充电任务主函数 (uC/OS-III 任务, 优先级6) * @note 初始化LED + 启动充电后, 以 TASK_REFRESH_PERIOD_MS (1ms) 周期运行 */ static void Task_FSBB_Charge(void *p_arg) { OS_ERR err; ChargeSetMode(CHARGE_STATE_STANDY); /* 设置充电模式为使能 */ Charge_Stop(); BatLed_Init(); /* 电池LED初始化(常亮),状态机后续自动切换 */ Vaux_SetSource(VAUX_BATTERY_DISABLE); for(uint8_t i = 0; i < 20; i++) /* 启动时LED闪烁指示 */ { OSTimeDly(50, OS_OPT_TIME_DLY, &err); BAT_LED_OFF; OSTimeDly(50, OS_OPT_TIME_DLY, &err); BAT_LED_ON; } /* LED闪烁完成后,显式启动充电状态机 */ ChargeSetMode(CHARGE_STATE_START); /* 充电硬件启动由状态机控制 */ while(1) { // printf("charge_state == %d\n", fsbb_status.charge_state); printf("\r\n"); // printf("temp,%d\n", g_powerStatus.pcb_temp); printf("\r\n"); // printf("vin,%.1f\n", g_powerStatus.vin); printf("\r\n"); // printf("VoltageBat,%.2f\n", g_powerStatus.bat); printf("\r\n"); // printf("convert_mode == %d\n", fsbb_status.convert_mode); printf("\r\n"); printf("I:%d,%.0f\n", g_powerStatus.charge_current_ref, /* 电流参考值 (mA) */ g_powerStatus.iout); BspBoard_ReadTemperature((signed short *)&g_powerStatus.pcb_temp); GetBatteryTemp((float *)&g_powerStatus.bat_temp); FilterParamAdd(); chargeRunStopMangement(); SelectInputSource(); PvInputEnableWithHysteresis(); BatteryHeaterEnableWithHysteresis(); BatLed_UpdateChargeIndicator(); /* 电池充电状态LED指示 */ OSTimeDly(TASK_REFRESH_PERIOD_10MS, OS_OPT_TIME_DLY, &err); /* 任务延时 1ms */ } } void TIMER7_UP_IRQHandler(void) { if (timer_interrupt_flag_get(TIMER7, TIMER_INT_FLAG_UP) == SET) { timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP); adc_software_trigger_enable(ADC_BOOST, ADC_REGULAR_CHANNEL); /* --- 系统节拍: 1Hz --- */ if (++t7_div.sys >= T7_DIV_SYS) { t7_div.sys = 0; g_system_tick++; } /* --- 电压采样: 100Hz --- */ if (++t7_div.volt >= T7_DIV_VOLT) { t7_div.volt = 0; g_powerStatus.bat = BspCharge_GetVbat(); /* 获取电池电压 */ g_powerStatus.vout = BspCharge_GetVout(); /* 获取输出电压 */ g_powerStatus.vdc = BspCharge_GetVdc(); g_powerStatus.vpv = BspCharge_GetVpv(); charge_step_machine(); Charge_Voltage_Control(); fsbb_select_mode(g_powerStatus.vin, g_powerStatus.bat); fsbb_charge_protection_check(); } /* --- 电流采样 + 动态充电: 1kHz --- */ if (++t7_div.curr >= T7_DIV_CURR) { t7_div.curr = 0; g_powerStatus.iout = BspCharge_GetIout(); /* 获取输出电流(内部含vin>10V保护) */ g_powerStatus.check_imos = BspCharge_GetImos();//获取mosfet电流(内部含vin>10V保护) softstart_trigger_check(); current_control_loop(); } } }