Bench Power Supply

0-25v @ 0-4Amp

 

History

This project is like the one that all of you must have done in electronics.  I took the idea from Circuit Cellar. The original power supply provides an output of 2.5-15V at 500mA. This circuit will provide 0-25V at 0 to 4A. You will see there is a lot of modification to achieve this.

    I will explain you some part of this power supply.  First you must find a transformer which can handle 30VAC at 5A.  Q2 and Q5 will pre-regulate your DC with ripple and noise to a clean 30V DC. We must have a clean DC to have good measure of the current. The Amplifier is not too far from the absolute maximum rating. You can use Voltage transformer from 30VAC to 37VAC. The ZXCT1001 will measure the current. This part is placed before the adjustable regulator because it can't work with voltage lower then 3V.

"we want adjustable current from 0 to 4amp", Q1 and Q4 is the final adjustable regulator from 0 to 25V DC. U1B Op-Amp limits the current set by R15, U1B will adjust the output voltage set by R12. R8 and R14 must be adjusted to set the maximum current output and voltage. JP1 will send the set point of voltage and current plus the current value of the current and voltage. Also you need a big heat sink with a fan to cool down the power dissipating from all of the mosfet.

    I also connect to this power supply a LCD to inform you of the set point for voltage and current, plus the current voltage and current.  It's done with a small ATMega32 with 4 A/D input to received the value from the power supply and with some simple calculation it display those value.

 

Features

puce Output Voltage adjustable from 0 to 25v
puce Output Current adjustable from 0 to 4amp
puce Digital reading of set points for current & voltage and output current & voltage.
puce No need of multi tap transformer or center tap transformer
puce Short circuit protected
puce Very low cost

 

Pictures

Click to enlarge

Power supply side view

Power supply front view

 

Power supply PCB view

Power supply front view

 

LCD Display

Power supply top view

 

Sources codes & Schematics

-Schematic of the powersupply  in PDF format

-Schematic of the digital volt & amp reading  in PDF format

-Printed Circuit Board of this power supply!!!!

-Circuit cellar inspiration article  in PDF format

 

//*****************************************************************************
//
Powersupply
// Version 1.0 Jan 2007
//
// 1.0 -> -Everything is new
//
// Sylvain Bissonnette
//*****************************************************************************
// Editor : UltraEdit32
//*****************************************************************************
//
//                    R E T U R N   S T A C K   6 4
//                    Internal RC oscillator of 8Mhz
//                   
//*****************************************************************************
//
//                          F U S E   B I T
//
//( )7      ( )6     ( )BL12 ( )BL11  ( )BL02   ( )BL01    ( )Lock2   ( )Lock1
//( )7      ( )6     ( )     ( )      ( )       ( )M103C   ( )WDTON   ( )
//( )OCDEN  ( )JTAGE (X)SPIEN(X)CKOPT (X)EESAVE ( )BOOTSZ1 (X)BOOTSZ0 (X)BOOTRST
//(X)BODLEV (X)BODEN ( )SUT1 (X)SUT0  ( )CKSEL3 (X)CKSEL2  ( )CKSEL1  ( )CKSEL0
//
//*****************************************************************************
//                          P I N   U S A G E
//
// PA0 -> GND
// PA1 -> ADC Input #1
// PA2 -> ADC Input #2
// PA3 -> ADC Input #3
// PA4 -> ADC Input #4
// PA5 -> GND
// PA6 -> GND
// PA7 -> GND
//
// PB0 -> N/C
// PB1 -> N/C
// PB2 -> N/C
// PB3 -> N/C
// PB4 -> N/C
// PB5 -> N/C
// PB6 -> N/C
// PB7 -> N/C
//
// PC0 -> LCD DB7
// PC1 -> LCD DB6
// PC2 -> LCD DB5
// PC3 -> LCD DB4
// PC4 -> LCD E
// PC5 -> LCD R/W
// PC6 -> LCD RS
// PC7 -> LCD BackLight
//
// PD0 -> N/C
// PD1 -> N/C
// PD2 -> +5
// PD3 -> LED
// PD4 -> N/C
// PD5 -> N/C
// PD6 -> N/C
// PD7 -> LCD Contrast
//
//*****************************************************************************
//                        T I M E R   U S A G E
//
// Timer 0 not use
// Timer 1 not use
// Timer 2 is use for LCD Contrast
// Timer 3 not use
//
//*****************************************************************************

