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.
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(); } }