Category Archives: PSU Project

PSU Project #11 – Prototype and Calibration

Published by:

It’s been a while since I’ve released a video for this series, but I have been doing final tests for the term at college and was a little overwhelmed. But I did my last test yesterday and decided it was time to do an update.

 

The schematic as PDF can be found here: PSU – Schematic

As promised in the video, here is a flowchart showing how the software currently works. This is the basic idea of what goes on.

Do note that the Volts and Current pots on the front of the case do not directly set the current and voltage limits, rather they are read by the Arduino via the ADC and scaled and then that is outputted via the DAC to the actually regulation circuitry. This leaves the possibility of having the push-buttons setting the Voltage and Current instead.

flowchart

Here is the Arduino code used in this episode, I will be cleaning it up for the final version:

#include "SPI.h"
#include <LiquidCrystal.h>
#define SW1 18 // Rightmost button
#define SW2 17
#define SW3 16
#define SW4 15
#define SW5 14 // Leftmost button
#define ADC_CS 10 // ADC chip-select
#define DAC_CS 9 // DAC chip-select
#define LCD_D7 8 
#define LCD_D6 7
#define LCD_D5 6
#define LCD_D4 5
#define LCD_E 4
#define LCD_RS 3
//#define SPARE 2
#define vout_cal 0.0065651063;
#define iout_cal 0.001;
#define vin_cal 0.006092087;
#define iin_cal 0.001;
#define max_scount 100000 // Counts for screen update
unsigned int v_set,i_set,v_feedback,i_feedback;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
void setup() {
 //set pin modes 
 pinMode(DAC_CS, OUTPUT); 
 pinMode(ADC_CS, OUTPUT);
 
 pinMode(LCD_D7, OUTPUT); 
 pinMode(LCD_D6, OUTPUT); 
 pinMode(LCD_D5, OUTPUT); 
 pinMode(LCD_D4, OUTPUT); 
 pinMode(LCD_E, OUTPUT); 
 pinMode(LCD_RS, OUTPUT);
pinMode(SW1, INPUT); 
 pinMode(SW2, INPUT); 
 pinMode(SW3, INPUT); 
 pinMode(SW4, INPUT); 
 pinMode(SW5, INPUT);
 // disable all devices to start with 
 digitalWrite(ADC_CS, HIGH); 
 digitalWrite(DAC_CS, HIGH); 
 SPI.begin();
 Serial.begin(115200); 
 Serial.println("Ready.");
 // set up the LCD's number of columns and rows:
 lcd.begin(16, 2);
 // Print a message to the LCD.
 //lcd.print("hello, world!");
}
void set_dac(byte chan, unsigned int value,byte ga, byte shdn)
{
 byte b,c,conf;
 // ga : 0=2x (0-4096v), 1=1x (0-2.048v)
 // shdn : 0 = shutdown DAC channel, 1 = output available
 // [ A'/B , x , GA', SHDN', D11, D10, D9, D8 ]
 conf=(chan&0x01)<<7; // mask out channel number and shift it to bit 7
 conf=conf|(ga&0x01)<<5; // mask out gain select and shift it to bit 5 and or it to conf
 conf=conf|(shdn&0x01)<<4; // mask out shutdown select and shift it to bit 4 and or it to conf
 conf=conf|(value>>8); // or in the top nibble of value left in conf
 b = value; // bottom byte of value
 SPI.beginTransaction(SPISettings(15000000, MSBFIRST, SPI_MODE0));
 digitalWrite (DAC_CS, LOW); // enable DAC
 SPI.transfer(conf); // send configuration and top nibble of value
 SPI.transfer(b); // send bottom byte
 digitalWrite (DAC_CS, HIGH); // disable DAC
 SPI.endTransaction();
 
}
unsigned int get_adc(byte chan)
{
 unsigned int a,b,c,conf;
 conf=conf=((chan&0b00000111)<<1)|0b00110000; // create configuration byte
 SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
 digitalWrite (ADC_CS, LOW); // enable ADC
 SPI.transfer(conf); // send configuration byte
 b = SPI.transfer(0x00); // receive sign bit & top 4 bits 
 c = SPI.transfer(0x00); // receive lower 8 bits
 digitalWrite (ADC_CS, HIGH); // disable ADC
 SPI.endTransaction();
 b = b&0b00011111; // filter out unwanted stuff from high byte
 a = (b*0x100)+c; // convert 2 8-bit numbers into a single 16-bit number
 return(a);
}
unsigned int get_adc_avg(byte chan)
{
 long tempx = 0;
 byte ax = 0;
 for (ax=0;ax<20;ax++)
 {
 tempx+=get_adc(chan);
 }
 tempx/=20;
 return (tempx);
}
void update_screen()
{
 static float vout,vin,iout,iin;
 static char voutstr[15];
 static char ioutstr[15];
 static char vinstr[15];
 static char iinstr[15];
// 0.004884;
 vout = v_set*vout_cal;
 iout = i_set*iout_cal;
 vin = v_feedback*vin_cal;
 iin = i_feedback*iin_cal;
 
 dtostrf(vout, 5,2, voutstr);
 dtostrf(iout, 5,3, ioutstr);
 dtostrf(vin, 5,2, vinstr);
 dtostrf(iin, 5,3, iinstr);
if (digitalRead(SW5)==1)
 {
 lcd.setCursor(0, 0); lcd.print(v_set, DEC); lcd.print(" "); // for calibration
 lcd.setCursor(0, 1); lcd.print(i_set, DEC); lcd.print(" "); // for calibration
 lcd.setCursor(8, 0); lcd.print(v_feedback, DEC); lcd.print(" "); // for calibration
 lcd.setCursor(8, 1); lcd.print(i_feedback, DEC); lcd.print(" "); // for calibration
 }
 else
 {
 lcd.setCursor(0, 0); lcd.print(voutstr); lcd.print("V ");
 lcd.setCursor(0, 1); lcd.print(ioutstr); lcd.print("A ");
 lcd.setCursor(8, 0); lcd.print(vinstr); lcd.print("V "); 
 lcd.setCursor(8, 1); lcd.print(iinstr); lcd.print("A ");
 }
}
void loop() 
{
 unsigned long scount = max_scount+1;
 unsigned int xx = 0b100000;
unsigned int adc0;
 unsigned int adc1;
 unsigned int adc2;
 unsigned int adc3;
adc0 = get_adc_avg(0)/2;
 adc1 = get_adc_avg(1)/2;
 adc2 = get_adc_avg(2)/2;
 adc3 = get_adc_avg(3)/2;
 
 set_dac(0, (adc0),0, 1);
 set_dac(1, (adc1),0, 1);
v_set = adc0;
 i_set = adc1;
 v_feedback = adc2;
 i_feedback = adc3;
scount++;
 if (scount>max_scount)
 {
 scount=0;
 update_screen();
 }
 
}