//*****************************************************************************
//                            I N C L U D E
//*****************************************************************************
#include <iom32v.h>
#include <shortnametype.h>
#include <macros.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <eeprom.h>

//*****************************************************************************
//                            D E F I N E
//*****************************************************************************
#define VERSION                 10
#define TRUE                    1
#define FALSE                   0
#define XTAL                    16000000
#define LED                               (1<<PD3);

// ADC
#define ADC2                              (1<<REFS0) + 2
#define ADC3                              (1<<REFS0) + 3
#define ADC4                              (1<<REFS0) + 4
#define ADC5                              (1<<REFS0) + 5

// LCD
#define LCD_D7                  0x01
#define LCD_D6                  0x02
#define LCD_D5                  0x04
#define LCD_D4                  0x08
#define LCD_E                   0x10
#define LCD_RW                  0x20
#define LCD_RS                  0x40
#define LCD_BACKLIGHT           0x80

#define LCD_PIN                 PINC
#define LCD_DDR                 DDRC
#define LCD_PORT                PORTC

#define LCD_DATA                0x01
#define LCD_CTRL                0x00

#define LCD_C_BLINK_ON          0x09
#define LCD_C_BLINK_OFF         0xfe
#define LCD_C_ON                0x0a
#define LCD_C_OFF               0xfd
#define LCD_DISPLAY_ON          0x0c
#define LCD_DISPLAY_OFF         0xfb
#define LCD_BRIGHT_25           0x23
#define LCD_BRIGHT_50           0x22
#define LCD_BRIGHT_75           0x21
#define LCD_BRIGHT_100          0x20
#define LCD_BACKLIGHT_ON        0x24
#define LCD_BACKLIGHT_OFF       0x25



//*****************************************************************************
//                            P R O T O T Y P E
//*****************************************************************************
void main(void);
void Info(void);
void Delay(ushort Del);

// A/D
void ADInit(void);
void AD_interrupt(void);

// LCD
void LCDInit(ushort x,ushort y);
void LCDOff(void);
void LCDClrSCR(void);
void LCDGotoXY(ushort,ushort);
ushort LCDWhereX(void);
ushort LCDWhereY(void);
void LCDWriteString(char *);
void LCDWriteConstString(const char *);
void LCDWriteChar(char);
void LCDWriteData(ushort,ushort);
ushort LCDReadData(ushort rs);
void LCDCreateCHR(ushort chnumber, char *ptr);
void LCDWait(void);
void LCDDelay50us(int Delay);
void LCDTextAttr(ushort attribute);
void LCDContrast(ushort Cont);

//*****************************************************************************
//                      G L O B A L   V A R I A B L E
//*****************************************************************************

// LCD
ushort MaxX, MaxY, LCDStat;
char Text[20];

// ADC
int AD1;
int AD2;
int AD3;
int AD4;

//*****************************************************************************
//                      M A I N
//*****************************************************************************
void main()
{
   float VoltSet,Volt,CurrentSet,Current;

  WDR();
  WDTCR = 0x0f; // Watch Dog enable
  LCDInit(20,2);
  ADInit();
  DDRD |= LED;

  SEI(); //re-enable interrupts

  Info();
  Delay(75);
  LCDClrSCR();
   LCDGotoXY(1,1);
   LCDWriteConstString("Vset:      Vout:\0");
   LCDGotoXY(1,2);
   LCDWriteConstString("Aset:      Aout:\0");

  while(1)
  {
    WDR();
    _StackCheck();
    PORTD ^= LED;

    VoltSet =    (((float)(AD2)) * 25) / 1024;
    Volt =       (((float)(AD1)) * 25) / 1024;
    CurrentSet = (((float)(AD4)) * 4) / 1024;
    Current =    (((float)(AD3)) * 4) / 1024;

    LCDGotoXY(6,1);
    csprintf(&Text[0],"%#4.1f\0",VoltSet);
      LCDWriteString(&Text[0]);

      LCDGotoXY(17,1);
      csprintf(&Text[0],"%#4.1f\0",Volt);
      LCDWriteString(&Text[0]);

      LCDGotoXY(6,2);
    csprintf(&Text[0],"%#4.1f\0",CurrentSet);
      LCDWriteString(&Text[0]);

      LCDGotoXY(17,2);
      csprintf(&Text[0],"%#4.1f\0",Current);
      LCDWriteString(&Text[0]);

    Delay(5);
  }
}

