最流行的降压和升压dc / dc拓扑有一个明显的限制:降压拓扑只能降低输入电压,而升压拓扑只能提高输入电压。但是,有些任务需要在输入电压范围需要同时操作以进行增减时,例如,我们的输入为3 ... 15V,并且在输出处必须获得稳定的12V。熟悉情况?
有两种可能的解决方案:
- 使用升压转换器,将输入电压从3 ... 15V增加到输出的稳定15V,然后使用降压拓扑将电压降低至所需的12V。
- 应用降压-升压拓扑可以最佳地解决此问题。
第一种方法的明显缺点是需要使用2个扼流圈,增加电容器的数量,而不是使用最佳工作模式,这意味着效率较低。降压-升压拓扑结构没有这些缺点,因此今天我们将讨论它。为了使它有趣,我决定不使用一些现成的控制器,而是基于STM32F334C8T6实现了一个数字控制的dc / dc转换器。
在本文的框架中,我将简要讨论转换器的硬件实现以及如何为各种操作模式实现控制系统。有趣?那我们走吧...
1.简要介绍升降压拓扑结构的工作原理
: 2 2 , .. , 2 (4 ). , . :
, : 2 ( 2 , ), 4 , . 1 2 (OCP) . 2 ? , , .
, , , STM32F334, STM32G474, XMC4108, TMS320F28027 , .. : HRPWM, , , . , , , . , , , (OCP) , , .
… buck-boost :
buck () boost (), — 3 buck-, L1C3 LC-. 3 boost-, . , buck-, boost-. .
buck:
boost:
, buck- boost :
buck-boost 3- : ( PWM-BUCK PWM-BOOST). , .
, . , 8, Dboost 70%, Dbuck 50%. :
, 8 . , , , 2 - :
. (duty) 2- . duty, .
2. .
2 , : . , , CC/CV . :
CC CV , : REF , , ; , , , , .
-, , " " . "" (REF), , , 10. , buck-boost , (duty). - . , .
:
它给我们什么?现在,我们知道输出电压的实际值与设定值(REF)相差了多少。这使我们能够理解是否有必要“发出命令”来增大或减小电压。例如,在降压拓扑中,要增加电压,您需要增加上部晶体管的占空比,并要降低电压,相应地减少填充。相反,对于升压拓扑,对于降压-升压,有2个信号,这已经很困难了-您需要进行平衡,但是我认为平均而言,思路很明确,为清楚起见,我将给出一个用于控制降压的伪代码:
// -
uint16_t dutyPWM = 0;
// ,
const float referenceOutputVoltage = 10.0f;
// , , 1
void sTim3::handler (void) {
float outputVoltage = GetOutputVoltage();
if (outputVoltage > referenceOutputVoltage) {
dutyPWM--;
} else {
dutyPWM++;
}
}
, . - ( ), , -, -:
// -
uint16_t dutyPWM = 0;
// ,
const float referenceOutputVoltage = 10.0f;
//
const float Kp = 1.0f;
// , , 1
void sTim3::handler (void) {
float outputVoltage = GetOutputVoltage();
float error = referenceOutputVoltage - outputVoltage;
dutyPWM += Kp * error;
}
… , , (dutyPWM) buck , , . , (reference), dutyPWM .
, 1 , . error -. , dutyPWM .
buck dc/dc , 20. dutyPWM 0, 1000, buck Vout = Vin x dutyPWM = 20V x 0 = 0V, 0. ( №1) error = 10 — 0 = 10 dutyPWM = 10, Vout = Vin x dutyPWM = 20V x (10/1000) = 0.2V. 1 ( №2) error = 10 — 0.2V = 9.8V, dutyPWM = 19.8, (reference). , reference 10 ( ).
Kp, , . 1, . , 0.2 . () , , . Kp 10 : dutyPWM = Kp x error = 10 x (10 — 0) = 100, 0.2, Vout = Vin x dutyPWM = 20V x (100/1000) = 2V, " " 10 . Kp . , , , , .
… ? , .
3. CV mode
CV mode, . ( ), , , : - ++. , . , .
STM32F334C8T6, , HRPWM . , , . , (2-3-4) , , .
CV :
/***********************************************************
* 200 ,
* HRPWM - 30 000.
* : 3...15
* : 20
*
* : 12
***********************************************************/
void sTim3::handler (void) {
TIM3->SR &= ~TIM_SR_UIF;
float inputVoltage = Feedback::GetInputVoltage();
// boost, Vin < 90% * Vref
if (inputVoltage <= (Application::referenceOutputVoltage * 0.9)) {
Hrpwm::SetDuty(Hrpwm::Channel::buck, 29000);
float outputVoltage = Feedback::GetOutputVoltage();
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBoost += pidVoltageMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::boost, Application::dutyBoost);
}
// buck, Vin > Vref * 110%
if (inputVoltage >= (Application::referenceOutputVoltage * 1.1)) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 1000);
float outputVoltage = Feedback::GetOutputVoltage();
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBuck += pidVoltageMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
// buck-boost, (90% * Vref) < Vin < (110% * Vref)
if ((inputVoltage > (Application::referenceOutputVoltage * 0.9)) && (inputVoltage < (Application::referenceOutputVoltage * 1.1))) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 6000);
float outputVoltage = Feedback::GetOutputVoltage();
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBuck += pidVoltageMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
}
… buck-boost, , 2- buck boost . 2- : . , , , .
/***********************************************************
* 200 ,
* HRPWM - 30 000.
* : 3...15
* : 20
*
* : 12
***********************************************************/
void sTim3::handler (void) {
TIM3->SR &= ~TIM_SR_UIF;
// boost
float inputVoltage = Feedback::GetInputVoltage();
if (inputVoltage < 6.0f) { Application::dutyBoost = 25000; }
if ((inputVoltage >= 6.0f) && (inputVoltage < 12.0f)) { Application::dutyBoost = 18000; }
if (inputVoltage >= 12.0f) { Application::dutyBoost = 6000; }
Hrpwm::SetDuty(Hrpwm::Channel::boost, Application::dutyBoost);
// buck
float outputVoltage = Feedback::GetOutputVoltage();
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBuck += pidVoltageMode.Get();
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
3 : 3...6, 6...12 12...15 boost , buck. , — , . , ( ), .
3 , , , , . dutyBoost : , buck boost-, 90% ( ). , 3...15 . dutyBoost — 3 15, , .. . dutyBuck 90% 3 "" boost- 3 x 0,9 = 2,7, boost 15 2.7! dutyBoost 1 — (Vout / Vin) = 1 — 2,7 / 15 = 82%, , - 30000, 30 000 x 82% = 24 600, 25000.
3, 5, buck 3. , dutyBoost, buck 90% 12. , ~3,2% . ? , , "" .
6...12 60% 18000, 12...15 20% 6000. - ...
3- . , , buck 100% boost-, boost dc/dc . , , — boost- 0% buckDuty, buck dc/dc . — , buck, boost buck-boost...
boost , "" 90% , Vref x 90% = 12 x 0,9 = 10,8. dutyBoost = 1 — (Vref x 90%) / (Vref x 110%) = 1 — 0,9 / 1,1 = 19% = 5700, 6000 . buck- buckDuty. "" buck-boost , . , :
4. CC mode
, . , , , LED, - , . , dc/dc , .. (duty), ?
— : U = I x R. , , , 10 . dc/dc 10 , I = U / R = 1, , .. . Li-ion , , 15, - 5, . , , I = U / R = const.
, , , . , , , I = U / R = const.
, 1. 1 1: I = 1 = const = U / R = 1 / 1 . 5 , 5: I = 1 = const = U / R = 5 / 5 . 5, 1 0.2 .
, , (error) , (dutyPWM). :
/***********************************************************
* 200 ,
* HRPWM - 30 000.
* : 3...15
* : 20
*
* : 1
***********************************************************/
void sTim3::handler (void) {
TIM3->SR &= ~TIM_SR_UIF;
float inputVoltage = Feedback::GetInputVoltage();
// boost, Vin < 90% * Vref
if (inputVoltage <= (Application::referenceOutputVoltage * 0.9)) {
Hrpwm::SetDuty(Hrpwm::Channel::buck, 29000);
float outputCurrent = Feedback::GetOutputCurrent();
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBoost += pidCurrentMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::boost, Application::dutyBoost);
}
// buck, Vin > Vref * 110%
if (inputVoltage >= (Application::referenceOutputVoltage * 1.1)) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 1000);
float outputCurrent = Feedback::GetOutputCurrent();
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBuck += pidCurrentMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
// buck-boost, (90% * Vref) < Vin < (110% * Vref)
if ((inputVoltage > (Application::referenceOutputVoltage * 0.9)) && (inputVoltage < (Application::referenceOutputVoltage * 1.1))) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 6000);
float outputCurrent = Feedback::GetOutputCurrent();
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(10,0,0,0,0)
.Compute();
Application::dutyBuck += pidCurrentMode.Get()
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
}
, buck-boost . , (outputCurrent) - (referenceOutputCurrent) , , . :
, CV mode. - , 2 : , , , .
LED 10 1, :
5. CC/CV mode
, … :
- 10 Li-ion , , . , , ( ) , .
- 1, Li-ion , . … ? , , , , , — .
- , ? CC/CV, . : 1 Li-ion 4.2 , CC/CV 3...15 1. , 1 , CC , . , 15, CV, 15 ( ).
2 , .. , 15 , , 1 — , . 3, , , CV , . , :
/***********************************************************
* 200 ,
* HRPWM - 30 000.
* : 3...15
* : 20
*
* : 10 1
***********************************************************/
void sTim3::handler (void) {
TIM3->SR &= ~TIM_SR_UIF;
float resultPID = 0.0f;
float inputVoltage = Feedback::GetInputVoltage();
// boost, Vin < 90% * Vref
if (inputVoltage <= (Application::referenceOutputVoltage * 0.9)) {
Hrpwm::SetDuty(Hrpwm::Channel::buck, 29000);
float outputVoltage = Feedback::GetOutputVoltage();
float outputCurrent = Feedback::GetOutputCurrent();
// CC mode, Vout < Vref
if (outputVoltage < (Application::referenceOutputVoltage - 0.2f)) {
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(20,0,0,0,0)
.Compute();
resultPID = pidCurrentMode.Get();
}
// CV mode, (Iout -> 0) (Vout => Vref)
if ((outputCurrent < 0.05f) || (outputVoltage >= (Application::referenceOutputVoltage - 0.2f))) {
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(50,0,0,0,0)
.Compute();
resultPID = pidVoltageMode.Get();
}
Application::dutyBoost += resultPID;
Hrpwm::SetDuty(Hrpwm::Channel::boost, Application::dutyBoost);
}
// buck, Vin > Vref * 110%
if (inputVoltage >= (Application::referenceOutputVoltage * 1.1)) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 1000);
float outputVoltage = Feedback::GetOutputVoltage();
float outputCurrent = Feedback::GetOutputCurrent();
// CC mode, Vout < Vref
if (outputVoltage < (Application::referenceOutputVoltage - 0.2f)) {
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(20,0,0,0,0)
.Compute();
resultPID = pidCurrentMode.Get();
}
// CV mode, (Iout -> 0) (Vout => Vref)
if ((outputCurrent < 0.05f) || (outputVoltage >= (Application::referenceOutputVoltage - 0.2f))) {
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(50,0,0,0,0)
.Compute();
resultPID = pidVoltageMode.Get();
}
Application::dutyBuck += resultPID;
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
// buck-boost, (90% * Vref) < Vin < (110% * Vref)
if ((inputVoltage > (Application::referenceOutputVoltage * 0.9)) && (inputVoltage < (Application::referenceOutputVoltage * 1.1))) {
Hrpwm::SetDuty(Hrpwm::Channel::boost, 6000);
float outputVoltage = Feedback::GetOutputVoltage();
float outputCurrent = Feedback::GetOutputCurrent();
// CC mode, Vout < Vref
if (outputVoltage < (Application::referenceOutputVoltage - 0.2f)) {
pidCurrentMode
.SetReference(Application::referenceOutputCurrent)
.SetSaturation(-29800, 29800)
.SetFeedback(outputCurrent, 0.001)
.SetCoefficient(20,0,0,0,0)
.Compute();
resultPID = pidCurrentMode.Get();
}
// CV mode, (Iout -> 0) (Vout => Vref)
if ((outputCurrent < 0.05f) || (outputVoltage >= (Application::referenceOutputVoltage - 0.2f))) {
pidVoltageMode
.SetReference(Application::referenceOutputVoltage)
.SetSaturation(-29800, 29800)
.SetFeedback(outputVoltage, 0.001)
.SetCoefficient(50,0,0,0,0)
.Compute();
resultPID = pidVoltageMode.Get();
}
Application::dutyBuck += resultPID;
Hrpwm::SetDuty(Hrpwm::Channel::buck, Application::dutyBuck);
}
}
, , if, . .
, 2 -, , — -. CC mode CV mode. : (Application::referenceOutputVoltage) , CV mode, 15. , CC mode 1.
, / , . , LED 2 . , , 10 STM32F334 .
buck-boost dc/dc CC/CV:
...
, : https://t.me/proHardware. , , , , , .
, . buck-boost-, , , - , .