PSU Project #10 – Current sensing and regulation

Published by:

In this video I will go over techniques of sensing current in the PSU circuit as well as explore the regulation of the current.

It’s been a while since my last episode, I have been busy with school work and I also needed to construct a variable dummy load in order to get this working.

We are nearing the end of the series. In the next video we will be putting the analogue side and the digital side together and having a look at it being completely driven from the DAC.

PSU Project #9 – Button and Matrix inputs

Published by:

Hi All,

sorry for the delay adding this to my website, I’ve been busy with college. I’ve just uploaded part 10 and realized that I didn’t update the webpage for 9, so here it is.

In this episode I will be briefly covering using the button inputs on the Arduino. I briefly go over debouncing and then I introduce using a matrix keypad to allow more buttons to be used.

Arduino code for debounced button input:

#include <LiquidCrystal.h>
#define button_5 6
#define button_4 7
#define button_3 8
#define button_2 9
#define button_1 10
#define hold_limit 15000
int temp=0,tempold=1;
int b1=0,b2=0,b3=0,b4=0,b5=0;
int bs1=0,bs2=0,bs3=0,bs4=0,bs5=0;
int bc1=0,bc2=0,bc3=0,bc4=0,bc5=0;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
 // set up the LCD's number of columns and rows:
 lcd.begin(16, 2);
 // Print a message to the LCD.
 lcd.print("hello, world!");
}
void loop() {
 // set the cursor to column 0, line 1
 // (note: line 1 is the second row, since counting begins with 0):
b1 = digitalRead(button_1);
 b2 = digitalRead(button_2);
 b3 = digitalRead(button_3);
 b4 = digitalRead(button_4);
 b5 = digitalRead(button_5);
//////////// Button 1 ///////////////
 if ((b1==1)&&(bs1==0))
 {
 temp = 0; bs1=1; bc1=0;
 }
 if ((b1==1)&&(bs1==1))
 {
 bc1++;
 if (bc1>hold_limit)
 {
 bs1=0; bc1=0;
 }
 }
 if ((b1==0)&&(bs1==1))
 {
 bs1=0;
 }
//////////// Button 2 ///////////////
 if ((b2==1)&&(bs2==0))
 {
 temp--; bs2=1; bc2=0;
 }
 if ((b2==1)&&(bs2==1))
 {
 bc2++;
 if (bc2>hold_limit)
 {
 bs2=0; bc2=0;
 }
 }
 if ((b2==0)&&(bs2==1))
 {
 bs2=0;
 }
//////////// Button 3 ///////////////
 if ((b3==1)&&(bs3==0))
 {
 temp++; bs3=1; bc3=0;
 }
 if ((b3==1)&&(bs3==1))
 {
 bc3++;
 if (bc3>hold_limit)
 {
 bs3=0; bc3=0;
 }
 }
 if ((b3==0)&&(bs3==1))
 {
 bs3=0;
 }
//////////// Button 4 ///////////////
 if ((b4==1)&&(bs4==0))
 {
 temp-=10; bs4=1; bc4=0;
 }
 if ((b4==1)&&(bs4==1))
 {
 bc4++;
 if (bc4>hold_limit)
 {
 bs4=0; bc4=0;
 }
 }
 if ((b4==0)&&(bs4==1))
 {
 bs4=0;
 }
//////////// Button 5 ///////////////
 if ((b5==1)&&(bs5==0))
 {
 temp+=10; bs5=1; bc5=0;
 }
 if ((b5==1)&&(bs5==1))
 {
 bc5++;
 if (bc5>hold_limit)
 {
 bs5=0; bc5=0;
 }
 }
 if ((b5==0)&&(bs5==1))
 {
 bs5=0;
 }
/////////////////////////////////////
 if (temp!=tempold)
 {
 lcd.setCursor(0, 1); lcd.print(" ");
 lcd.setCursor(0, 1); lcd.print(temp);
 tempold=temp;
 }
}