/******************************************************************************

Name:         void _StackOverflowed(char c)

Description:  This function is automaticaly called if
              the stack crash/


Input:        none

Output:       none

Misc:
******************************************************************************/
void _StackOverflowed(char c)
{
  while(TRUE);
}

/*****************************************************************************

Name:         void Info(void)

Description:  Display power on message

Input:        void

Output:       void

Misc:        

******************************************************************************/
void Info(void)
{
  LCDClrSCR();
  LCDGotoXY(1,1);
  LCDWriteConstString("PowerSupply  Ver:1.0\0");
  LCDGotoXY(1,2);
  LCDWriteConstString("Sylvain  Bissonnette\0");
}

/******************************************************************************

Name:         void Delay(ushort Del)

Description:  This function make a delay

Input:        none

Output:       none

Misc:
******************************************************************************/
void Delay(ushort Del)
{
  int i,j;
  for (i=0;i<Del;i++) for (j=0;j<32000;j++) WDR();
}

/******************************************************************************

Name:         ADCInit(void)

Description:  This function initialize the ADC

Input:        none

Output:       none

Misc:
******************************************************************************/
void ADInit(void)
{
   ADCSRA = (1<<ADEN) + (1<<ADIE) + (1<<ADPS2) + (1<<ADPS1) + (1<<ADPS0);
  ADMUX = ADC2;

  ADCSRA |= (1<<ADSC);      // Start AD convertion
}

/******************************************************************************

Name:         AD_interrupt(void)

Description:  This function is automaticaly called when the AD had finish
              is convertion

Input:        none

Output:       none

Misc:
******************************************************************************/
#pragma interrupt_handler AD_interrupt:17
void AD_interrupt(void)
{

   if (ADMUX == ADC2)
   {
      AD1 = (int)((int)ADCH << 8) + ADCL;
      ADMUX = ADC3;
   }

   else if (ADMUX == ADC3)
   {
      AD2 = (int)((int)ADCH << 8) + ADCL;
      ADMUX = ADC4;
   }

   else if (ADMUX == ADC4)
   {
      AD3 = (int)((int)ADCH << 8) + ADCL;
      ADMUX = ADC5;
   }

   else if (ADMUX == ADC5)
   {
      AD4 = (int)((int)ADCH << 8) + ADCL;
      ADMUX = ADC2;
   }

   ADCSRA |= (1<<ADSC);      // Start AD convertion
}

//*****************************************************************************
// LCD Code
//*****************************************************************************
/******************************************************************************

Name:         LCDCreateCHR

Description:  Create a new char in CGRAM

Input:        ushort  : Character number (0-7)
              *ushort : 7 ushort containing the data

Output:       none

Misc:

******************************************************************************/
void LCDCreateCHR(ushort chnumber, char *ptr)
{
  ushort i,j;

  i = 8 * chnumber;

  for (j=0;j<8;j++)
  {
    LCDWriteData(LCD_CTRL,(0x40 | (i + j)));
    LCDWriteData(LCD_DATA,ptr[j]);
  }
}


