Close

April 17, 2015 - first tests

A project log for Digital Bench Power Supply

A new design, made from scratch, for a digital bench power supply to offer regulated voltage and current, and prompt shortcircuit protection

radu-motisanRadu Motisan 04/27/2015 at 14:380 Comments

ADC on port PC4 is used to read output voltage through a 10K/100K resistive divider. PC5 is connected to the shunt and used to read the current.

I measured the transformer output, immediately after the filter capacitors following the rectifier. I get 16.1V with the center tap and 33.8V on the full secondary. With full output, using the TL082, I only get 14.56V vs 16.1V and 26.26V vs 33.8V.

Finally the PWM code is in place, and I can now adjust not only the duty cycle, to vary the DAC output from 0 to 5V, but also the frequency. I wanted to see the ripple. So I connected the oscilloscope , CH1 (yellow) on the RC low pass filter capacitor and CH2(cyan) on the OpAmp output, right where the signal goes to the base of the power transistors.

It's not much. The question is what's the best frequency to use with this setup? With a small RC filter cap, it's clear that we need higher frequency values. After a few tests, I opted for 100KHz.

At 100KHz I get some ripple close to 0.05V, which is good. Next thing to do is to have the output control code in place. As said previously, that needs to be fast. All ADC conversions must be done as interrupts, to avoid the main program loop delaying the critical response (as in case of shortcircuit).

The only problem is ADC can do a single conversion at a time, so we need to measure voltage and current alternatively since we use two separate ADC channels for that. A 16Mhz crystal is used with the Atmega8 and an ADC prescaler of 128 to increase the conversion speed to maximum. Here's the code logic:

1) Initialization

float vref = 5.0;

#define MODE_MEASURE_CURRENT 0
#define MODE_MEASURE_VOLTAGE 1
volatile bool adc_mode = MODE_MEASURE_CURRENT;
volatile float current = 0, voltage = 0; 

// setup ADC to measure as interrupt: go for current first
adc_mode = MODE_MEASURE_CURRENT;
ADMUX = PC5;
ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADIF) | (1<<ADSC) |
	(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // set prescaler to 128 (16M/128=125kHz, above 200KHz 10bit results are not reliable)
sei(); 

2) interrupt

// Interrupt service routine for the ADC completion
// we measure the current (PC5) and the voltage (PC4) alternatively
ISR(ADC_vect){
  uint16_t analogVal = ADCL | (ADCH << 8);
  if (adc_mode == MODE_MEASURE_CURRENT) {
	  current = (analogVal / 1024.0 * vref) / 0.55;
	  // alternate mode
	  adc_mode = MODE_MEASURE_VOLTAGE;
	  ADMUX = PC4; // next time we will do ADC on PC4, to get the voltage
  } else if (adc_mode == MODE_MEASURE_VOLTAGE) {
	  float R14 = 10, //10k
			R13 = 100; //100K
	  voltage = analogVal / 1024.0 * (R13 + R14) / R14 * vref;
	  // alternate mode
	  adc_mode = MODE_MEASURE_CURRENT;
	  ADMUX = PC5; // next time we will do ADC on PC5, to get the current
  }
  // Not needed because free-running mode is enabled, so the convertion will restart by itself
  // start another ADC convertion
  //aux_ADCReadIntr(PC5);
  // ADCSRA |= 1<<ADSC;
  ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADIF) /* | (1<<ADFR) */ | (1<<ADSC) |
  				(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // set prescaler to 128 (16M/128=125kHz, above 200KHz 10bit results are not reliable)

 }
Next thing to do is to test the supply for a shortcircuit! In the interrupt code, right in the if (adc_mode == MODE_MEASURE_CURRENT) { , if the current is dangerously high I need to reduce the DAC by lowering the duty cycle, to limit the output. How fast can this be done, is something we need to see.

fingers crossed...

Discussions