查看: 13351|回复: 52

[经验] 基于STM32F334的BUCK同步降压数字电源设计

  [复制链接]
  • TA的每日心情
    无聊
    2018-11-16 10:48
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2019-12-30 14:47:56 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 gjhk001 于 2019-12-30 14:50 编辑

    1. 方案概述

    1.1. 概述
    数字电源并不是简单的指在系统中应用了数字器件,如单片机及DSP,而是指整个系统的控制应用数字器件的计算能力和离散控制方法来完成,随着电力电子的发展,电源越来越趋向数字化与智能化发展。本设计采用STM32F334作为控制器的同步降压变换器的数字电源,可以实现降压控制,也可以实现升压控制,能量双向流动。数字控制不只能让电源更简单,还可以让电源实现四遥功能。四遥:遥测、遥信、遥控及遥调。
    本设计将介绍同步降压的数字控制方案硬件和软件的设计说明,并附相关电路原理图及参考代码。
    1.2. 系统主要结构
    如图-1所示,BUCK同步降压系统由辅助电路、控制电路、驱动电路、BUCK电路、信号调理电路构成。具体硬件的介绍及说明见第2章节内容。


    -1 基于STM32F334微控制器的BUCK同步降压的数字控制方案结构图
    本设计应用了STM32F334PWM模块发出对称的PWM波驱动BUCK电路;通过ADC模块采集直流母线电压,输出电压、输出电流及远端测量,特别说明的是远端测量,认为在电池充放电应用是有效的,因为其可以解决电缆电线的压降问题;预留一个串口通信接口,可以实现与上位机,操作面板等设备通信。
    1.3. 主要功能和指标
    • 输入电压:10~64V,输出电压:5~60V
    • 最大电流:5A
    • 最大功率:240w
    • 高效率设计,支持的最大效率超过95%
    • 250 KHz开关频率支持更小的无源组件,从而减小电路板面积并延长寿命
    • 三个满足各种应用场合的控制模式:1) 输出电压控制 2) MPPT 控制(输入电流控制)3) 反向电压控制。
    • 保护机制:过压保护,欠压保护,过流保护。
    1.4. 应用对象
    适合于太阳能微转换器、数字电源和电池充放电、直流UPS应用
    2. 方案硬件设计
    2.1. 功率电路

    如图-2所示,同步BUCK由经典的BUCK变换而来,具体是使用mos替换二极管实现。输入端与输出端都采用LC滤波,使得输入输出电流连续,便于滤波。输出端的-极采用采用电阻实现电流采样,并经过放大电路放大之后送入MCUADC口,具体将在第2.3节介绍。

    -2 BUCK同步降压电路原理图
    2.2. 驱动电路
    如图-3所示,MOS管驱动电路采用TI的半桥驱动芯片UCC27211。该器件内部集成自举电容充电用二极管,耐压120V,驱动电流达4A。特别注意,该器件内部不带死区时间功能,为避免上下桥臂同时导通,死区时间必须在MCU上实现。

    -3 MOS管驱动电路
    2.3. 信号调理电路
    信号调理电路包含输入电压检测,输出电压检测,远端电压测量,输出电流检测等,这些功能都是基于TLV2374运算放大器实现并且采用差分形式。
    1)输入电压检测
    如图-4所示,输入电压检测直接采用电阻分压实现。
    表达式:
    Vin   =   ADC_V_IN * 31              (式1


    -4 输入电压检测电路

    2)输出电压检测
    如图-5所示,输出电压检测电路基于TLV2374的差分电路实现,由于主电路的输出端的低端电流采样会对电压检测形成干扰,并且差分电路具有很高的共模信号抑制,有利于猜到准确的信号。
    表达式:
    Vout   =   ADC_V_OUT * 30              (式2


    -5 输出电压检测电路
    3)远端电压检测
    如图-6所示,远端电压检测电路基于TLV2374的差分电路实现,远端电压测量对于电池充放电是有效的,可以避免由于导线压降产生的影响。用法:直接接入电池两端,请注意正负极。
    表达式:
    Vext   =   ADC_EXT_SENSN * 30              (式3


    -6 远端电压检测电路
    4)输出电流检测
    如图-7所示,输出电流检测电路基于TLV2374的差分放大电路实现,在主电路中采样电阻采用10mΩ,要使MCU能够识别该信号,必须经过放大到一定值。由因为本应用要实现双向DCDC功能,这就使得电流有正负,但是MCU无法采集负信号,这里得认为将电压提高,保证电流在负值时,ADC_I_OUT输出还是为正。所以,采用1:1电阻分压,然后经过一个跟随器(提高驱动能力)输出一个1.65V的参考电压,如图-8所示。到这里,该检测电路就可实现正负点流的采样。
    表达式:
    Iout   =   ADC_I_OUT - 1.65/ 0.20           (式3


    -7 输出电流检测电路


    -8 参考电压1.65V产生电路


    2.4. 控制电路


    -9 控制电路
    如图-9所示,控制电路采用STM32F334微控制器,有下载接口,串口通信等接口以及运行指示LED灯。STM32资源分配如表1所示。

    1 STM32资源分配
    功能分类
    引脚名称
    对应信号
    说明
    PWM信号
    PA8
    PWM1A
    上桥臂驱动信号
    PA9
    PWM1B
    下桥臂驱动信号
    ADC信号
    PA0
    ADC_I_OUT
    输出电流检测
    PA1
    ADC_V_OUT
    输出电压检测
    PA2
    ADC_EXT_SENSN
    远端电压检测
    PA3
    ADC_V_IN
    输入电压检测
    串口通信
    PB6
    USART1_TX
    USART1发送
    PB7
    USART1_RX
    USART1接收
    程序下载接口
    PA13
    SWDAT
    SWD仿真接口
    PA14
    SWCLK
    LED指示灯
    PB3
    LED2
    故障指示灯
    PB4
    LED1
    运行指示灯

    2.5. 辅助电源电路
    如图-10所示图-10 辅助电源电路产生12V3.3V两种电压等级。XL7005A将输入端降压到12VSPX3819-M-3.312V稳压到3.3V



    -10 辅助电源电路

    3. 方案主要算法介绍
    3.1. PID算法
    PID算法是一个很经典的自动控制算法,经过几十年的认证,在我们生活发挥了重大作用。PID的资料已经太多了,此处不再讲述其原理,直接给出C代码,若想了解其根本原理,请自行学习。

    PID算法用到的数据:
    typedef struct  _PID{   
    pid_float32        SetPoint;                //输入:给定值
            pid_float32        Feedback;                //输入:反馈值

            pid_float64        T;                //采样时间
            pid_float64        Kp;                //比例常数
            pid_float64        Ti;                //积分时间
            pid_float64        Td;                //微分时间

            pid_float32        a0;                //系数1:a0 = Kp(1 + T/Ti + Td/T)
            pid_float32        a1;                //系数2: a1 = Kp(1 + 2Td/T)
            pid_float32        a2;                //系数3:a2 = Kp*Td/T

            pid_float32        Ek;       //当前误差
            pid_float32        Ek_1;     //前一次误差
            pid_float32        Ek_2;     //第二次误差

            pid_float32        Output;                        //输出值
            pid_float32        Last_Output;        //上一次输出值
            pid_float32        Increment;                //增量值

            pid_float32        OutMax;                        //输出限制最大值
            pid_float32        OutMin;                        //输出限制最小值

    } PID_TypeDef;


    PID的数据初始化程序:
    void PID_init ( PID_TypeDef *p)
    {   

            p->a0                = p->Kp*(1 + 1.0*p->T/p->Ti + 1.0*p->Td/p->T);
            p->a1                = p->Kp*(1 + 2.0*p->Td/p->T);
            p->a2                = 1.0*p->Kp*p->Td/p->T;
    }


    增量式PID算法:
    pid_float32 PID_Calc( PID_TypeDef *p, pid_float32 feedback, pid_float32 ref)
    {
            p->Ek        = ref - feedback;                //¼ÆËãÎó²î

            p->Increment                = (  p->a0*p->Ek        - p->a1*p->Ek_1 + p->a2*p->Ek_2 );        //PID¼ÆËã

            p->Output = p->Last_Output + p->Increment;

            if(p->Output > p->OutMax)p->Output   =        p->OutMax;
            if(p->Output < p->OutMin)p->Output   =        p->OutMin;
            p->Ek_2           = p->Ek_1;
            p->Ek_1           = p->Ek;               
            p->Last_Output    = p->Output;
            return p->Output;
    }

    附件:
    游客,如果您要查看本帖隐藏内容请回复

    评分

    参与人数 1与非币 +24 收起 理由
    wangxihe + 24

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2018-11-16 10:48
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

     楼主| 发表于 2019-12-30 14:49:40 | 显示全部楼层
    . BUCK同步减压拓扑及控制方式说明
    4.1. BUCK同步降压
    降压转换器仅能提供比输入电压低的平均输出电压,这正如其名称所表示的一样。降压转换器的基本原理图和开关波形如图-11所示。在降压转换器中,开关(Q1)与输入电压源VIN 串联。输入电压源VIN 通过功率开关和低通滤波器馈送到输出,而低通滤波器则由电感和电容构成。在稳态运行中,若开关导通时间为TON,输入将向输出和电感(L)提供能量。在TON 期间,电感电流流经功
    率开关且VIN 和VOUT 之间的正向电压差将加在电感两端,如图-11(C)所示。因此,电感电流IL 将呈线性规律从当前值IL1 上升到IL2,如图-11(E)所示。在TOFF 期间,当开关关闭,电感电流的方向与前面相同,这是由于电感中的储能继续提供负载所需电流。在Q1 关闭期间(TOFF),二极管D1 提供电感电流回路;因此,该二极管称为续流二极管。在TOFF 期间,输出电压VOUT 将以反方向加在电感两端,如图-11(C)所示。因此,电感电流将从当前值IL2 减小至IL1,如图-11所示。

    图-11 电压模式控制

    当输出电流要求较高时,续流二极管D1 中过高的功耗将限制可达到的最小输出电压。为减少大电流下的功耗并获得较低的输出电压,采用具有极低导通电阻RDSON的MOSFET替代续流二极管。该MOSFET的导通与关断与降压MOSFET同步。因此,这一结构称为同步降压转换器。该同步MOSFET的栅极驱动信号需与降压开关栅极驱动信号呈现互补关系。
    4.2. 控制模式
    1)电压模式控制
    在电压模式控制中,对输出电压进行测量并将测量结果与参考值(期望的输出电压)进行比较。随后补偿电路将对误差进行处理以产生下一个占空比值,如图-12所示。该模式只有一个控制环,因此易于设计和分析。然而,在这种控制方法中,当输出电压变化时,必须首先对线电压或负载变化进行检测,随后通过反馈环对它们进行校正。

    图-12 电压模式控制

    2)电流模式控制
    电流模式控制技术需要两个反馈环,如图13 所示。在这一模式,需对两个参数进行检测以实现控制目的。在输出电容侧或负载端(称为远程检测)对输出电压进行检测。还需对输出电感/ 原边开关电流进行检测。在电流模式控制中,首先将输出电压和参考电压(期望输出电压)进行比较。补偿电路随后对该误差进行处理以产生电流环的参考信号。这一电流参考信号将与测量电流进行比较。电流补偿电路将对由电压补偿电路产生的参考信号与实际从输入汲取的电流进行比较得到的误差进行处理。这将产生所需占空比以保持输出电压在限定范围之内。由于电流模式控制对电路电流进行检测,因此任何输出负载电流或输入电压的变化在影响输出电压之前都会被校正。由于输入电流取决于输入电压,因此对输入电流的检测具有内在的前馈控制特性。电流模式控制提供了推挽式或桥式转换器内在的输入电流对称特性、内在电流限制特性和多转换器并联连接时的负载分流特性。由于采用电流内环,因此阶跃负载响应和瞬态响应特性也得到改善。

    图-13 电流模式控制


    4.3. 参考代码
    此处给出固定电压输出的DEMO 代码,采用电流模式控制:(此处只给出主函数程序,若要详细代码,请自行到Q群下载)


    /*--------Includes--------*/
    #include "system_typedef.h"
    #include "hp_pid_code.h"
    #include "onboard_led.h"
    #include "timer.h"
    #include "usart.h"
    #include "hrpwm.h"
    #include "stdio.h"
    #include "adc.h"
    #include "stdio.h"
    #include "string.h"


    #define fabs(x)        (x < 0 ? -x : x)        //¾ø¶ÔÖµ¼ÆËã

    #define Err_OK                 0x00
    #define Err_HV        0x01
    #define Err_LV        0x02
    #define Err_        0x03



    float32        VIPWR        = 0;
    float32        VOPWR        = 0;
    float32        VOEXT        = 0;
    float32        IOPWR        = 0;
    float32        PWRIN        = 0;
    float32        PWROUT        = 0;
    float32 VoutREF = 24;
    float32 VinREF          = 28;

    uint16  ADC_VIPWR_Value;
    uint16  ADC_VOPWR_Value;
    uint16  ADC_VOEXT_Value;
    uint16  ADC_IOPWR_Value;

    uint32 PWM_Period;
    uint32 PWM_Duty;
    PID_TypeDef pid_voltage_loop;
    PID_TypeDef pid_current_loop;

    void Get_Voltage_Current(void);

    int main(void)
    {
    static uint64 i        = 0;

    u8 Status = 0;
    GPIO_InitTypeDef  GPIO_Struct;
      SysTick_Config(SystemCoreClock / 1000);//Systick³õʼ»¯,SysTick end of count event each 1ms
    Delay_ms(100);  

      LED_Init();
    LED1_On();
    LED2_On();
    Delay_ms(200);
    LED1_Off();
    LED2_Off();
    Delay_ms(200);
    LED1_On();
    LED2_On();
    Delay_ms(200);
    LED1_Off();
    LED2_Off();
    //-----------USART1_Rx == PB7-------------//
      GPIO_Struct.GPIO_Pin        = GPIO_Pin_7;
      GPIO_Struct.GPIO_Mode        = GPIO_Mode_OUT;
      GPIO_Struct.GPIO_OType = GPIO_OType_PP;
      GPIO_Struct.GPIO_PuPd        = GPIO_PuPd_UP;
    GPIO_Struct.GPIO_Speed        = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_Struct);

    TIMER3_init(0.1e3);
    USART1_init(115200);
    PWM_Period        = HrPWM_CHA_Init(200e3);//PWM³õʼ»¯
      
    ADC_init();//ADCÍâÉè³õʼ»¯

    PID_DeInit( &pid_voltage_loop );
    pid_voltage_loop.T        = 1000;//PI²ÉÑùÖÜÆÚ£¬µ¥Î»Îªus
    pid_voltage_loop.Kp        = 0.2;
    pid_voltage_loop.Ti        = 2000;
    pid_voltage_loop.Td        = 0;
    pid_voltage_loop.OutMax        = 5;
    pid_voltage_loop.OutMin        = -4;
    PID_init(&pid_voltage_loop);//µçѹ»·PI²ÎÊý³õʼ»¯

    PID_DeInit( &pid_current_loop );
    pid_current_loop.T        = 10;//PI²ÉÑùÖÜÆÚ£¬µ¥Î»Îªus
    pid_current_loop.Kp        = 12;
    pid_current_loop.Ti        = 100;
    pid_current_loop.Td        = 0;
    pid_current_loop.OutMax        = 0.90*PWM_Period;
    pid_current_loop.OutMin        = 0.05*PWM_Period;
    PID_init(&pid_current_loop);//µçÁ÷»·PI²ÎÊý³õʼ»¯
    Delay_ms(5);
    HrPWM_CHA_Update(PWM_Period, 0.05*PWM_Period);
    HRTIM_WaveformOutputStart(HRTIM1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2 );
    Delay_ms(300);
    LED1_Off();
    LED2_Off();


    while (1)
      {
    VIPWR        = ADC_VIPWR_Value * 3.3/4095.0*30.00;
    VOPWR        = ADC_VOPWR_Value * 3.3/4095.0*30.00;
    VOEXT        = ADC_VOEXT_Value * 3.3/4095.0*30.00;
    if(((VIPWR < 26 + 1.0)  || fabs(IOPWR) > 6.0) && i > 5 )
    {
    HRTIM_WaveformOutputStop(HRTIM1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2 );
    LED2_Off();
    if(i%50 == 0)LED1_Toggle();//ָʾµÆ½»ÌæÉÁ˸
    }
    else
    {
    LED1_Off();
    if(i%50 == 0)LED2_Toggle();//ָʾµÆ½»ÌæÉÁ˸
    }
    PID_Calc( &pid_voltage_loop, VOPWR, VoutREF);        //µçѹ»·PI¼ÆËã
    if(i%1000 == 0)
    {
    printf("Vin  = %fv\r\nVout = %fv\r\nVext = %fv\r\nIout = %fA\r\nPWM  = %f\r\n", VIPWR, VOPWR, VOEXT, IOPWR, (float)PWM_Duty/PWM_Period);
    }
    Delay_ms(1);


    i++;        //¼Æʱ
       }
    }

    void TIM3_IRQHandler(void)   //TIM3ÖжÏ
    {
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)        {
    GPIOB->ODR ^= GPIO_Pin_7;
    ADC_IOPWR_Value        = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
    ADC_VOPWR_Value        = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);
    ADC_VOEXT_Value        = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_3);
    ADC_VIPWR_Value        = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_4);

    IOPWR        = -(ADC_IOPWR_Value * 3.3/4095 - 1.585)/0.265;

    PWM_Duty        = PID_Calc( &pid_current_loop, IOPWR, pid_voltage_loop.Output);
    HrPWM_CHA_Update(PWM_Period, PWM_Duty);//¸üÐÂPWMÕ¼¿Õ±È
    }
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);           //Çå³ýTIMxµÄÖжϴý´¦Àíλ:TIM ÖжÏÔ´
    }

    #pragma arm section code = "RAMCODE"
    void Get_Voltage_Current(void)
    {
    //        IOPWR        = (float32)(-((ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1) * 3.3)/4095.0 - 1.681)/0.201 );
    //        VOPWR        = (float32)((ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2) * 3.3)/4095.0*31.50);
    //        VOEXT        = (float32)((ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_3) * 3.3)/4095.0*31.60);
    //        VIPWR        = (float32)((ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_4) * 3.3)/4095.0*32.30);
    }
    #pragma arm section
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2019-12-30 19:00
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2019-12-30 19:00:48 | 显示全部楼层
    感谢分享      
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2021-3-17 20:56
  • 签到天数: 5 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2020-1-1 15:20:13 | 显示全部楼层
    看看PID算法
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-5-24 10:58
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2020-1-1 21:11:04 | 显示全部楼层
    好东西,学习了,我也刚做了一个。 1.jpg 2.jpg


    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2020-10-21 18:18
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2020-1-2 22:19:34 | 显示全部楼层
    学习一下,真正学习这方面知识
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2020-1-9 16:05
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2020-1-9 08:16:37 | 显示全部楼层
    自制BLDC/PMSM电机驱动板汇总开源分享:PCB+元件库+程序+教程  
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 04:49 , Processed in 0.221346 second(s), 36 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.