/** ****************************************************************************** * @file pwm.c * @author * @version * @date * @brief ****************************************************************************** * @attention * * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "global.h" //GPIOA #define PIN_CHG_LIMIT_PON GPIO_Pin_8 //限流 电源控制管脚 //GPIOB #define PIN_CHG_LIMIT_PWM GPIO_Pin_9 //限流 电流值控制 #define BIAS_VOLTAGE (200 * bmsMem.ucCellNum/16) //基准偏差电压值,单位1mV #define BASE_VOLTAGE (60000 * bmsMem.ucCellNum/16) //基准电压值,单位1mV #define BASE_CURRENT 10000 //基准/目标电流值10A,单位1mA #define MAX_DUTY 99.00f //最大占空比(百分比) #define MIN_DUTY 50.00f //最小占空比(百分比) #define PWM_ARR 3599 //定时器自动重装值(对应0~100%占空比) #define PWM_PSC 0 //预分频系数(PWM频率=72M/(0+1)/(3599+1) = 20kHz) uint8_t curLimit_ctrlFlag; //执行限流开/关的标志 0:关限流 1:开限流 float base_duty; //初始电流值偏小最好,对应假设充电器电压是最大值60V float old_duty; //有效的上一次调整的占空比 float duty_cycle; //实时基准占空比 //开限流 void CHG_LIMIT_On(void) { if(curLimit_ctrlFlag != 1) { curLimit_ctrlFlag = 1; delay_ms(10); //关充电MOS后,再延时开限流 //计算初始占空比 base_duty = (float)(bmsMem.packVoltage + BIAS_VOLTAGE) / BASE_VOLTAGE * 100; base_duty = (int)(base_duty * 100 + 0.5) / 100.0f; if(base_duty < MIN_DUTY) { base_duty = MIN_DUTY; } else if(base_duty > MAX_DUTY) { base_duty = MAX_DUTY; } //限流功能开启 GPIO_SetBits(GPIOA, PIN_CHG_LIMIT_PON); //PWM占空比为默认值 duty_cycle = base_duty; old_duty = duty_cycle; PWM_Set_Duty_Percent(duty_cycle); } } //关限流 void CHG_LIMIT_Off(void) { if(curLimit_ctrlFlag != 0) { curLimit_ctrlFlag = 0; //限流功能关闭 GPIO_ResetBits(GPIOA, PIN_CHG_LIMIT_PON); //PWM占空比为0% duty_cycle = 0.00f; old_duty = duty_cycle; PWM_Set_Duty_Percent(duty_cycle); delay_ms(10); //关限流后,延时开充电MOS } } //限流控制脚和PWM脚的初始化 void CHG_LIMIT_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //限流充电控制 GPIO_InitStructure.GPIO_Pin = PIN_CHG_LIMIT_PON; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA, PIN_CHG_LIMIT_PON); //限流控制脚,默认关闭状态 //限流PWM波初始化 TIM4_PWM_Init(PWM_ARR, PWM_PSC); } /************************************************************************** ** 初始化TIM4_CH1(PA8)的PWM输出 ** arr: 定时器自动重装值 ** psc: 定时器预分频系数 ***************************************************************************/ void TIM4_PWM_Init(uint16_t arr, uint16_t psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 开启外设时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // TIM4+GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); // 复用功能时钟(必要) // 配置PB9为复用推挽输出(PWM必须用复用模式) GPIO_InitStructure.GPIO_Pin = PIN_CHG_LIMIT_PWM; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // 配置TIM4时基参数 TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装值 TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割(无分频) TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 配置TIM4_CH1的PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1:CNT 100.00f) duty_per = 100.00f; //转换为定时器CCR值(四舍五入,提升精度) ccr_val = (u16)(duty_per / 100.00f * PWM_ARR + 0.50f); //设置CCR值 TIM_SetCompare4(TIM4, ccr_val); } /************************************************************************************************* * 函数名: CHG_LIMIT_PWM_Adjust * 参 数: 无 * 返回值: 无 * 描 述: pwm限流,根据电流来计算占空比,53.4V 10A时占空比为93.0 *************************************************************************************************/ void CHG_LIMIT_PWM_Adjust(void) { int16_t cur_diff = bmsMem.packCurrent - BASE_CURRENT; //根据电流差值调整占空比,变化越大电流波动越大 if(cur_diff >= 9000) { //电流超过目标9A以上,快速减小占空比(步长5.00,因为大电流有风险) duty_cycle -= 5.00f; } else if(cur_diff >= 5000) { //电流超过目标5A以上,快速减小占空比(步长1.50,因为大电流有风险) duty_cycle -= 1.50f; } else if(cur_diff >= 2000) { //电流超过目标2A以上,中速减小占空比(步长0.30) duty_cycle -= 0.30f; } else if(cur_diff >= 1000) { //电流超过目标1A以上,中速减小占空比(步长0.20) duty_cycle -= 0.20f; } else if(cur_diff >= 500) { //电流超过目标0.5A以上,慢速减小占空比(步长0.05) duty_cycle -= 0.05f; } else if(cur_diff >= 100) { //电流超过目标0.5A以上,慢速减小占空比(步长0.01) duty_cycle -= 0.01f; } else if(cur_diff <= -9000) { //电流低于目标9A以上,快速增大占空比(步长2.00) duty_cycle += 2.00f; } else if(cur_diff <= -5000) { //电流低于目标5A以上,快速增大占空比(步长1.00) duty_cycle += 1.00f; } else if(cur_diff <= -2000) { //电流低于目标3A以上,中速增大占空比(步长0.30) duty_cycle += 0.30f; } else if(cur_diff <= -1000) { //电流低于目标1A以上,中速增大占空比(步长0.20) duty_cycle += 0.20f; } else if(cur_diff <= -500) { //电流低于目标0.5A以上,慢速增大占空比(步长0.05) duty_cycle += 0.05f; } else if(cur_diff <= -100) { //电流低于目标0.5A以上,慢速增大占空比(步长0.01) duty_cycle += 0.01f; } else { //电流差在±500mA(0.5A)以内,占空比保持不变 duty_cycle = old_duty; } //限制占空比范围 if(duty_cycle < MIN_DUTY) { duty_cycle = MIN_DUTY; } else if(duty_cycle > MAX_DUTY) { duty_cycle = MAX_DUTY; } old_duty = duty_cycle; PWM_Set_Duty_Percent(duty_cycle); }