Buck Boost Digital Switching Power Supply

Buck Boost Digital Switching Power Supply



This project was my collaborative final year project with another Electronic engineering group at GIKI. Circuit design, Arduino programming and prototyping were all done by me. They intended to use this type of supply to charge a lead acid battery with a solar panel and increase the efficiency of the solar panel by concentrating the sunlight on the panel and water cooling it to prevent heat damage. Their copy of the project contained a simple 16x2 LCD and 4x4 keypad. They got the highest grade (A) for this project.






This is a digital switching power supply controlled by Arduino. There is not even a single push button, hardware keypad, potentiometer, rotary encoder or any other input device except than the touchscreen to control the power supply. The power supply is equipped with a 3.5 inch color TFT LCD with resistive touch panel.

Buck-Boost Converter


A Buck-Boost converter is a type of switched mode power supply which combines the principles of the Buck Converter and the Boost converter in a single circuit.

Block Diagram






Working Principle


Operation as a Buck Converter



In this mode SW2 is turned off, and SW1 is switched ON and OFF by a high frequency square wave from the control unit. When the gate of SW1 is high, current flows though L, charging its magnetic field, charging C and supplying the load. The Schottky diode D1 is turned off due to the positive voltage on its cathode.

When the control unit switches SW1 OFF, the initial source of current is now the inductor L. Its magnetic field is collapsing, the back e.m.f. generated by the collapsing field reverses the polarity of the voltage across L, which turns on D1 and current flows through D2 and the load.

As the current due to the discharge of L decreases, the charge accumulated in C during the ON period of SW1 now also adds to the current flowing through the load, keeping Vout reasonably constant during the OFF period. This helps keep the ripple amplitude to a minimum and keeps the Vout at a constant level during the whole ON/OFF cycle.

Operation as a Boost Converter


In Boost Converter mode, SW1 is turned on continually and the high frequency square wave applied to SW2 gate. During the ON periods when SW2 is conducting, the input current flows through the inductor L and via SW2, directly back to the supply negative terminal charging up the magnetic field around L. Whilst this is happening D2 cannot conduct as its anode is being held at ground potential by the heavily conducting SW2. For the duration of the ON period, the load is being supplied entirely by the charge on the capacitor C, built up on previous oscillator cycles. The gradual discharge of C during the ON period (and its subsequent recharging) accounts for the amount of high frequency ripple on the output voltage, which is at a potential of approximately Vin + VL.

The OFF Period

At the start of the OFF period of SW2, L is charged and C is partially discharged. The inductor L now generates a back e.m.f. whose value depends on the rate of change of current as SW2 switches OFF/ON and the inductance value; therefore the back e.m.f can be any voltage over a wide range, depending on the design of the circuit. Notice particularly that the polarity of the voltage across L has now reversed, and so adds to the input voltage Vin giving an output voltage that is at least equal to or greater than the input voltage. D2 is now forward biased and so the circuit current supplies the load current, and at the same time re-charges the capacitor to Vin + VL ready for the next ON period of SW2.


Implementation








We used two MOSFETs (stp80nf70 ) as the switches SW1 and SW2 which are driven by PWM signals from Arduino. As stp80nf70 MOSFETs require a full turn ON voltage of 15V which can not be supplied by Arduino so a level shifter circuit per MOSFET is used. The level shifter shifts the  0/5V level to 0/Vcc or 0/15v in a typical case but it can work as low as Vcc=4V according to datasheet.



The output voltage of the buck boost coverter is reduced by a series resistor divider network which is read by Arduino's ADC and the PWMs are adjusted by two software PID controllers implemented in Arduino to keep the output voltage equal or near to the set voltage. Thus a closed loop system is implemented.One PID controller controls buck mode while the other controls the boost mode. The 5.1V zener diode protects the Arduino from damage if in case the voltage goes higher than 5.1V.


Graphical User Interface (GUI)


The main screen shows a graphical user interface with three parameters i.e set voltage, real voltage (output voltage) and input voltage. The "Set VOUT" button takes the user to the keypad screen where the output voltage can be entered.




Keypad





The required output voltage can be entered through an on screen keypad with touch input. The output voltage can be set from 0-32V while the input voltage can be anywhere from 6-30V.