/******************************************************************************

Name:         void LCDClrSCR(void)

Description:  Clear the LCD

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDClrSCR(void)
{
  LCDWait();
  LCDWriteData(LCD_CTRL,0x01);      // Clear display
}

/******************************************************************************

Name:         LCDGotoXY(ushort x, ushort y)

Description:  Position cursor on the LCD at X & Y location

Input:        X -> X position on the LCD
              Y -> Y position on the LCD

Output:       none

Misc:

******************************************************************************/
void LCDGotoXY(ushort x,ushort y)
{
  ushort address;

  x--;

  if (MaxY < 3)
  {
    switch(y)
    {
      case '\x01' :
      address = 0 + x;
      break;
      case '\x02' :
      address = 64 + x;
      break;
    }
  }
  else
  {
    switch(y)
    {
      case '\x01' :
      address = 0 + x;
      break;
      case '\x02' :
      address = 64 + x;
      break;
      case '\x03' :
      address = 20 + x;
      break;
      case '\x04' :
      address = 84 + x;
      break;
    }
  }
  LCDWriteData(LCD_CTRL,address | 0x80);
}

/******************************************************************************

Name:         LCDWhereX

Description:  Get the x position of the cursor on the LCD

Input:        None

Output:       ushort : Cursor position "x"

Misc:

******************************************************************************/
ushort LCDWhereX(void)
{
ushort i,x,y;

i = LCDReadData(LCD_CTRL) & 0x7f;

y = LCDWhereY();

if (MaxY == 2)
    {
    if (y == 1) x = i;
    if (y == 2) x = i - 0x40;
    }
else if (MaxY == 4)
    {
    if (y == 1) x = i;
    if (y == 2) x = i - 0x40;
    if (y == 3) x = i - 0x14;
    if (y == 4) x = i - 0x54;
    }
x = x + 1;
return x;
}

/******************************************************************************

Name:         LCDWhereY

Description:  Get the y position of the cursor on the LCD

Input:        None

Output:       ushort : Cursor position "y"

Misc:

******************************************************************************/
ushort LCDWhereY(void)
{
  ushort i,j;

  i = LCDReadData(LCD_CTRL) & 0x7f;

  if (MaxY == 2)
  {
    if (i < 0x28) j = 1;
    else j = 2;
  }
  else if (MaxY == 4)
  {
    if ((i >0x00) && (i < 0x15)) j = 1;
    if ((i >0x14) && (i < 0x28)) j = 3;
    if ((i >0x40) && (i < 0x55)) j = 2;
    if ((i >0x54) && (i < 0x68)) j = 4;
  }
  return j;
}

/******************************************************************************

Name:         WtireByteLCD(char byte)

Description:  Write a byte on the LCD at cursor position

Input:        byte

Output:       none

Misc:

******************************************************************************/
void LCDWriteChar(char byte)
{
  char tmp;

  tmp = byte & 0xf0;
  tmp = tmp >> 4;
  tmp += 0x30;
  if (tmp > 0x39) tmp += 0x07;
  LCDWriteData(LCD_DATA,tmp);

  tmp = byte & 0x0f;
  tmp += 0x30;
  if (tmp > 0x39) tmp += 0x07;
  LCDWriteData(LCD_DATA,tmp);
}

/******************************************************************************

Name:         void LCDWriteString(char *ptr)

Description:  Write a string from RAM on the LCD

Input:        string pointer

Output:       none

Misc:

******************************************************************************/
void LCDWriteString(char *ptr)
{
  ushort i;

  for (i=1;i<41;i++)
  {
    if (*ptr == 0x00) break;
    LCDWriteData(LCD_DATA,*ptr++);
  }
}

/******************************************************************************

Name:         void LCDWriteConstString(const char *ptr)

Description:  Write a constant string on the LCD

Input:        string pointer

Output:       none

Misc:

******************************************************************************/
void LCDWriteConstString(const char *ptr)
{
  ushort i;

  for (i=1;i<41;i++)
  {
    if (*ptr == 0x00) break;
    else if (i == 21) LCDGotoXY(1,2);
    LCDWriteData(LCD_DATA,*ptr++);
  }
}

