本帖最后由 Tiny。P 于 2018-9-16 11:03 编辑 : o! z. O" z' [7 R; [" o: x5 r 1. 方案概述 1.1. 概述 数字电源并不是简单的指在系统中应用了数字器件,如单片机及DSP等,而是指整个系统的控制应用数字器件的计算能力和离散控制方法来完成,随着电力电子的发展,电源越来越趋向数字化与智能化发展。本设计采用STM32F334作为控制器的同步降压变换器的数字电源,可以实现降压控制,也可以实现升压控制,能量双向流动。数字控制不只能让电源更简单,还可以让电源实现四遥功能。四遥:遥测、遥信、遥控及遥调。 本设计将介绍同步降压的数字控制方案硬件和软件的设计说明,并附相关电路原理图及参考代码。 1.2. 系统主要结构如图-1所示,BUCK同步降压系统由辅助电路、控制电路、驱动电路、BUCK电路、信号调理电路构成。具体硬件的介绍及说明见第2章节内容。 åæ¥éåçæ°åæ§å¶æ¹æ¡ç»æå¾ 图-1 基于STM32F334微控制器的BUCK同步降压的数字控制方案结构图 本设计应用了STM32F334的PWM模块发出对称的PWM波驱动BUCK电路;通过ADC模块采集直流母线电压,输出电压、输出电流及远端测量,特别说明的是远端测量,认为在电池充放电应用是有效的,因为其可以解决电缆电线的压降问题;预留一个串口通信接口,可以实现与上位机,操作面板等设备通信。 1.3. 主要功能和指标
适合于太阳能微转换器、数字电源和电池充放电、直流UPS应用 2. 方案硬件设计2.1. 功率电路 如图-2所示,同步BUCK由经典的BUCK变换而来,具体是使用mos替换二极管实现。输入端与输出端都采用LC滤波,使得输入输出电流连续,便于滤波。输出端的-极采用采用电阻实现电流采样,并经过放大电路放大之后送入MCU的ADC口,具体将在第2.3节介绍。 BUCK 图-2 BUCK同步降压电路原理图 2.2. 驱动电路如图-3所示,MOS管驱动电路采用TI的半桥驱动芯片UCC27211。该器件内部集成自举电容充电用二极管,耐压120V,驱动电流达4A。特别注意,该器件内部不带死区时间功能,为避免上下桥臂同时导通,死区时间必须在MCU上实现。 UCC27211 图-3 MOS管驱动电路 2.3. 信号调理电路信号调理电路包含输入电压检测,输出电压检测,远端电压测量,输出电流检测等,这些功能都是基于TLV2374运算放大器实现并且采用差分形式。 1)输入电压检测 如图-4所示,输入电压检测直接采用电阻分压实现。 表达式: Vin = ADC_V_IN * 31 (式1) 12 图-4 输入电压检测电路 2)输出电压检测 如图-5所示,输出电压检测电路基于TLV2374的差分电路实现,由于主电路的输出端的低端电流采样会对电压检测形成干扰,并且差分电路具有很高的共模信号抑制,有利于猜到准确的信号。 表达式: Vout = ADC_V_OUT * 30 (式2) 13 图-5 输出电压检测电路 3)远端电压检测 如图-6所示,远端电压检测电路基于TLV2374的差分电路实现,远端电压测量对于电池充放电是有效的,可以避免由于导线压降产生的影响。用法:直接接入电池两端,请注意正负极。 表达式: Vext = ADC_EXT_SENSN * 30 (式3) 14 图-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) 15 ( v2 Q1 \3 h+ G9 V4 @9 P 图-7 输出电流检测电路 16 , l/ \( `/ r8 Q( J1 k& j' z; j 图-8 参考电压1.65V产生电路 3 i" o, R0 a! V$ `6 X5 d! d0 {2.4. 控制电路 & f7 Y) Z- g5 e. {, ] 图-9 控制电路 如图-9所示,控制电路采用STM32F334微控制器,有下载接口,串口通信等接口以及运行指示LED灯。STM32资源分配如表1所示。 " B& _+ T. i" \, u表1 STM32资源分配
2.5. 辅助电源电路 如图-10所示图-10 辅助电源电路产生12V、3.3V两种电压等级。XL7005A将输入端降压到12V,SPX3819-M-3.3将12V稳压到3.3V。 2 a7 y- @2 e7 N* b9 t9 b! N: y3 [图-10 辅助电源电路 1 ]5 g) k) A9 _! f) U0 n8 U3. 方案主要算法介绍 D# ]( O) k7 U- v# c; y( { 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; //输出限制最小值 - ?- C2 X) e3 j4 R+ M$ f} 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; //¼ÆËãÎó²î 6 R8 [! ^2 `* O$ m2 w: x& t p->Increment = ( p->a0*p->Ek - p->a1*p->Ek_1 + p->a2*p->Ek_2 ); //PID¼ÆËã $ ]$ ?. {0 n, Y2 s4 U p->Output = p->Last_Output + p->Increment; 0 r& K D/ w+ X% H3 Q- |. l 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; } ( H5 b9 N+ ~( z- J. \5 y2 q: V/ C附件: ===============================================================/ u, I! Z2 `$ s( M; {* @ 数字电源的交流1群: 474805564/ ~4 W% s7 F* i 数字电源的交流2群: 183376789- g0 d0 R' a) T n+ D ' a, P) u; ?( Y8 `, D3 f 4 u3 C& `2 O7 G1 g. g/ l8 D$ H- G |
参与人数 1 | ST金币 +30 | 收起 理由 |
---|---|---|
wolfgang2015 | + 30 | 很给力! 写的很详细~~ |
【资料】STM32F3系列精彩集锦——教程、资料、方案
意法半导体推出STM32微处理器专用高集成度电源管理芯片
【经验分享】基于STM32F334的数字电源
开源一个F334的多功能数控电源,基于HAL库编写,手头有一...
基于STM32F334的数字电源
STM32F3DISCOVERY + UCGUI3.90A的移植(源码+视频)
意法半导体八路输出高边开关
意法半导体STM32支持 UCSI 规范,加快Type-C供电广泛应用
如何打造更小的数字输入模块
NFC赋能减碳节能
4.1. BUCK同步降压
降压转换器仅能提供比输入电压低的平均输出电压,这正如其名称所表示的一样。降压转换器的基本原理图和开关波形如图-11所示。在降压转换器中,开关(Q1)与输入电压源VIN 串联。输入电压源VIN 通过功率开关和低通滤波器馈送到输出,而低通滤波器则由电感和电容构成。在稳态运行中,若开关导通时间为TON,输入将向输出和电感(L)提供能量。在TON 期间,电感电流流经功4 r2 R5 R7 y+ q5 s `2 T7 |2 l4 j& o- o
率开关且VIN 和VOUT 之间的正向电压差将加在电感两端,如图-11(C)所示。因此,电感电流IL 将呈线性规律从当前值IL1 上升到IL2,如图-11(E)所示。在TOFF 期间,当开关关闭,电感电流的方向与前面相同,这是由于电感中的储能继续提供负载所需电流。在Q1 关闭期间(TOFF),二极管D1 提供电感电流回路;因此,该二极管称为续流二极管。在TOFF 期间,输出电压VOUT 将以反方向加在电感两端,如图-11(C)所示。因此,电感电流将从当前值IL2 减小至IL1,如图-11所示。
当输出电流要求较高时,续流二极管D1 中过高的功耗将限制可达到的最小输出电压。为减少大电流下的功耗并获得较低的输出电压,采用具有极低导通电阻RDSON的MOSFET替代续流二极管。该MOSFET的导通与关断与降压MOSFET同步。因此,这一结构称为同步降压转换器。该同步MOSFET的栅极驱动信号需与降压开关栅极驱动信号呈现互补关系。3 H2 W" x2 Y& S2 s3 S' N6 n$ s
4.2. 控制模式
1)电压模式控制0 p0 }( T# L7 H/ m; z+ |
在电压模式控制中,对输出电压进行测量并将测量结果与参考值(期望的输出电压)进行比较。随后补偿电路将对误差进行处理以产生下一个占空比值,如图-12所示。该模式只有一个控制环,因此易于设计和分析。然而,在这种控制方法中,当输出电压变化时,必须首先对线电压或负载变化进行检测,随后通过反馈环对它们进行校正。
2)电流模式控制
电流模式控制技术需要两个反馈环,如图13 所示。在这一模式,需对两个参数进行检测以实现控制目的。在输出电容侧或负载端(称为远程检测)对输出电压进行检测。还需对输出电感/ 原边开关电流进行检测。在电流模式控制中,首先将输出电压和参考电压(期望输出电压)进行比较。补偿电路随后对该误差进行处理以产生电流环的参考信号。这一电流参考信号将与测量电流进行比较。电流补偿电路将对由电压补偿电路产生的参考信号与实际从输入汲取的电流进行比较得到的误差进行处理。这将产生所需占空比以保持输出电压在限定范围之内。由于电流模式控制对电路电流进行检测,因此任何输出负载电流或输入电压的变化在影响输出电压之前都会被校正。由于输入电流取决于输入电压,因此对输入电流的检测具有内在的前馈控制特性。电流模式控制提供了推挽式或桥式转换器内在的输入电流对称特性、内在电流限制特性和多转换器并联连接时的负载分流特性。由于采用电流内环,因此阶跃负载响应和瞬态响应特性也得到改善。2 M. o8 c& ?: ~" Y- R
7 _1 V) ]- a" I; n# V
4.3. 参考代码* x7 I9 k3 j' P/ ~! J0 C7 H
此处给出固定电压输出的DEMO 代码,采用电流模式控制:(此处只给出主函数程序,若要详细代码,请自行到Q群下载)" D9 U1 B$ a/ ?/ d4 z
' p8 _1 _2 Y9 t i! k# k6 }
/*--------Includes--------*/, V4 l( r I/ E, y4 T
#include "system_typedef.h"
#include "hp_pid_code.h"
#include "onboard_led.h"* ?4 H- h9 F7 v1 e1 w
#include "timer.h"
#include "usart.h"
#include "hrpwm.h"
#include "stdio.h"/ j$ y. ~5 w5 M) E( J5 Z
#include "adc.h"8 K) k+ i! ]) M) i1 t, P
#include "stdio.h"- I' W) @. \0 w0 ]+ E: x
#include "string.h"; q) R& o! N) I9 ~! L
! f3 y$ N+ B* g- G# x
1 g; L5 g' S( e' A9 f8 s* ?, V1 p
#define fabs(x) (x < 0 ? -x : x) //¾ø¶ÔÖµ¼ÆËã% i6 ?. `9 [+ f
#define Err_OK 0x00
#define Err_HV 0x018 A8 L P( F/ K
#define Err_LV 0x02$ I6 I: [. x, ?# ~ Z1 p
#define Err_ 0x03
% ^# H6 `3 x5 E5 l1 l" a
float32 VIPWR = 0;5 [% a& \4 g) ]
float32 VOPWR = 0;
float32 VOEXT = 0;! z Y& P6 s1 L3 S' Z; P* r! e
float32 IOPWR = 0;
float32 PWRIN = 0;
float32 PWROUT = 0;
float32 VoutREF = 24;+ o- j! k+ {5 c0 G/ M( s* J' |
float32 VinREF = 28;+ M7 N% w* _) B U0 B# M
0 k2 g5 t+ S2 r2 |) a1 h
uint16 ADC_VIPWR_Value;! U, C! \, [) Z
uint16 ADC_VOPWR_Value;# X# S% y" h+ h- m* B- P `6 t
uint16 ADC_VOEXT_Value;
uint16 ADC_IOPWR_Value;0 S# V, h; p, ]6 M/ J
. |4 A9 K% L9 V' p% ?
uint32 PWM_Period;
uint32 PWM_Duty;
PID_TypeDef pid_voltage_loop;5 X! X" d# n, `# q+ P/ I, {
PID_TypeDef pid_current_loop;
void Get_Voltage_Current(void);% h5 H) v6 M, X% L1 r/ l
int main(void)
{
static uint64 i = 0;4 ?% A( H6 _3 f Z6 X7 y; x" T; g
u8 Status = 0;
GPIO_InitTypeDef GPIO_Struct;) }$ e' H, _/ m3 W" j5 e' a) u; ~ F
SysTick_Config(SystemCoreClock / 1000);//Systick³õʼ»¯,SysTick end of count event each 1ms- h' \0 u7 ` L( t( n9 | x
Delay_ms(100);
3 n/ n7 E% [- Q4 ^5 p0 V0 M( N( \
LED_Init();
LED1_On();/ o5 R* _$ U, x) N; u' l5 x+ m! q
LED2_On();
Delay_ms(200);
LED1_Off();: f. ^9 r! Y4 T" ]% J
LED2_Off();$ q/ Q. R* D d$ h6 x7 }
Delay_ms(200);% [! x, {. d) ~$ K
LED1_On();
LED2_On();+ Y" R! S; W5 e% t- g5 o) @
Delay_ms(200);
LED1_Off();0 q8 g R7 B V5 X
LED2_Off();
//-----------USART1_Rx == PB7-------------//
GPIO_Struct.GPIO_Pin = GPIO_Pin_7;$ O. z4 L! ^) K: \" J5 |% Y
GPIO_Struct.GPIO_Mode = GPIO_Mode_OUT;7 L0 V9 L( U0 z2 m9 Z( ?
GPIO_Struct.GPIO_OType = GPIO_OType_PP;, c I j' ?" X, \
GPIO_Struct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;2 N7 k, A: N# q
GPIO_Init(GPIOB, &GPIO_Struct);2 T. c' A, R$ _) ^# W# x: Y# G
TIMER3_init(0.1e3);* |: }2 L# D! E2 p
USART1_init(115200);6 N2 m' w) l* e' K9 K" s
PWM_Period = HrPWM_CHA_Init(200e3);//PWM³õʼ»¯
! p. @% f! O' X% m2 _
ADC_init();//ADCÍâÉè³õʼ»¯
" o; S% N* X& u+ O. q& `: E
PID_DeInit( &pid_voltage_loop );+ M' L4 ] c( V9 B+ L9 w. W
pid_voltage_loop.T = 1000;//PI²ÉÑùÖÜÆÚ£¬µ¥Î»Îªus
pid_voltage_loop.Kp = 0.2;$ r- G( G. I1 t9 N
pid_voltage_loop.Ti = 2000;- g2 h3 H/ e7 c4 d3 d1 O; k7 J$ G
pid_voltage_loop.Td = 0;- a: T9 u6 |% D1 \: I5 Z" n
pid_voltage_loop.OutMax = 5;- v+ a$ n2 \& x% O$ u
pid_voltage_loop.OutMin = -4;
PID_init(&pid_voltage_loop);//µçѹ»·PI²ÎÊý³õʼ»¯5 }, b) F1 B. m" A2 J7 b$ p/ S
PID_DeInit( &pid_current_loop );
pid_current_loop.T = 10;//PI²ÉÑùÖÜÆÚ£¬µ¥Î»Îªus. ]) t! w8 {7 u3 X( o5 f" _
pid_current_loop.Kp = 12;
pid_current_loop.Ti = 100;7 x" U, |( l9 u, Q/ i' y; Q9 i) c
pid_current_loop.Td = 0;
pid_current_loop.OutMax = 0.90*PWM_Period;
pid_current_loop.OutMin = 0.05*PWM_Period;& N) R& |) a6 J! M* k
PID_init(&pid_current_loop);//µçÁ÷»·PI²ÎÊý³õʼ»¯* p' m$ x# B y& }
Delay_ms(5); I* r& h! k e5 Q5 D
HrPWM_CHA_Update(PWM_Period, 0.05*PWM_Period);
HRTIM_WaveformOutputStart(HRTIM1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2 );
Delay_ms(300);! E3 @3 e& W/ ?" G% V
LED1_Off();
LED2_Off();: x1 H" I0 h. L
g0 o; ~; e/ Z: t5 @. ^6 P! W$ v4 l
while (1)4 J* r) K' r2 |+ i: _! B3 q
{
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 );8 K3 m: N$ I w: Z
LED2_Off();: O: m; f, F7 W2 c3 B$ X2 v9 h; m
if(i%50 == 0)LED1_Toggle();//ָʾµÆ½»ÌæÉÁ˸$ c8 J+ _8 p% ]2 }6 X6 f- ^$ m
}
else1 v. Z+ [! y7 ?4 f
{+ D* c8 c3 G! B$ e
LED1_Off();0 r% l& W( `- Q5 \ j$ c
if(i%50 == 0)LED2_Toggle();//ָʾµÆ½»ÌæÉÁ˸3 G p% G/ n! G. l+ r4 u+ t
}" W* j/ A$ l5 ?: Z6 o' ?
PID_Calc( &pid_voltage_loop, VOPWR, VoutREF); //µçѹ»·PI¼ÆËã
if(i%1000 == 0)9 F: \, O# j9 ?* T
{0 O3 m# w! K: X
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);
- Q1 k \ \' \) W
9 a- v5 H( ~2 A; m) e2 |$ i
i++; //¼Æʱ" q# _2 S6 e7 o* b {* e! q
}
}8 G$ [! h F" e2 ~" d% g
void TIM3_IRQHandler(void) //TIM3ÖжÏ( _- O8 C& e( W r$ J
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {# T2 U9 X) T( f" B9 ?
GPIOB->ODR ^= GPIO_Pin_7;- R$ M# ]9 l7 O1 X' {
ADC_IOPWR_Value = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
ADC_VOPWR_Value = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);% H# c; c/ N- }3 N3 _" O0 Y% ?0 a
ADC_VOEXT_Value = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_3);
ADC_VIPWR_Value = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_4);( m0 g( ^9 O- H! H
IOPWR = -(ADC_IOPWR_Value * 3.3/4095 - 1.585)/0.265;$ c# X) l& }! Z2 a
PWM_Duty = PID_Calc( &pid_current_loop, IOPWR, pid_voltage_loop.Output);
HrPWM_CHA_Update(PWM_Period, PWM_Duty);//¸üÐÂPWMÕ¼¿Õ±È4 V7 E. s6 y. O
}+ Y# F6 v# T' G. W* [; b
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //Çå³ýTIMxµÄÖжϴý´¦Àíλ:TIM ÖжÏÔ´
}1 H, B( ?" ^" X
#pragma arm section code = "RAMCODE"+ o' X) q V2 H* d5 X# O: R
void Get_Voltage_Current(void)
{ t1 O# @6 {0 B" N% ^, r& X( Q9 f
// 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);+ r8 G) i4 O4 d
// VIPWR = (float32)((ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_4) * 3.3)/4095.0*32.30);5 Z. R& [+ [, f* \
}) x4 M8 T7 P' I
#pragma arm section
===============================================================% P5 D& M+ T3 ~, W" o
数字电源的交流群: 4748055648 Z( t& X3 a2 v4 b- c
想了解详细源代码,请加入交流群,即可下载。# P% x5 f# a' l N# ~ c* g
7 O7 G' n ?/ a# ^
1.PID的周期应和定时器中断一致/ z3 x! K- a$ ~& H
2.PID的参数整定我用的是试凑法,先调P再调Ki Kd。
3.PID要用数字控制需要用数学的方法(离散化)变成数字PID。2 o* C I, O- m9 Z( p
可以加入我们交流群474805564一起交流学习。
谢谢夸奖,我一直在用感觉效果还不错,还请再指导优化。
原理图花的还好