PSU Project #8 – Transistor Voltage Regulation

Published by:

October 17th 2015

In this video I will be demonstrating regulating the voltage with a 2N3055 NPN Power transistor.

The basic idea is very simple, the transistor will compare the Vin with the output voltage via R1 and R2, it will then adjust the output which drives the transistor and will make corrections to the voltage that is being driven by it.

vreg with 3055

I also give a quick demonstration of this circuit being controlled by the MCP4822 DAC which is connected to my Arduino.

2015-10-17 01.12.43

You may have noticed that I have moved the DAC/ADC setup onto a new board which now uses the Arduino Nano as opposed to the Arduino Mega. This is getting it all in line for when I start to merge the analogue and digital side of things.

PSU Project #7 – LCD’s

Published by:

September 19th 2015
In this quick video we discuss the use of LCD’s on the Arduino board.
The LCD’s we use are the standard 16×2 Hitachi based alphanumeric display and a 84×48 Nokia 3310 display.

PSU Project #7 – LCD’s

Hitachi based LCD:
Hitachi LCD to Arduino
This is the wiring diagram of the setup used in the demonstration of the Hitachi based LCD.
This Hitachi based display is a very commonly used display type, there is a library in the Arduino IDE by standard under the name of LiquidCrystal and there is example code that is used. Should I find myself restricted on space inside the Arduino then I may consider using this display as the character set is hardcoded into the Hitachi controller on the module thus saving us space in the code.
Nokia 3310 display:
Nokia 3310 LCD to Arduino
This is the wiring diagram of the setup used in the demonstration of the Nokia 3310 display.

