BMS STM32 V4.0.0.0

This commit is contained in:
2026-08-25 17:30:40 +08:00
commit 3ae7bcb054
313 changed files with 115734 additions and 0 deletions
+269
View File
@@ -0,0 +1,269 @@
/**
******************************************************************************
* @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_CH1PA8)的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模式1CNT<CCR时输出高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能通道输出
TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0CCR值)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 有效电平为高
TIM_OC4Init(TIM4, &TIM_OCInitStructure); // 初始化通道4
// 使能预装载寄存器(保证参数修改生效)
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); // 通道4预装载使能
TIM_ARRPreloadConfig(TIM4, ENABLE); // TIM4自动重装预装载使能
// 开启主输出(否则无PWM波形)
TIM_CtrlPWMOutputs(TIM4, ENABLE);
// 启动TIM4
TIM_Cmd(TIM4, ENABLE);
}
/*************************************************************************************************
* 函数名: PWM_Set_Duty_Percent
* 参 数: 无
* 返回值: 无
* 描 述:
*************************************************************************************************/
void PWM_Set_Duty_Percent(float duty_per)
{
uint16_t ccr_val;
//限制百分比范围
if (duty_per < 0.00f) duty_per = 0.00f;
if (duty_per > 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);
}