If the output voltage higher than 32V is entered, the screen displays an error messsage. The output voltage can be set to lower,equal or higher than the input voltage.


Output Terminals


The load can be connected to the two binding posts at the front of the power supply. Red is for positive voltage while black is for ground.

Uses/Applications


This power supply has more applications than a typical power supply because its voltage can be lower than, equal to or higher than the input voltage. Following are some of the applications

1) It can be used to charge batteries with solar panels. As the sunlight brightness changes, the solar panel voltage can go lower or higher than the battery charging voltage, therefore, this power supply can be used to keep the charging voltage constant at a constant value.

2) It can be used to supply 9V/12V or higher voltages to different electronics items like wifi routers , laptops etc from a 6V lead acid battery or a 7.2V Li-ion battery.

3) The circuit can be used to provide different voltage levels in a circuit from a single supply.


Future Enhancements




1) The microcontroller can be upgraded to an ARM processor which typically has 72 MHz or higher clock and built in hardware LCD controller. This will increase the refresh rate of the LCD which is awfully slow in Arduino.


2) Dedicated switch mode power supply ICs like TL494, LTC3789, LM5118 can be used to reduce the ripple voltage and decrease inductor/capacitor size due to their high PWM frequencies. Also the response time will improve due to hardware implementation (op-amps) of voltage regulation.


3) The efficiency will also improve by using dedicated ICs.


Video of Final Working Product





Arduino Code



#include <UTFT.h>
#include <UTouch.h>


int state=1;


UTFT    myGLCD(ILI9327,38,39,40,41);
UTouch  myTouch( 6, 5, 9, 3, 2);

// Declare which fonts we will be using
extern uint8_t arial_italic[];
extern uint8_t Inconsola[];
extern uint8_t hallfetica_normal[];
//extern uint8_t SevenSegNumFont[];
//extern uint8_t SevenSegmentFull[];
extern uint8_t GroteskBold32x64[];
extern uint8_t nadianne[];
//extern uint8_t swiss721_outline[];
extern uint8_t arial_bold[];
//extern uint8_t DotMatrix_M_Slash[];

int x, y;
char stCurrent[20]="";
int stCurrentLen=0;
char stLast[20]="";

//*********************switching global********************************
#include
//int buckPin=5;
int buckPin=4;
//int boostPin=6;
int boostPin=13;
int boostLimit=230;
int numReadings=10;

double vin=0;

//buckPID variables
double vref=8;
double vout, buckPWM;
int voutRealDisplayCount=60;
int vinDisplayCount=100;
boolean switchToBuck=false;

//boostPID variables
double boostPWM;


//Specify the links and initial tuning parameters
//PID buckPID(&amp;vout, &amp;buckPWM, &amp;vref,2,5,1, DIRECT);
PID buckPID(&amp;vout, &amp;buckPWM, &amp;vref,3,30,0.5, DIRECT);
//PID boostPID(&amp;vout, &amp;boostPWM, &amp;vref,2,5,1, DIRECT);
PID boostPID(&amp;vout, &amp;boostPWM, &amp;vref,3,20,0.5, DIRECT);

//*********************end switching global********************************

/*************************
 **   Custom functions   **
 *************************/
void drawSetVoltageButton(){
    myGLCD.setColor(204, 204, 153);
    myGLCD.setBackColor(204, 204, 153);
    myGLCD.fillRoundRect (220,120,360,184);//x1,y1,x2,y2
    myGLCD.setColor(255,255,255);
    //myGLCD.drawRoundRect (10+(x*60), 10, 60+(x*60), 60);
    myGLCD.setFont(arial_bold);
    myGLCD.print("Set VOUT",225 ,150);
}