The Nokia 3310 display uses a Philips PCD8544 driver chip but since it was mostly used in the Nokia 3310 cell-phone it is more commonly known by that name.

Example code for this display can be found here at the Arduino playground site. (opens in new window)
This is the code that I used in the demonstration. I did however make changes to the code:
The lines that read:
#define PIN_SDIN  4
#define PIN_SCLK  3

Were changed to:

#define PIN_SDIN  11
#define PIN_SCLK  13
This allowed it to work it my wiring shown above.
Note: I have since moved it back to pins 4 and 3, it seems to be fine now. I decided to do this to ensure that 11 and 13 were available for SPI communications on normal (non-mega) Arduino’s, this is important as I’m going to base most of it around the Arduino Nano.

PSU Project #6 – Operational Amplifiers

Published by:

September 30th 2015
In this video I will briefly be discussing the Operational Amplifier and it’s functions.
I will be covering the basic configurations that may be used in out power supply design.
This is by no means an exhaustive lesson on OPAMP’s, that would take many hours of video footage and knowledge that I do not possess at this point in time, but it should be sufficient enough to allow a beginner to start using them in circuits.

PSU Project #6 – Operational Amplifiers

Open loop:
  Vout = ((IN+)-(IN-))*Aol
  Aol is the gain of the OPAMP
Negative feedback:
  Vout = -(Rf/Ri)*Vin
Positive feedback
Vout = (1+(Rf/Ri))*Vin
Multi-Channel / Summing Amplifier
Vout = (-(Rf/Ri1)*Vin1) + (-(Rf/Ri2)*Vin2)
          further stages can be added if needed, just add them at the end of the formula.
Unity Gain / Buffer
Vout = Vin
Differential Amplifier
Vout = (Vin2-Vin1)*(Ra/Rb)

PSU Project #5 – Arduino SPI

Published by:

September 19th 2015
In this video I get the hardware SPI up and running on the Arduino and write code for the MCP3304 and MCP4822
The example Arduino code further down the page will read channel 0 of the ADC and output it to both channels of the DAC.
I recorded this with a Sony DCR-SR300 camcorder I borrowed from the college, turns out that it’s not a HD recorder. I didn’t realize this until I was nearly done editing. I will make sure I get a HD camera for next time.

Arduino code (can be downloaded here):
#include "SPI.h"

#define DAC_CS 9 // DAC chip-select
#define ADC_CS 10 // ADC chip-select

void setup() {
 //set pin modes 
 pinMode(DAC_CS, OUTPUT); 
 pinMode(ADC_CS, OUTPUT); 
 // disable all devices to start with 
 digitalWrite(ADC_CS, HIGH); 
 digitalWrite(DAC_CS, HIGH); 
 SPI.begin();
 Serial.begin(115200); 
 Serial.println("Ready.");
}

void set_dac(byte chan, unsigned int value,byte ga, byte shdn)
{
 byte b,c,conf;
 // ga : 0=2x (0-4096v), 1=1x (0-2.048v)
 // shdn : 0 = shutdown DAC channel, 1 = output available
 // [ A'/B , x , GA', SHDN', D11, D10, D9, D8 ]
 conf=(chan&0x01)<<7; // mask out channel number and shift it to bit 7
 conf=conf|(ga&0x01)<<5; // mask out gain select and shift it to bit 5 and or it to conf
 conf=conf|(shdn&0x01)<<4; // mask out shutdown select and shift it to bit 4 and or it to conf
 conf=conf|(value>>8); // or in the top nibble of value left in conf
 b = value; // bottom byte of value
 SPI.beginTransaction(SPISettings(15000000, MSBFIRST, SPI_MODE0));
 digitalWrite (DAC_CS, LOW); // enable DAC
 SPI.transfer(conf); // send configuration and top nibble of value
 SPI.transfer(b); // send bottom byte
 digitalWrite (DAC_CS, HIGH); // disable DAC
 SPI.endTransaction();

}

