资料下载:
1、实现功能
以12-48V直流电作为输入,通过BUCK-BOOST电路实现0-48V的可调输出电压,最大电流5A。控制方面,采用STM32F334作为控制器,利用内部ADC实现电流和电压检测,GS8552-SR输出模拟信号以控制BUCK-BOOST电路,并利用OLED液晶显示当前输出电压和工作状态。在功能上,用户可通过按键和调节输出电压,每次调节步进为0.1V,并且具有具备多种保护功能,可以在电源板出现异常情况时切断输出。
可增加的功能:
主要元器件:
目录
2、硬件介绍
1、硬件拓扑介绍
双向BUCK-BOOST 电路拓扑是由同步 BUCK 电路和同步 BOOST 电路级
联而成。传统的BUCK电路和BOOST电路中由二极管续流,但在低压大电流场
合,由于二极管上存在导通压降,会引起较大的导通损耗。利用MOS管代替传
统的BUCK电路和BOOST电路中的续流二极管,由于MOS管开通时的管压降
相对较低,能够显著降低电路中半导体的导通损耗,这种方式称为同步整流。
硬件拓扑如图所示:
以左侧为输入,右侧为输出为例子,分析电路工作原理。当Q4常闭,Q3常
开,Q1与Q2以特定占空比互补导通,则电路工作于BUCK模式,如图1.2所
示;当 Q1 常闭,Q2 常开,Q3 和 Q4 以特定占空比互补导通,则电路工作于
BOOST 模式,如图1.3所示;当Q1和Q2,Q3和Q4均特定占空比互补导通,
则电路工作于BUCK-BOOST模式(MIX混合模式)
2、实物图
3、实物演示视频
3、代码
1、PID代码
STM32代码采用C语言,HAL库编写,软件是keil5,使用PID算法控制输出电压,200Khz采样率降低纹波,ADC+DMA+定时器触发采样输出输出电压和电流数据。
//环路的参数buck输出-恒压-PID型补偿器
#define BUCKPIDb0 5203 //Q8
#define BUCKPIDb1 -10246 //Q8
#define BUCKPIDb2 5044 //Q8
//环路的参数BOOST输出-恒压-PID型补偿器
#define BOOSTPIDb0 8860 //Q8
#define BOOSTPIDb1 -17445 //Q8
#define BOOSTPIDb2 8588 //Q8
CCMRAM void BuckBoostVLoopCtlPID(void)
{
int32_t VoutTemp=0;//输出电压矫正后
//输出电压矫正
VoutTemp = ((uint32_t )ADC1_RESULT[2]*CAL_VOUT_K>>12)+CAL_VOUT_B;
//计算电压误差量,当参考电压大于输出电压,占空比增加,输出量增加
VErr0= CtrValue.Voref - VoutTemp;
//当模式切换时,认为降低占空比,确保模式切换不过冲
//BBModeChange为模式切换为,不同模式切换时,该位会被置1
if(DF.BBModeChange)
{
u1 = 0;
DF.BBModeChange =0;
}
//判断工作模式,BUCK,BOOST,BUCK-BOOST
switch(DF.BBFlag)
{
case NA ://初始阶段
{
VErr0=0;
VErr1=0;
VErr2=0;
u0 = 0;
u1 = 0;
break;
}
case Buck: //BUCK模式
{
//调用PID环路计算公式
u0 = u1 + VErr0*BUCKPIDb0 + VErr1*BUCKPIDb1 + VErr2*BUCKPIDb2;
//历史数据幅值
VErr2 = VErr1;
VErr1 = VErr0;
u1 = u0;
//环路输出赋值,u0右移8位为BUCKPIDb0-2为人为放大Q8倍的数字量
CtrValue.BuckDuty= u0>>8;
CtrValue.BoostDuty=MIN_BOOST_DUTY1;//BOOST上管固定占空比93%,下管7%
//环路输出最大最小占空比限制
if(CtrValue.BuckDuty > CtrValue.BUCKMaxDuty)
CtrValue.BuckDuty = CtrValue.BUCKMaxDuty;
if(CtrValue.BuckDuty < MIN_BUKC_DUTY)
CtrValue.BuckDuty = MIN_BUKC_DUTY;
break;
}
case Boost://Boost模式
{
//调用PID环路计算公式(参照PID环路计算文档)
u0 = u1 + VErr0*BOOSTPIDb0 + VErr1*BOOSTPIDb1 + VErr2*BOOSTPIDb2;
//历史数据幅值
VErr2 = VErr1;
VErr1 = VErr0;
u1 = u0;
//环路输出赋值,u0右移8位为BUCKPIDb0-2为人为放大Q8倍的数字量
CtrValue.BuckDuty = MAX_BUCK_DUTY;//否则固定占空比93%
CtrValue.BoostDuty = u0>>8;
//环路输出最大最小占空比限制
if(CtrValue.BoostDuty > CtrValue.BoostMaxDuty)
CtrValue.BoostDuty = CtrValue.BoostMaxDuty;
if(CtrValue.BoostDuty < MIN_BOOST_DUTY)
CtrValue.BoostDuty = MIN_BOOST_DUTY;
break;
}
case Mix://Mix模式
{
//调用PID环路计算公式
u0 = u1 + VErr0*BOOSTPIDb0 + VErr1*BOOSTPIDb1 + VErr2*BOOSTPIDb2;
//历史数据幅值
VErr2 = VErr1;
VErr1 = VErr0;
u1 = u0;
//环路输出赋值,u0右移8位为BUCKPIDb0-2为人为放大Q8倍的数字量
CtrValue.BuckDuty = MAX_BUCK_DUTY1;//否则固定占空比80%
CtrValue.BoostDuty = u0>>8;
//环路输出最大最小占空比限制
if(CtrValue.BoostDuty > CtrValue.BoostMaxDuty)
CtrValue.BoostDuty = CtrValue.BoostMaxDuty;
if(CtrValue.BoostDuty < MIN_BOOST_DUTY)
CtrValue.BoostDuty = MIN_BOOST_DUTY;
break;
}
}
//PWMENFlag是PWM开启标志位,当该位为0时,buck的占空比为0,无输出;
if(DF.PWMENFlag==0)
CtrValue.BuckDuty = MIN_BUKC_DUTY;
//更新对应寄存器
HRTIM1->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_A].CMP1xR = CtrValue.BuckDuty * PERIOD>>12; //buck占空比
HRTIM1->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_A].CMP3xR = HRTIM1->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_A].CMP1xR>>1; //ADC触发采样点
HRTIM1->sTimerxRegs[HRTIM_TIMERINDEX_TIMER_B].CMP1xR = PERIOD - (CtrValue.BoostDuty * PERIOD>>12);//Boost占空比
}
2、输入输出保护代码
以下为输出模式,输出过压、过流,温度保护。以及输出过压、过流保护实现代码。
程序根据输入输出电压的关系判断模块运行在BUCK模式,BOOST模式还是MIX模式(BUCK-BOOST模式)。 模块上电初始化后默认模式状态为NA,当输出电压参考量小于0.8倍的输入电压时,进入BUCK模式;当输出电压参考量大于1.2倍的输入电压时,进入BOOST 模式;否则输出电压参考量在0.8倍和1.2倍输入电压之间,进入MIX
模式化;
当模块为BUCK模式运行时,输出电压参考量大于1.2倍的输入电压时,进入BOOST模式;为了保证模块运行模式在不同模式之间切换频繁,设置模式切换的滞环效果,模块处于BUCK模式下,当输出电压参考量大于0.85倍的输入
电压时,进入MIX模式。
当模块为BOOST模式运行时,输出电压参考量小于0.8倍的输入电压时,进入 BUCK 模式;为了保证模块运行模式在不同模式之间切换频繁,设置模式切换的滞环效果,模块处于BOOST模式下,当输出电压参考量小于1.15倍的输
入电压时,进入MIX模式。
当模块为MIX模式运行时,输出电压参考量小于0.8倍的输入电压时,进入BUCK模式;当输出电压参考量大于1.2倍的输入电压时,进入BOOST模式。 由于不同工作模式状态下,环路的控制方式不同,当运行模式发生变换时,
需要对环路运算过程变量复位。模式判断函数定义PreBBFlag保存当前模式,当执行完模式判断后,若PreBBFlag保存的模式和新模式不同,则认为模块运行模式发生变化,模式变化标志位DF.BBModeChange置1。
1、初始化状态至空闲状态:上电程序初始化后跳转。
2、空闲状态至软启动状态:等待3S后自动跳转。
3、软启动状态至正常运行状态:正常启动结束后。
4、软启动状态至故障状态:启动过程中发生故障或保护。
5、正常运行状态至故障状态:正常运行过程中发生故障或保护。
6、故障状态至空闲状态:故障消除后自动跳转,模块自动恢复启动。
#include "function.h"//功能函数头文件
#include "CtlLoop.h"//控制环路头文件
struct _ADI SADC={0,0,2048,0,0,0,0,2048,0,0,0,0};//输入输出参数采样值和平均值
struct _Ctr_value CtrValue={0,0,0,MIN_BUKC_DUTY,0,0,0};//控制参数
struct _FLAG DF={0,0,0,0,0,0,0,0};//控制标志位
uint16_t ADC1_RESULT[4]={0,0,0,0};//ADC采样外设到内存的DMA数据保存寄存器
//软启动状态标志位
SState_M STState = SSInit ;
//OLED刷新计数 5mS计数一次,在5mS中断里累加
uint16_t OLEDShowCnt=0;
/*
** ===================================================================
** Funtion Name : void ADCSample(void)
** Description : 采样输出电压、输出电流、输入电压、输入电流
** Parameters :
** Returns :
** ===================================================================
*/
CCMRAM void ADCSample(void)
{
//输入输出采样参数求和,用以计算平均值
static uint32_t VinAvgSum=0,IinAvgSum=0,VoutAvgSum=0,IoutAvgSum=0;
//从DMA缓冲器中获取数据 Q15,并对其进行线性矫正-采用线性矫正
SADC.Vin = ((uint32_t )ADC1_RESULT[0]*CAL_VIN_K>>12)+CAL_VIN_B;
SADC.Iin = (((int32_t )ADC1_RESULT[1]-SADC.IinOffset)*CAL_IIN_K>>12)+CAL_IIN_B;
SADC.Vout = ((uint32_t )ADC1_RESULT[2]*CAL_VOUT_K>>12)+CAL_VOUT_B;
SADC.Iout = (((int32_t )ADC1_RESULT[3] - SADC.IoutOffset)*CAL_IOUT_K>>12)+CAL_IOUT_B;
if(SADC.Vin <100 )//采样有零偏离,采样值很小时,直接为0
SADC.Vin = 0;
if(SADC.Iin <0 )//对电流采样限制,当采样值小于SADC.IinOffset时
SADC.Iin =0;
if(SADC.Vout <100 )
SADC.Vout = 0;
if(SADC.Iout <0 )
SADC.Iout = 0;
//计算各个采样值的平均值-滑动平均方式
VinAvgSum = VinAvgSum + SADC.Vin -(VinAvgSum>>2);//求和,新增入一个新的采样值,同时减去之前的平均值。
SADC.VinAvg = VinAvgSum>>2;//求平均
IinAvgSum = IinAvgSum + SADC.Iin -(IinAvgSum>>2);
SADC.IinAvg = IinAvgSum >>2;
VoutAvgSum = VoutAvgSum + SADC.Vout -(VoutAvgSum>>2);
SADC.VoutAvg = VoutAvgSum>>2;
IoutAvgSum = IoutAvgSum + SADC.Iout -(IoutAvgSum>>2);
SADC.IoutAvg = IoutAvgSum>>2;
}
/** ===================================================================
** Funtion Name :void StateM(void)
** Description : 状态机函数,在5ms中断中运行,5ms运行一次
** 初始化状态
** 等外启动状态
** 启动状态
** 运行状态
** 故障状态
** Parameters :
** Returns :
** ===================================================================*/
void StateM(void)
{
//判断状态类型
switch(DF.SMFlag)
{
//初始化状态
case Init :StateMInit();
break;
//等待状态
case Wait :StateMWait();
break;
//软启动状态
case Rise :StateMRise();
break;
//运行状态
case Run :StateMRun();
break;
//故障状态
case Err :StateMErr();
break;
}
}
/** ===================================================================
** Funtion Name :void StateMInit(void)
** Description : 初始化状态函数,参数初始化
** Parameters :
** Returns :
** ===================================================================*/
void StateMInit(void)
{
//相关参数初始化
ValInit();
//状态机跳转至等待软启状态
DF.SMFlag = Wait;
}
/** ===================================================================
** Funtion Name :void StateMWait(void)
** Description : 等待状态机,等待1S后无故障则软启
** Parameters :
** Returns :
** ===================================================================*/
void StateMWait(void)
{
//计数器定义
static uint16_t CntS = 0;
static uint32_t IinSum=0,IoutSum=0;
//关PWM
DF.PWMENFlag=0;
//计数器累加
CntS ++;
//等待*S,采样输入和输出电流偏置好后, 且无故障情况,切按键按下,启动,则进入启动状态
if(CntS>256)
{
CntS=256;
HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //开启PWM输出和PWM计时器
if((DF.ErrFlag==F_NOERR)&&(DF.KeyFlag1==1))
{
//计数器清0
CntS=0;
IinSum=0;
IoutSum=0;
//状态标志位跳转至等待状态
DF.SMFlag = Rise;
//软启动子状态跳转至初始化状态
STState = SSInit;
}
}
else//进行输入和输出电流1.65V偏置求平均
{
//输入输出电流偏置求和
IinSum += ADC1_RESULT[1];
IoutSum += ADC1_RESULT[3];
//256次数
if(CntS==256)
{
//求平均
SADC.IinOffset = IinSum >>8;
SADC.IoutOffset = IoutSum >>8;
}
}
}
/*
** ===================================================================
** Funtion Name : void StateMRise(void)
** Description :软启阶段
** 软启初始化
** 软启等待
** 开始软启
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MAX_SSCNT 20//等待100ms
void StateMRise(void)
{
//计时器
static uint16_t Cnt = 0;
//最大占空比限制计数器
static uint16_t BUCKMaxDutyCnt=0,BoostMaxDutyCnt=0;
//判断软启状态
switch(STState)
{
//初始化状态
case SSInit:
{
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//软启中将运行限制占空比启动,从最小占空比开始启动
CtrValue.BUCKMaxDuty = MIN_BUKC_DUTY;
CtrValue.BoostMaxDuty = MIN_BOOST_DUTY;
//环路计算变量初始化
VErr0=0;
VErr1=0;
VErr2=0;
u0 = 0;
u1 = 0;
//跳转至软启等待状态
STState = SSWait;
break;
}
//等待软启动状态
case SSWait:
{
//计数器累加
Cnt++;
//等待100ms
if(Cnt> MAX_SSCNT)
{
//计数器清0
Cnt = 0;
//限制启动占空比
CtrValue.BuckDuty = MIN_BUKC_DUTY;
CtrValue.BUCKMaxDuty= MIN_BUKC_DUTY;
CtrValue.BoostDuty = MIN_BOOST_DUTY;
CtrValue.BoostMaxDuty = MIN_BOOST_DUTY;
//环路计算变量初始化
VErr0=0;
VErr1=0;
VErr2=0;
u0 = 0;
u1 = 0;
//CtrValue.Voref输出参考电压从一半开始启动,避免过冲,然后缓慢上升
CtrValue.Voref = CtrValue.Voref >>1;
STState = SSRun; //跳转至软启状态
}
break;
}
//软启动状态
case SSRun:
{
if(DF.PWMENFlag==0)//正式发波前环路变量清0
{
//环路计算变量初始化
VErr0=0;
VErr1=0;
VErr2=0;
u0 = 0;
u1 = 0;
HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //开启PWM输出和PWM计时器
HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //开启PWM输出和PWM计时器
}
//发波标志位置位
DF.PWMENFlag=1;
//最大占空比限制逐渐增加
BUCKMaxDutyCnt++;
BoostMaxDutyCnt++;
//最大占空比限制累加
CtrValue.BUCKMaxDuty = CtrValue.BUCKMaxDuty + BUCKMaxDutyCnt*5;
CtrValue.BoostMaxDuty = CtrValue.BoostMaxDuty + BoostMaxDutyCnt*5;
//累加到最大值
if(CtrValue.BUCKMaxDuty > MAX_BUCK_DUTY)
CtrValue.BUCKMaxDuty = MAX_BUCK_DUTY ;
if(CtrValue.BoostMaxDuty > MAX_BOOST_DUTY)
CtrValue.BoostMaxDuty = MAX_BOOST_DUTY ;
if((CtrValue.BUCKMaxDuty==MAX_BUCK_DUTY)&&(CtrValue.BoostMaxDuty==MAX_BOOST_DUTY))
{
//状态机跳转至运行状态
DF.SMFlag = Run;
//软启动子状态跳转至初始化状态
STState = SSInit;
}
break;
}
default:
break;
}
}
/*
** ===================================================================
** Funtion Name :void StateMRun(void)
** Description :正常运行,主处理函数在中断中运行
** Parameters : none
** Returns : none
** ===================================================================
*/
void StateMRun(void)
{
}
/*
** ===================================================================
** Funtion Name :void StateMErr(void)
** Description :故障状态
** Parameters : none
** Returns : none
** ===================================================================
*/
void StateMErr(void)
{
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//若故障消除跳转至等待重新软启
if(DF.ErrFlag==F_NOERR)
DF.SMFlag = Wait;
}
/** ===================================================================
** Funtion Name :void ValInit(void)
** Description : 相关参数初始化函数
** Parameters :
** Returns :
** ===================================================================*/
void ValInit(void)
{
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//清除故障标志位
DF.ErrFlag=0;
//初始化电压参考量
CtrValue.Voref=0;
//限制占空比
CtrValue.BuckDuty = MIN_BUKC_DUTY;
CtrValue.BUCKMaxDuty= MIN_BUKC_DUTY;
CtrValue.BoostDuty = MIN_BOOST_DUTY;
CtrValue.BoostMaxDuty = MIN_BOOST_DUTY;
//环路计算变量初始化
VErr0=0;
VErr1=0;
VErr2=0;
u0 = 0;
u1 = 0;
}
/** ===================================================================
** Funtion Name :void VrefGet(void)
** Description : 从滑动变阻器值获取输出电压参考值,调整滑动电位器,CtrValue.Voref变换,当电压参考值变化时,缓慢增加
** Parameters :
** Returns :
** ===================================================================*/
#define MAX_VREF 2921//最大输出参考电压48V 0.5V的余量 48.5V/68V*Q12 Vsmax=68V
#define MIN_VREF 60//最低输出电压参考值5V 0.5V的余量 4.5V/68V*Q12
#define VREF_K 5//递增或递减步长
void VrefGet(void)
{
// //电压参考值中间变量
// int32_t VTemp = 0;
// //滑动平均求和中间变量
// static int32_t VadjSum = 0;
// //获取ADC采样值-读滑动电位器上的电压
// SADC.Vadj = HAL_ADC_GetValue(&hadc2);
//对采样值滑动求平均
// VadjSum = VadjSum + SADC.Vadj -(VadjSum>>8);
// SADC.VadjAvg = VadjSum>>8;
//
// //参考电压 = MIN_VREF+滑动变阻器采样值,MIN_VREF为最低输出电压。
// VTemp = MIN_VREF + SADC.Vadj;
//
// //缓慢递增或缓慢递减电压参考值
// if( VTemp> ( CtrValue.Voref + VREF_K))
// CtrValue.Voref = CtrValue.Voref + VREF_K;
// else if( VTemp < ( CtrValue.Voref - VREF_K ))
// CtrValue.Voref =CtrValue.Voref - VREF_K;
// else
// CtrValue.Voref = VTemp ;
// //MIX模式下调压限制-输出电压最大达到输入电压的2倍
// if(CtrValue.Voref >(SADC.VinAvg<<1))//输出限制在输入的2*vin
// CtrValue.Voref =(SADC.VinAvg<<1);
// if( CtrValue.Voref >MAX_VREF )
// CtrValue.Voref =MAX_VREF;
}
/*
** ===================================================================
** Funtion Name :void ShortOff(void)
** Description :短路保护,可以重启10次
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MAX_SHORT_I 1396//短路电流判据
#define MIN_SHORT_V 289//短路电压判据
void ShortOff(void)
{
static int32_t RSCnt = 0;
static uint8_t RSNum =0 ;
//当输出电流大于 *A,且电压小于*V时,可判定为发生短路保护
if((SADC.Iout> MAX_SHORT_I)&&(SADC.Vout <MIN_SHORT_V))
{
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//故障标志位
setRegBits(DF.ErrFlag,F_SW_SHORT);
//跳转至故障状态
DF.SMFlag =Err;
}
//输出短路保护恢复
//当发生输出短路保护,关机后等待4S后清楚故障信息,进入等待状态等待重启
if(getRegBits(DF.ErrFlag,F_SW_SHORT))
{
//等待故障清楚计数器累加
RSCnt++;
//等待2S
if(RSCnt >400)
{
//计数器清零
RSCnt=0;
//短路重启只重启10次,10次后不重启
if(RSNum > 10)
{
//确保不清除故障,不重启
RSNum =11;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
}
else
{
//短路重启计数器累加
RSNum++;
//清除过流保护故障标志位
clrRegBits(DF.ErrFlag,F_SW_SHORT);
}
}
}
}
/*
** ===================================================================
** Funtion Name :void SwOCP(void)
** Description :软件过流保护,可重启
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MAX_OCP_VAL 1117//*A过流保护点
void SwOCP(void)
{
//过流保护判据保持计数器定义
static uint16_t OCPCnt=0;
//故障清楚保持计数器定义
static uint16_t RSCnt=0;
//保留保护重启计数器
static uint16_t RSNum=0;
//当输出电流大于*A,且保持500ms
if((SADC.Iout > MAX_OCP_VAL)&&(DF.SMFlag ==Run))
{
//条件保持计时
OCPCnt++;
//条件保持50ms,则认为过流发生
if(OCPCnt > 10)
{
//计数器清0
OCPCnt = 0;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//故障标志位
setRegBits(DF.ErrFlag,F_SW_IOUT_OCP);
//跳转至故障状态
DF.SMFlag =Err;
}
}
else
//计数器清0
OCPCnt = 0;
//输出过流后恢复
//当发生输出软件过流保护,关机后等待4S后清楚故障信息,进入等待状态等待重启
if(getRegBits(DF.ErrFlag,F_SW_IOUT_OCP))
{
//等待故障清楚计数器累加
RSCnt++;
//等待2S
if(RSCnt > 400)
{
//计数器清零
RSCnt=0;
//过流重启计数器累加
RSNum++;
//过流重启只重启10次,10次后不重启(严重故障)
if(RSNum > 10 )
{
//确保不清除故障,不重启
RSNum =11;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
}
else
{
//清除过流保护故障标志位
clrRegBits(DF.ErrFlag,F_SW_IOUT_OCP);
}
}
}
}
/*
** ===================================================================
** Funtion Name :void SwOVP(void)
** Description :软件输出过压保护,不重启
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MAX_VOUT_OVP_VAL 3180//50V过压保护 (48*110%/68)*Q12
void VoutSwOVP(void)
{
//过压保护判据保持计数器定义
static uint16_t OVPCnt=0;
//当输出电压大于50V,且保持100ms
if (SADC.Vout > MAX_VOUT_OVP_VAL)
{
//条件保持计时
OVPCnt++;
//条件保持10ms
if(OVPCnt > 2)
{
//计时器清零
OVPCnt=0;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//故障标志位
setRegBits(DF.ErrFlag,F_SW_VOUT_OVP);
//跳转至故障状态
DF.SMFlag =Err;
}
}
else
OVPCnt = 0;
}
/*
** ===================================================================
** Funtion Name :void VinSwUVP(void)
** Description :输入软件欠压保护,低压输入保护,可恢复
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MIN_UVP_VAL 686//11.4V欠压保护 (11.4/68 )*Q12
#define MIN_UVP_VAL_RE 795//13.2V欠压保护恢复 (13.2/68)*Q12
void VinSwUVP(void)
{
//过压保护判据保持计数器定义
static uint16_t UVPCnt=0;
static uint16_t RSCnt=0;
//当输出电流小于于11.4V,且保持200ms
if ((SADC.Vin < MIN_UVP_VAL) && (DF.SMFlag != Init ))
{
//条件保持计时
UVPCnt++;
//条件保持10ms
if(UVPCnt > 2)
{
//计时器清零
UVPCnt=0;
RSCnt=0;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//故障标志位
setRegBits(DF.ErrFlag,F_SW_VIN_UVP);
//跳转至故障状态
DF.SMFlag =Err;
}
}
else
UVPCnt = 0;
//输入欠压保护恢复
//当发生输入欠压保护,等待输入电压恢复至正常水平后清楚故障标志位,重启
if(getRegBits(DF.ErrFlag,F_SW_VIN_UVP))
{
if(SADC.Vin > MIN_UVP_VAL_RE)
{
//等待故障清楚计数器累加
RSCnt++;
//等待1S
if(RSCnt > 200)
{
RSCnt=0;
UVPCnt=0;
//清楚故障标志位
clrRegBits(DF.ErrFlag,F_SW_VIN_UVP);
}
}
else
RSCnt=0;
}
else
RSCnt=0;
}
/*
** ===================================================================
** Funtion Name :void VinSwOVP(void)
** Description :软件输入过压保护,不重启
** Parameters : none
** Returns : none
** ===================================================================
*/
#define MAX_VIN_OVP_VAL 3012//50V过压保护 (50/68)*Q12
void VinSwOVP(void)
{
//过压保护判据保持计数器定义
static uint16_t OVPCnt=0;
//当输出电压大于50V,且保持100ms
if (SADC.Vin > MAX_VIN_OVP_VAL )
{
//条件保持计时
OVPCnt++;
//条件保持10ms
if(OVPCnt > 2)
{
//计时器清零
OVPCnt=0;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
//故障标志位
setRegBits(DF.ErrFlag,F_SW_VIN_OVP);
//跳转至故障状态
DF.SMFlag =Err;
}
}
else
OVPCnt = 0;
}
/** ===================================================================
** Funtion Name :void LEDShow(void)
** Description : LED显示函数
** 初始化与等待启动状态,红黄绿全亮
** 启动状态,黄绿亮
** 运行状态,绿灯亮
** 故障状态,红灯亮
** Parameters :
** Returns :
** ===================================================================*/
//输出状态灯宏定义
#define SET_LED_G() HAL_GPIO_WritePin(GPIOB, LED_G_Pin,GPIO_PIN_SET)//绿灯亮
#define SET_LED_Y() HAL_GPIO_WritePin(GPIOB, LED_Y_Pin,GPIO_PIN_SET)//绿灯亮
#define SET_LED_R() HAL_GPIO_WritePin(GPIOB, LED_R_Pin,GPIO_PIN_SET)//绿灯亮
#define CLR_LED_G() HAL_GPIO_WritePin(GPIOB, LED_G_Pin,GPIO_PIN_RESET)//绿灯灭
#define CLR_LED_Y() HAL_GPIO_WritePin(GPIOB, LED_Y_Pin,GPIO_PIN_RESET)//黄灯灭
#define CLR_LED_R() HAL_GPIO_WritePin(GPIOB, LED_R_Pin,GPIO_PIN_RESET)//红灯灭
void LEDShow(void)
{
switch(DF.SMFlag)
{
//初始化状态,红黄绿全亮
case Init :
{
SET_LED_G();
SET_LED_Y();
SET_LED_R();
break;
}
//等待状态,红黄绿全亮
case Wait :
{
SET_LED_G();
SET_LED_Y();
SET_LED_R();
break;
}
//软启动状态,黄绿亮
case Rise :
{
SET_LED_G();
SET_LED_Y();
CLR_LED_R();
break;
}
//运行状态,绿灯亮
case Run :
{
SET_LED_G();
CLR_LED_Y();
CLR_LED_R();
break;
}
//故障状态,红灯亮
case Err :
{
CLR_LED_G();
CLR_LED_Y();
SET_LED_R();
break;
}
}
}
/** ===================================================================
** Funtion Name :void KEYFlag(void)
** Description :两个按键的状态
** 默认状态KEYFlag为0.按下时Flag变1,再次按下Flag变0,依次循环
** 当机器正常运行,或者启动过程中,按下按键后,关闭输出,进入待机状态
** Parameters :
** Returns :
** ===================================================================*/
#define READ_KEY1() HAL_GPIO_ReadPin(GPIOB, KEY_1_Pin)
#define READ_KEY2() HAL_GPIO_ReadPin(GPIOB, KEY_2_Pin)
void KEYFlag(void)
{
//计时器,按键消抖用
static uint16_t KeyDownCnt1=0,KeyDownCnt2=0;
//按键按下
if(READ_KEY1()==0)
{
//计时,按键按下150mS有效
KeyDownCnt1++;
if(KeyDownCnt1 > 30)
{
KeyDownCnt1 = 0;//计时器清零
//按键状态有变化
if(DF.KeyFlag1==0)
DF.KeyFlag1 = 1;
else
DF.KeyFlag1 = 0;
}
}
else
KeyDownCnt1 = 0;//计时器清零
//按键按下
if(READ_KEY2()==0)
{
//计时,按键按??0mS有效
KeyDownCnt2++;
if(KeyDownCnt2 > 30)
{
KeyDownCnt2 = 0;//计时器清零
//按键状态有变化
if(DF.KeyFlag2==0)
DF.KeyFlag2 = 1;
else
DF.KeyFlag2 = 0;
}
}
else
KeyDownCnt2 = 0;//计时器清零
//当机器正常运行,或者启动过程中,按下按键后,关闭输出,进入待机状态
if((DF.KeyFlag1==0)&&((DF.SMFlag==Rise)||(DF.SMFlag==Run)))
{
DF.SMFlag = Wait;
//关闭PWM
DF.PWMENFlag=0;
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //关闭
HAL_HRTIM_WaveformOutputStop(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //关闭
}
}
/** ===================================================================
** Funtion Name :void BBMode(void)
** Description :运行模式判断
** BUCK模式:输出参考电压<0.8倍输入电压
** BOOST模式:输出参考电压>1.2倍输入电压
** MIX模式:1.15倍输入电压>输出参考电压>0.85倍输入电压
** 当进入MIX(buck-boost)模式后,退出到BUCK或者BOOST时需要滞缓,防止在临界点来回振荡
** Parameters :
** Returns :
** ===================================================================*/
void BBMode(void)
{
//上一次模式状态量
uint8_t PreBBFlag=0;
//暂存当前的模式状态量
PreBBFlag = DF.BBFlag;
//判断当前模块的工作模式
switch(DF.BBFlag)
{
//NA-初始化模式
case NA :
{
if(CtrValue.Voref < ((SADC.VinAvg*3277)>>12))//vout<0.8*vin
DF.BBFlag = Buck;//buck mode
else if(CtrValue.Voref > ((SADC.VinAvg*4915)>>12))//vout>1.2*vin
DF.BBFlag = Boost;//boost mode
else
DF.BBFlag = Mix;//buck-boost(MIX) mode
break;
}
//BUCK模式
case Buck :
{
if(CtrValue.Voref > ((SADC.VinAvg*4915)>>12))//vout>1.2*vin
DF.BBFlag = Boost;//boost mode
else if(CtrValue.Voref >((SADC.VinAvg*3482)>>12))//1.2*vin>vout>0.85*vin
DF.BBFlag = Mix;//buck-boost(MIX) mode
break;
}
//Boost模式
case Boost :
{
if(CtrValue.Voref < ((SADC.VinAvg*3277)>>12))//vout<0.8*vin
DF.BBFlag = Buck;//buck mode
else if(CtrValue.Voref < ((SADC.VinAvg*4710)>>12))//0.8*vin<vout<1.15*vin
DF.BBFlag = Mix;//buck-boost(MIX) mode
break;
}
//Mix模式
case Mix :
{
if(CtrValue.Voref < ((SADC.VinAvg*3277)>>12))//vout<0.8*vin
DF.BBFlag = Buck;//buck mode
else if(CtrValue.Voref > ((SADC.VinAvg*4915)>>12))//vout>1.2*vin
DF.BBFlag = Boost;//boost mode
break;
}
}
//当模式发生变换时(上一次和这一次不一样),则标志位置位,标志位用以环路计算复位,保证模式切换过程不会有大的过冲
if(PreBBFlag==DF.BBFlag)
DF.BBModeChange =0;
else
DF.BBModeChange =1;
}
/** ===================================================================
** Funtion Name :void MX_OLED_Init(void)
** Description :OLED初始化函数
** 通用OLED驱动程序
** Parameters :
** Returns :
** ===================================================================*/
void MX_OLED_Init(void)
{
//初始化OLED
OLED_Init();
OLED_CLS();
//以下显示固定的字符
OLED_ShowStr(25,0,"BUCK-BOOST",2);
// OLED_ShowStr(0,2,"State:",2);
OLED_ShowStr(16,2,".",2); OLED_ShowStr(32,2,"V",2);
OLED_ShowStr(88,4,".",2); OLED_ShowStr(112,4,"V",2); OLED_ShowStr(16,4,".",2); OLED_ShowStr(40,4,"V",2);
OLED_ShowStr(88,6,".",2); OLED_ShowStr(112,6,"A",2); OLED_ShowStr(16,6,".",2); OLED_ShowStr(40,6,"A",2);
OLED_ON();
}
/** ===================================================================
** Funtion Name :void OLEDShow(void)
** Description : OLED显示函数
** 显示运行模式-BUCK MODE,BOOST MODE,MIX MODE
** 显示状态:IDEL,RISISING,RUNNING,ERROR
** 显示输出电压:两位小数
** 显示输出电流:两位小数
** Parameters :
** Returns :
** ===================================================================*/
void OLEDShow(void)
{
u8 VOtemp[4]={0,0,0,0};
u8 IOtemp[4]={0,0,0,0};
u8 VItemp[4]={0,0,0,0};
u8 IItemp[4]={0,0,0,0};
u8 VStemp[4]={0,0,0,0};
uint32_t VoutT=0,IoutT=0;
uint32_t VinT=0,IinT=0,VadjT=0;
static uint16_t BBFlagTemp=10,SMFlagTemp=10;
//将采样值转换成实际值,并扩大100倍(显示屏幕带小数点)如果显示输入电压电流,则打开另外注释掉的计算
VoutT = SADC.VoutAvg*6800>>12; //校准 6800*1.015
IoutT = SADC.IoutAvg*1100>>12;
VinT = SADC.VinAvg*6800>>12; //6800*
IinT = SADC.IinAvg*1100>>12;
VadjT = CtrValue.Voref*6800>>12;
//分别保存实际电压和电流的每一位,小数点后两位保留,如果显示输入电压电流,则打开另外注释掉的计算
//输出电压
VOtemp[0] = (u8)(VoutT/1000);
VOtemp[1] = (u8)((VoutT-(uint8_t)VOtemp[0]*1000)/100);
VOtemp[2] = (u8)((VoutT-(uint16_t)VOtemp[0]*1000-(uint16_t)VOtemp[1]*100)/10);
VOtemp[3] = (u8)(VoutT-(uint16_t)VOtemp[0]*1000-(uint16_t)VOtemp[1]*100-(uint16_t)VOtemp[2]*10);
//输入电压
VItemp[0] = (u8)(VinT/1000);
VItemp[1] = (u8)((VinT-(uint8_t)VItemp[0]*1000)/100);
VItemp[2] = (u8)((VinT -(uint16_t)VItemp[0]*1000-(uint16_t)VItemp[1]*100)/10);
VItemp[3] = (u8)(VinT-(uint16_t)VItemp[0]*1000-(uint16_t)VItemp[1]*100-(uint16_t)VItemp[2]*10);
//输出电流
IOtemp[0] = (u8)(IoutT/1000);
IOtemp[1] = (u8)((IoutT-(uint8_t)IOtemp[0]*1000)/100);
IOtemp[2] = (u8)((IoutT-(uint16_t)IOtemp[0]*1000-(uint16_t)IOtemp[1]*100)/10);
IOtemp[3] = (u8)(IoutT-(uint16_t)IOtemp[0]*1000-(uint16_t)IOtemp[1]*100-(uint16_t)IOtemp[2]*10);
//输入电流
IItemp[0] = (u8)(IinT/1000);
IItemp[1] = (u8)((IinT-(uint8_t)IItemp[0]*1000)/100);
IItemp[2] = (u8)((IinT-(uint16_t)IItemp[0]*1000-(uint16_t)IItemp[1]*100)/10);
IItemp[3] = (u8)(IinT-(uint16_t)IItemp[0]*1000-(uint16_t)IItemp[1]*100-(uint16_t)IItemp[2]*10);
//参考电压
//输入电流
// VStemp[0] = (u8)(VadjT/1000);
// VStemp[1] = (u8)((VadjT-(uint8_t)VStemp[0]*1000)/100);
// VStemp[2] = (u8)((VadjT-(uint16_t)VStemp[0]*1000-(uint16_t)VStemp[1]*100)/10);
// VStemp[3] = (u8)(VadjT-(uint16_t)VStemp[0]*1000-(uint16_t)VStemp[1]*100-(uint16_t)VStemp[2]*10);
VStemp[0] = V_Key_Set/100;
VStemp[1] = V_Key_Set/10%10;
VStemp[2] = V_Key_Set%10;
//如果运行模式有变化,则更改屏幕
if(BBFlagTemp!= DF.BBFlag)
{
//暂存标志位
BBFlagTemp = DF.BBFlag;
//显示运行模式
switch(DF.BBFlag)
{
//NA
case NA :
{
OLED_ShowStr(25,0,"MODE:*NA* ",2);
break;
}
//BUCK模式
case Buck :
{
OLED_ShowStr(25,0,"MODE:BUCK ",2);
break;
}
//Boost模式
case Boost :
{
OLED_ShowStr(25,0,"MODE:BOOST",2);
break;
}
//Mix模式
case Mix :
{
OLED_ShowStr(25,0,"MODE:MIX ",2);
break;
}
}
}
//电源工作状态有变换,更新屏幕
if(SMFlagTemp!= DF.SMFlag)
{
SMFlagTemp = DF.SMFlag;
//显示电源工作状态
switch(DF.SMFlag)
{
//初始化状态
case Init :
{
OLED_ShowStr(55,2,"Init ",2);
break;
}
//等待状态
case Wait :
{
OLED_ShowStr(55,2,"Waiting",2);
break;
}
//软启动状态
case Rise :
{
OLED_ShowStr(55,2,"Rising",2);
break;
}
//运行状态
case Run :
{
OLED_ShowStr(55,2,"Running",2);
break;
}
//故障状态
case Err :
{
OLED_ShowStr(55,2,"Error ",2);
break;
}
}
}
//显示电压电流每一位
OLEDShowData(72,4,VOtemp[0]);
OLEDShowData(80,4,VOtemp[1]);
OLEDShowData(96,4,VOtemp[2]);
OLEDShowData(104,4,VOtemp[3]);
OLEDShowData(72,6,IOtemp[0]);
OLEDShowData(80,6,IOtemp[1]);
OLEDShowData(96,6,IOtemp[2]);
OLEDShowData(104,6,IOtemp[3]);
//显示电压电流每一位
OLEDShowData(0,4,VItemp[0]);
OLEDShowData(8,4,VItemp[1]);
OLEDShowData(24,4,VItemp[2]);
OLEDShowData(32,4,VItemp[3]);
OLEDShowData(0,6,IItemp[0]);
OLEDShowData(8,6,IItemp[1]);
OLEDShowData(24,6,IItemp[2]);
OLEDShowData(32,6,IItemp[3]);
//设置电压每一位
OLEDShowData(0,2,VStemp[0]);
OLEDShowData(8,2,VStemp[1]);
OLEDShowData(24,2,VStemp[2]);
}
4、原理图/PCB
原理图和PCB都使用立创EDA绘制,对新手较为友好。可以导出为AD格式的文件。
原理图主要包括电源电路,为单片机、显示器等提供辅助电源。信号调理电路,包括直流偏执电路,运算放大电路,BUCK-BOOST开关电路等。