void drawButtons()
{
  // Draw the upper row of buttons
  for (x=0; x<5 data-blogger-escaped-div="" data-blogger-escaped-x="">
  {
    myGLCD.setColor(0, 0, 255);
    myGLCD.fillRoundRect (10+(x*60), 10, 60+(x*60), 60);
    myGLCD.setColor(255, 255, 255);
    myGLCD.drawRoundRect (10+(x*60), 10, 60+(x*60), 60);
    myGLCD.printNumI(x+1, 27+(x*60), 27);
  }
  // Draw the center row of buttons
  for (x=0; x<6 data-blogger-escaped-div="" data-blogger-escaped-x="">
  {
    myGLCD.setColor(0, 0, 255);
    myGLCD.fillRoundRect (10+(x*60), 70, 60+(x*60), 120);
    myGLCD.setColor(255, 255, 255);
    myGLCD.drawRoundRect (10+(x*60), 70, 60+(x*60), 120);
    if (x<4 data-blogger-escaped-div="">
      myGLCD.printNumI(x+6, 27+(x*60), 87);
  }
  myGLCD.print("0", 267, 87);
  myGLCD.print(".", 327, 87);
  // Draw the lower row of buttons
  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (10, 130, 150, 180);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (10, 130, 150, 180);
  myGLCD.print("Clear", 40, 147);
  myGLCD.setColor(0, 0, 255);
  myGLCD.fillRoundRect (160, 130, 300, 180);
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (160, 130, 300, 180);
  myGLCD.print("Enter", 190, 147);
  myGLCD.setBackColor (0, 0, 0);
}

void updateStr(int val)
{
  if (stCurrentLen<20 data-blogger-escaped-div="">
  {
    stCurrent[stCurrentLen]=val;
    stCurrent[stCurrentLen+1]='\0';
    stCurrentLen++;
    myGLCD.setColor(0, 0, 0);
    //myGLCD.print(stCurrent, CENTER, 224);
    myGLCD.print(stCurrent, CENTER, 200);
  }
  else
  {
    myGLCD.setColor(255, 0, 0);
    myGLCD.print("BUFFER FULL!", CENTER, 192);
    delay(500);
    myGLCD.print("            ", CENTER, 192);
    delay(500);
    myGLCD.print("BUFFER FULL!", CENTER, 192);
    delay(500);
    myGLCD.print("            ", CENTER, 192);
    myGLCD.setColor(0, 255, 0);
  }
}

// Draw a red frame while a button is touched
void waitForIt(int x1, int y1, int x2, int y2)
{
  myGLCD.setColor(255, 0, 0);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
  while (myTouch.dataAvailable())
    myTouch.read();
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawRoundRect (x1, y1, x2, y2);
}

/*************************
 **  Required functions  **
 *************************/
void mainScreenDraw()//state=1
{
  myGLCD.clrScr();
  //myGLCD.fillScr(134,237,38);light green
  myGLCD.fillScr(239,233,242);//light grey
  drawSetVoltageButton();
  
  myGLCD.setBackColor(239,233,242);//light grey
  myGLCD.setColor(210, 100, 40);//light red
  myGLCD.setFont(arial_bold);
  myGLCD.print("Buck Boost Chopper Supply",LEFT,220);
  
  myGLCD.setFont(arial_bold);
  myGLCD.setColor(255,0,0);// red
  myGLCD.print("VOUT set",40,20);//for 1st voltage
  
  myGLCD.setColor(0,255,0);//light green
  myGLCD.print("VOUT real",240,20);//for 2nd voltage
  
  myGLCD.setColor(0, 0, 255);//blue
  myGLCD.print("VIN",65,190);//for 3rd voltage
  
  //VOUT set
  myGLCD.setFont(GroteskBold32x64);
  myGLCD.setColor(255,0,0);// red
  myGLCD.printNumF(vref,1,20,40);//1 decimal place, x=40, y=40, 46 = ".", 3 characters, 48= "0" (filler)
  
  myGLCD.setColor(255,0,0);// red
  myGLCD.print("V",160,40);//for 1st voltage
  
  myGLCD.setColor(0,255,0);//light green
  myGLCD.print("V",360,40);//for 2nd voltage
  
  myGLCD.setColor(0, 0, 255);//blue
  myGLCD.print("V",160,120);//for 3rd voltage
  
  //display VIN
  myGLCD.setColor(0, 0, 255);//blue
  myGLCD.printNumF(vin,1,20,120);//1 decimal place, x=40, y=40, 46 = ".", 3 characters, 48= "0" (filler)
  
  state=2;
  
}//end mainScreenDraw()
  
void inputScreenDraw()//state=3
{
  myGLCD.clrScr();
  myGLCD.fillScr(239,233,242);
  myGLCD.setFont(nadianne);
  myGLCD.setBackColor(0, 0, 255);
  drawButtons();  
  //myGLCD.setFont(Inconsola);
  myGLCD.setBackColor(239,233,242);

  state=4;
  
}//end inputScreenDraw()

void regulate()
{
  if (Serial.available() &gt; 0) {

    double vol = Serial.parseFloat();
    Serial.println(vol);
    vref=vol;
    }
    
  vout=0;
  for(int i=0;i
  // read the input on analog pin 0:
  vout = vout + analogRead(A1);
                      }
  vout=vout/numReadings;
  vout=vout*0.0493;
  //Input=Input*0.0229;
  Serial.print(vout);
  Serial.println(" V");
  
  if(buckPWM<255 data-blogger-escaped-amp="" data-blogger-escaped-boostpwm="=0" data-blogger-escaped-switchtobuck="=true){</div">
  switchToBuck=false;
  buckPID.Compute();
  analogWrite(buckPin,buckPWM);
                  }
  else{
  boostPID.Compute();
  //if(boostPWM &lt; boostLimit)
   boostPWM = map(boostPWM, 0, 255, 0, 230);
   analogWrite(boostPin,boostPWM);
   
  if(boostPWM==0)
   switchToBuck=true;
       }
                  
    
  Serial.print("buck pwm: ");
  Serial.println(buckPWM);
  
  Serial.print("boost pwm: ");
  Serial.println(boostPWM);
}

void setup()
{
  Serial.begin(9600);
  
  //*********************switching setup********************************
  TCCR0B = TCCR0B &amp; B11111000 | B00000010;    // set timer 0 divisor to     8 for PWM frequency of  7812.50 Hz
  analogWrite(buckPin,0);
  analogWrite(boostPin,0);
  vout=0;
  for(int i=0;i
  vout = vout + analogRead(A1);
                      }
  vout=vout/numReadings;
  vout=vout*0.0493;
  Serial.print(vout);
  Serial.println(" V");

  buckPID.SetMode(AUTOMATIC);
  boostPID.SetMode(AUTOMATIC);
  
  //*********************end switching setup********************************
  
  myGLCD.InitLCD();

  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  
  mainScreenDraw();
  

}

void loop()
{
  if(state==1)
    mainScreenDraw();
    
    
  else if(state==2)
  {
    regulate();
  if (myTouch.dataAvailable())
    {
      myTouch.read();
      x=myTouch.getX();
      y=myTouch.getY();
      
      if ((x&gt;=220) &amp;&amp; (x&lt;=360) &amp;&amp; (y&gt;=120) &amp;&amp; (y&lt;=184))  // Button: Set VOUT
        {
          Serial.println("key press");
          state=3;
        }
    }
   
   
  //VOUT real
  if(voutRealDisplayCount++==60)
  {
    myGLCD.setColor(0,255,0);//green
    myGLCD.printNumF(vout,1,220,40);//1 decimal place, x=40, y=40, 46 = ".", 3 characters, 48= "0" (filler)
    voutRealDisplayCount=0;
  }
  
  
  //VIN
  if(vinDisplayCount++==100)
  {
  
  vin=0;
  for(int i=0;i<5 data-blogger-escaped-div="" data-blogger-escaped-i="">
  vin=vin+analogRead(A7);
  vin=vin/5;
  vin=vin*0.0196;
  vinDisplayCount=0;
  
  myGLCD.setColor(0, 0, 255);//blue
  myGLCD.printNumF(vin,1,20,120);//1 decimal place, x=40, y=40, 46 = ".", 3 characters, 48= "0" (filler)
  }
  
  
  }//end of state 2
    
  
  else if (state==3)
  {
    inputScreenDraw();
  }//end of state 3

  
  else if (state==4)//input screen loop
  {
     regulate();
    if (myTouch.dataAvailable())
    {
      myTouch.read();
      x=myTouch.getX();
      y=myTouch.getY();

      if ((y&gt;=10) &amp;&amp; (y&lt;=60))  // Upper row
      {
        if ((x&gt;=10) &amp;&amp; (x&lt;=60))  // Button: 1
        {
          waitForIt(10, 10, 60, 60);
          updateStr('1');
        }
        if ((x&gt;=70) &amp;&amp; (x&lt;=120))  // Button: 2
        {
          waitForIt(70, 10, 120, 60);
          updateStr('2');
        }
        if ((x&gt;=130) &amp;&amp; (x&lt;=180))  // Button: 3
        {
          waitForIt(130, 10, 180, 60);
          updateStr('3');
        }
        if ((x&gt;=190) &amp;&amp; (x&lt;=240))  // Button: 4
        {
          waitForIt(190, 10, 240, 60);
          updateStr('4');
        }
        if ((x&gt;=250) &amp;&amp; (x&lt;=300))  // Button: 5
        {
          waitForIt(250, 10, 300, 60);
          updateStr('5');
        }
      }

      if ((y&gt;=70) &amp;&amp; (y&lt;=120))  // Center row
      {
        if ((x&gt;=10) &amp;&amp; (x&lt;=60))  // Button: 6
        {
          waitForIt(10, 70, 60, 120);
          updateStr('6');
        }
        if ((x&gt;=70) &amp;&amp; (x&lt;=120))  // Button: 7
        {
          waitForIt(70, 70, 120, 120);
          updateStr('7');
        }
        if ((x&gt;=130) &amp;&amp; (x&lt;=180))  // Button: 8
        {
          waitForIt(130, 70, 180, 120);
          updateStr('8');
        }
        if ((x&gt;=190) &amp;&amp; (x&lt;=240))  // Button: 9
        {
          waitForIt(190, 70, 240, 120);
          updateStr('9');
        }
        if ((x&gt;=250) &amp;&amp; (x&lt;=300))  // Button: 0
        {
          waitForIt(250, 70, 300, 120);
          updateStr('0');
        }
        if ((x&gt;=310) &amp;&amp; (x&lt;=360))  // Button: "."
        {
          waitForIt(310, 70, 360, 120);
          updateStr('.');
        }
      }

      if ((y&gt;=130) &amp;&amp; (y&lt;=180))  // Lower row
      {
        if ((x&gt;=10) &amp;&amp; (x&lt;=150))  // Button: Clear
        {
          waitForIt(10, 130, 150, 180);
          myGLCD.print("                    ", CENTER, 200);
          stCurrent[0]='\0';
          stCurrentLen=0;

        }
        if ((x&gt;=160) &amp;&amp; (x&lt;=300))  // Button: Enter
        {
          waitForIt(160, 130, 300, 180);
          if (stCurrentLen&gt;0)
          {
            double v=StrToFloat(stCurrent);
            Serial.println(v);
            stCurrent[0]='\0';
            stCurrentLen=0;
            if(v&gt;32)
            {
              myGLCD.print("                     ", LEFT, 192);
              myGLCD.print("                    ", CENTER, 200);
              myGLCD.setColor(255, 0, 0);
              myGLCD.print("Range is 0-&gt;32 V", LEFT, 192);
              delay(500);
              myGLCD.print("                     ", LEFT, 192);
              delay(500);
              myGLCD.print("Range is 0-&gt;32 V", LEFT, 192);
              delay(500);
              myGLCD.setColor(0, 255, 0); 
              myGLCD.print("                     ", LEFT, 192);
              myGLCD.print("                    ", CENTER, 200);
            }
            else
              {
              state=1;
              vref=v;
              }
            
          }
          else
          {
            myGLCD.setColor(255, 0, 0);
            myGLCD.print("Please Enter a value", LEFT, 192);
            delay(500);
            myGLCD.print("                     ", LEFT, 192);
            delay(500);
            myGLCD.print("Please Enter a value", LEFT, 192);
            delay(500);
            myGLCD.print("                     ", LEFT, 192);
            myGLCD.setColor(0, 255, 0);
          }
        }
      }
    }
  }//end  if (setVoltage==true)
}

float StrToFloat(String str){
  char carray[str.length() + 1]; //determine size of the array
  str.toCharArray(carray, sizeof(carray)); //put str into an array
  return atof(carray);
}




Comments