/******************************************************************************

Name:         void LCDWriteData(ushort rs, ushort ch)

Description:  Write a byte in rs of the LCD

Input:        rs -> Register select
              ch -> byte to write

Output:       none

Misc:

******************************************************************************/
void LCDWriteData(ushort rs,ushort ch)
{
  ushort Stat;

  Stat = LCD_PIN & LCD_BACKLIGHT;

  LCD_PORT = Stat;

  LCDWait();

  if ((ch & 0x80) == 0x80) LCD_PORT |= LCD_D7;
  if ((ch & 0x40) == 0x40) LCD_PORT |= LCD_D6;
  if ((ch & 0x20) == 0x20) LCD_PORT |= LCD_D5;
  if ((ch & 0x10) == 0x10) LCD_PORT |= LCD_D4;
  if (rs == 1) LCD_PORT |= LCD_RS;
   LCDDelay50us(1);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;

  LCD_PORT = Stat;
  if ((ch & 0x08) == 0x08) LCD_PORT |= LCD_D7;
  if ((ch & 0x04) == 0x04) LCD_PORT |= LCD_D6;
  if ((ch & 0x02) == 0x02) LCD_PORT |= LCD_D5;
  if ((ch & 0x01) == 0x01) LCD_PORT |= LCD_D4;
  if (rs == 1) LCD_PORT |= LCD_RS;
   LCDDelay50us(1);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;
}

/******************************************************************************

Name:         ushort LCDRead(ushort rs)

Description:  read a byte in rs of the LCD

Input:        rs -> Register select

Output:       ushort

Misc:    

******************************************************************************/
ushort LCDReadData(ushort rs)
{
  ushort Byte=0;

  LCD_DDR &= ~(LCD_D7 + LCD_D6 + LCD_D5 + LCD_D4);

  LCD_PORT = LCD_PIN & LCD_BACKLIGHT;
  LCD_PORT |= LCD_RW;
  if (rs == 1) LCD_PORT |= LCD_RS;
  LCDDelay50us(1);

  LCD_PORT |= LCD_E;
  LCD_PORT |= LCD_E;
  if (LCD_PIN & LCD_D7) Byte |= 0x80;
  if (LCD_PIN & LCD_D6) Byte |= 0x40;
  if (LCD_PIN & LCD_D5) Byte |= 0x20;
  if (LCD_PIN & LCD_D4) Byte |= 0x10;
  LCD_PORT &= ~LCD_E;

  LCD_PORT |= LCD_E;
  LCD_PORT |= LCD_E;
  if (LCD_PIN & LCD_D7) Byte |= 0x08;
  if (LCD_PIN & LCD_D6) Byte |= 0x04;
  if (LCD_PIN & LCD_D5) Byte |= 0x02;
  if (LCD_PIN & LCD_D4) Byte |= 0x01;
  LCD_PORT &= ~LCD_E;

  LCD_PORT &= ~LCD_RW;

  LCD_DDR |= LCD_D7 + LCD_D6 + LCD_D5 + LCD_D4;

  return (Byte);
}

/******************************************************************************

Name:         void LCDWait(void)

Description:  wait for the LCD to be ready

Input:        none

Output:       none

Misc:    

******************************************************************************/
void LCDWait(void)
{
  while((LCDReadData(0) & 0x80) == 0x80) WDR();
}

/******************************************************************************

Name:         void LCDDelay50us(int Delay)

Description:  Delay of 50 us with a 1Mhz resonator

Input:        Delay X x 50us

Output:       none

Misc:

******************************************************************************/
void LCDDelay50us(int Delay)
{
  int i,j;

  for (i=0;i<Delay;i++)
  {
    for (j=1;j<120;j++);
    asm("WDR");
  }
}

