Convertisseur Buck-Boost avec commande numérique sur STM32F334 en mode CC / CV

Les topologies de convertisseur abaisseur / boost cc / cc les plus populaires ont une limitation importante: la topologie abaisseur ne peut que réduire la tension d'entrée, et la topologie boost ne l'augmente. Cependant, il y a des tâches lorsque la plage de tension d'entrée nécessite un fonctionnement simultané pour augmenter et diminuer, par exemple, nous avons une entrée de 3 ... 15V, et en sortie, il est nécessaire d'obtenir un 12V stabilisé. Situation familière?



Il existe 2 solutions possibles:



  • À l'aide d'un convertisseur élévateur, augmentez la tension d'entrée de 3 ... 15V à un 15V stable en sortie, puis, en utilisant la topologie buck, abaissez la tension au 12V requis;
  • Appliquez une topologie buck-boost qui résout de manière optimale ce problème.


Un inconvénient évident de la première méthode est la nécessité d'utiliser 2 selfs, un nombre accru de condensateurs et non le mode de fonctionnement le plus optimal, ce qui signifie un rendement inférieur. La topologie Buck-Boost est dépourvue de ces inconvénients, nous en parlerons donc aujourd'hui. Pour rendre cela intéressant, j'ai décidé de ne pas prendre de contrôleur prêt à l'emploi et j'ai implémenté un convertisseur DC / DC à commande numérique basé sur STM32F334C8T6.



Convertisseur de photos



Le résultat du travail pour ceux qui ne veulent pas lire le mur de texte


Dans le cadre de cet article, je parlerai brièvement de l'implémentation matérielle du convertisseur et de la façon d'implémenter un système de contrôle pour différents modes de fonctionnement. Intéressant? Alors c'est parti ...



1. Brièvement sur le fonctionnement de la topologie buck-boost



: 2 2 , .. , 2 (4 ). , . :



Structure Buck-boost



, : 2 ( 2 , ), 4 , . 1 2 (OCP) . 2 ? , , .



, , , STM32F334, STM32G474, XMC4108, TMS320F28027 , .. : HRPWM, , , . , , , . , , , (OCP) , , .



… buck-boost :



Circuit buck-boost équivalent



buck () boost (), — 3 buck-, L1C3 LC-. 3 boost-, . , buck-, boost-. .



buck:



Vout=VinD



boost:



Vout=Vin(1D)



, buck- boost :



Voutboost=VinbuckDbuck1Dboost



buck-boost 3- : ( PWM-BUCK PWM-BOOST). , .



, . , 8, Dboost 70%, Dbuck 50%. :



Voutboost=VinbuckDbuck1Dboost=8V0,510,7=13,33V



, 8 . , , , 2 - :



Graphique de l'oscilloscope



. (duty) 2- . duty, .



2. .



2 , : . , , CC/CV . :



Schéma fonctionnel de contrôle



CC CV , : REF , , ; , , , , .



-, , " " . "" (REF), , , 10. , buck-boost , (duty). - . , .



:

error=VreferenceVout



Qu'est-ce que cela nous donne? Et maintenant, nous savons à quel point la valeur réelle de la tension de sortie s'est écartée de la valeur de consigne ( REF ). Cela nous permet de comprendre s'il est nécessaire de «donner une commande» pour augmenter ou diminuer la tension. Par exemple, dans la topologie abaisseur , pour augmenter la tension, vous devez augmenter la charge du transistor supérieur et pour diminuer la tension, réduire le remplissage en conséquence. Pour la topologie de boost , au contraire, et pour le buck-boost, il y a 2 signaux, et ici c'est déjà plus difficile - il faut équilibrer, mais je pense qu'en moyenne l'idée est claire, pour plus de clarté je vais donner un pseudo-code pour contrôler le buck :

//      -
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) , , . :



error=jereFerence-jeout



, 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:





...



lamerok veydlin, (, , ), !



, : https://t.me/proHardware. , , , , , .



, . buck-boost-, , , - , .




All Articles