unsigned int get_adc(byte chan)
{
 unsigned int a,b,c,conf;
 conf=conf=((chan&0b00000111)<<1)|0b00110000; // create configuration byte
 SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
 digitalWrite (ADC_CS, LOW); // enable ADC
 SPI.transfer(conf); // send configuration byte
 b = SPI.transfer(0x00); // receive sign bit & top 4 bits 
 c = SPI.transfer(0x00); // receive lower 8 bits
 digitalWrite (ADC_CS, HIGH); // disable ADC
 SPI.endTransaction();
 b = b&0b00011111; // filter out unwanted stuff from high byte
 a = (b*0x100)+c; // convert 2 8-bit numbers into a single 16-bit number
 return(a);
}

unsigned int get_adc_avg(byte chan)
{
 long tempx = 0;
 byte ax = 0;
 for (ax=0;ax<10;ax++)
 {
 tempx+=get_adc(chan);
 }
 tempx/=10;
 return (tempx);
}

void loop() 
{
 unsigned int xx;
 set_dac(0, (get_adc_avg(0)/2),0, 1);
 set_dac(1, (get_adc_avg(0)/2),0, 1);
}

PSU Project #3 – MCP4822

Published by:

(Transplanted from old website)

August 31st 2015:

In this episode we investigate the MCP4822 12-Bit DAC.
This is another digital building block for the PSU design, this component will allow us to set the voltage level and the current limit for the circuit digitally.
Below is the schematic used in this episode. It builds upon the one from episode #1
In the episode, I explain how the internals of the DAC work and introduce the concept of an R-2R ladder.

PSU Project #3 – MCP4822

Sketch used in the episode (can be downloaded here):

/*
 Test sketch for the MCP3304 and MCP4822
 Both are bit-banged to get them working.
 In this demo:
 DAC channel A will count up from 0v to 4.096V
 DAC Channel B will mirror what is being read on ADC Channel 0
 Arduino   MCP3304   MCP4822
 */
 #define ADC_CS 10    // ADC chip-select
 #define DAC_CS 9    // DAC chip-select
 #define ADC_MOSI 11   // ADC_MOSI
 #define ADC_MISO 12    // ADC_MISO
 #define SPI_CLK 13  // Clock
 #define MCP4822_DAC_A_BUFFERED_GAIN_1X_NON_SHDN      0x70  // DAC A, Buffered, Gain 1x, Output power control
 #define MCP4822_DAC_A_BUFFERED_GAIN_2X_NON_SHDN      0x50  // DAC A, Buffered, Gain 2x, Output power control
 #define MCP4822_DAC_A_NON_BUFFERED_GAIN_1X_NON_SHDN  0x30  // DAC A, Non buffered, Gain 1x, Output power control
 #define MCP4822_DAC_A_NON_BUFFERED_GAIN_2X_NON_SHDN  0x10  // DAC A, Non buffered, Gain 2x, Output power control
 #define MCP4822_DAC_B_BUFFERED_GAIN_1X_NON_SHDN      0xF0  // DAC B, Buffered, Gain 1x, Output power control
 #define MCP4822_DAC_B_BUFFERED_GAIN_2X_NON_SHDN      0xD0  // DAC B, Buffered, Gain 2x, Output power control
 #define MCP4822_DAC_B_NON_BUFFERED_GAIN_1X_NON_SHDN  0xB0  // DAC B, Non buffered, Gain 1x, Output power control
 #define MCP4822_DAC_B_NON_BUFFERED_GAIN_2X_NON_SHDN  0x90  // DAC B, Non buffered, Gain 2x, Output power control
int test2=0;
 long test3=0;