/******************************************************************************

Name:         void LCDTextAttr(ushort Attribute)

Description:  Set the LCD attribute

Input:        LCD_C_BLINK_ON     : Cursor blink on
              LCD_C_BLINK_OFF    : Cursor blink off
              LCD_C_ON           : Cursor on
              LCD_C_OFF          : Cursor off
              LCD_DISPLAY_ON     : Display ON
              LCD_DISPLAY_OFF    : Display OFF
              LCD_BRIGHT_25      : VFD 25% Bright
              LCD_BRIGHT_50      : VFD 50% Bright
              LCD_BRIGHT_75      : VFD 75% Bright
              LCD_BRIGHT_100     : VFD 100% Bright
              LCD_BACK_LIGHT_ON  : Back Light ON
              LCD_BACK_LIGHT_OFF : Back Light OFF

Output:       none

Misc:

******************************************************************************/
void LCDTextAttr(ushort attribute)
{
switch (attribute)
    {
    case LCD_C_BLINK_ON:
         LCDStat |= LCD_C_BLINK_ON;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_C_BLINK_OFF:
         LCDStat &= LCD_C_BLINK_OFF;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_C_ON:
         LCDStat |= LCD_C_ON;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_C_OFF:
         LCDStat &= LCD_C_OFF;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_DISPLAY_ON:
         LCDStat |= LCD_DISPLAY_ON;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_DISPLAY_OFF:
         LCDStat &= LCD_DISPLAY_OFF;
         LCDWriteData(LCD_CTRL,LCDStat);
         break;

    case LCD_BRIGHT_25:
         LCDWriteData(LCD_CTRL,0x20);
         LCDWriteData(LCD_DATA,0x03);
         break;

    case LCD_BRIGHT_50:
         LCDWriteData(LCD_CTRL,0x20);
         LCDWriteData(LCD_DATA,0x02);
         break;

    case LCD_BRIGHT_75:
         LCDWriteData(LCD_CTRL,0x20);
         LCDWriteData(LCD_DATA,0x01);
         break;

    case LCD_BRIGHT_100:
         LCDWriteData(LCD_CTRL,0x20);
         LCDWriteData(LCD_DATA,0x00);
         break;

    case LCD_BACKLIGHT_ON:
         LCD_PORT |= LCD_BACKLIGHT;
         break;

    case LCD_BACKLIGHT_OFF:
         LCD_PORT &= ~(LCD_BACKLIGHT);
         break;
    }
}

/******************************************************************************

Name:         void LCDOn(ushort X, ushort Y)

Description:  Initialize LCD in 4bit mode

Input:        ushort X -> X size
              ushort Y -> Y size

Output:       none

Misc:

******************************************************************************/
void LCDInit(ushort X, ushort Y)
{
  MaxX = X;
  MaxY = Y;
  LCDStat = 0x0c;
  LCD_PORT = 0x00;
  LCD_DDR = LCD_D7+LCD_D6+LCD_D5+LCD_D4+LCD_E+LCD_RS+LCD_RW+LCD_BACKLIGHT;
  LCD_PORT = ~(LCD_D7+LCD_D6+LCD_D5+LCD_D4+LCD_E+LCD_RS+LCD_RW);
  LCD_PORT |= LCD_BACKLIGHT;
  LCDDelay50us(340);

  LCD_PORT = (LCD_D5 + LCD_D4 + LCD_BACKLIGHT);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;
  LCDDelay50us(100);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;
  LCDDelay50us(100);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;
  LCDDelay50us(100);

  LCD_PORT = (LCD_D5 + LCD_BACKLIGHT);
  LCD_PORT |= LCD_E;
  LCD_PORT &= ~LCD_E;
  LCDDelay50us(100);

  if (Y == 1) LCDWriteData(LCD_CTRL,0x20);    // 1 line
  else LCDWriteData(LCD_CTRL,0x28);           // 2 line

  LCDWriteData(LCD_CTRL,0x0c);                // Disp ON-Cur OFF-Blink OFF
  LCDWriteData(LCD_CTRL,0x01);                // Clear display
  LCDDelay50us(50);
  LCDWriteData(LCD_CTRL,0x06);                // Cursor INC Shift OFF

  DDRD |= 0x80;
  TCCR2 = 0x79;
  OCR2 = 0xf0;
}

/******************************************************************************

Name:         void LCDContrast(ushort Cont)

Description:  Set the LCD Contrast

Input:        from 0 to 255

Output:       none

Misc:

******************************************************************************/
void LCDContrast(ushort Cont)
{
  OCR2 = Cont;
}

/******************************************************************************

Name:         void LCDOff(void)

Description:  Shut down LCD

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDOff(void)
{
 LCD_DDR = 0xff;
 LCD_PORT = 0x00;
 DDRD &= ~0x80;
}