void pulse_MCP_clock(void)
 {
 digitalWrite(SPI_CLK, LOW); delayMicroseconds(50);
 digitalWrite(SPI_CLK, HIGH); delayMicroseconds(50);
 }
long read_MCP(int channel)
 {
 long value=0;
 signed int x=0;
 digitalWrite(ADC_CS, LOW);
 digitalWrite(DAC_CS, HIGH);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, LOW);
 delayMicroseconds(50);
 digitalWrite(ADC_MOSI, HIGH); //start pulse
 pulse_MCP_clock();
 digitalWrite(ADC_MOSI, HIGH); //single mode
 pulse_MCP_clock();
 for(x=2; x>=0; --x)
 {
 if(bitRead(channel,x))
 {
 digitalWrite(ADC_MOSI, HIGH);
 }
 else
 {
 digitalWrite(ADC_MOSI, LOW);
 }
 pulse_MCP_clock();
 }
 digitalWrite(ADC_MOSI, LOW);//put low throughout
 for(x=1;x<=3;++x)
 {
 //blank, Null, and sign bit (always 0 in single mode)
 pulse_MCP_clock();
 }
 //now get twelve bits
 for(x=11; x>=0; --x)
 {
 pulse_MCP_clock();
 if (digitalRead(ADC_MISO))
 {
 bitSet(value,x);
 }
 else
 {
 bitClear(value,x);
 }
 }
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 return value;
 }
void init_ADC(void)
 {
 digitalWrite(SPI_CLK,HIGH); //clock
 digitalWrite(ADC_MISO, LOW); //output -- supposed to be float but not sure how to do this on Arduino
 digitalWrite(ADC_MOSI, HIGH); //input
 digitalWrite(ADC_CS, HIGH);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, LOW);
 delayMicroseconds(50);
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 }
int get_adc_avg(int channel)
 {
 long tempx = 0;
 byte ax = 0;
 for (ax=0;ax<10;ax++)
 {
 tempx+=read_MCP(channel);
 }
 tempx/=10;
 return (tempx);
 }
void mcp4822_init() {
 digitalWrite(DAC_CS,HIGH);
 digitalWrite(SPI_CLK, LOW);
 digitalWrite(ADC_CS,HIGH);
 digitalWrite(ADC_MOSI, LOW);
 }
void mcp4822_write(byte control,int data) {
 byte i;
 int tempx=0x00;
 tempx = data|(control<<8);
 digitalWrite(ADC_CS,HIGH);
 delayMicroseconds(10);
 digitalWrite(SPI_CLK,LOW);
 delayMicroseconds(10);
 digitalWrite(DAC_CS,LOW);
 delayMicroseconds(10);
 digitalWrite(ADC_MOSI,LOW);
 for(i=16;i>0;--i)
 {
 digitalWrite(SPI_CLK,LOW);
 digitalWrite(ADC_MOSI,bitRead(tempx,i-1));
 digitalWrite(SPI_CLK,HIGH);
 }
 digitalWrite(DAC_CS,HIGH);
 delayMicroseconds(10);
 }
void setup() {
 //set pin modes
 pinMode(ADC_CS, OUTPUT);
 pinMode(DAC_CS, OUTPUT);
 pinMode(ADC_MOSI, OUTPUT);
 pinMode(ADC_MISO, INPUT);
 pinMode(SPI_CLK, OUTPUT);
 init_ADC();
 mcp4822_init();
 digitalWrite(ADC_CS, HIGH);
 digitalWrite(DAC_CS, HIGH);
 Serial.begin(115200);
 Serial.print("Hello2"); // Just to show the serial is working
 }
void loop() {
 int tempx2 = 0;
 if (test3++>0xFFF) test3=0;
 tempx2 = read_MCP(0);
 mcp4822_write(MCP4822_DAC_A_NON_BUFFERED_GAIN_2X_NON_SHDN, test3);
 mcp4822_write(MCP4822_DAC_B_NON_BUFFERED_GAIN_2X_NON_SHDN, tempx2);
 delay(10);
 }