Following the bare bones Arduino power supply with LCD of my previous post, I wanted to fix the problem that the load voltage (V_load) will vary when the current varies, because of the voltage drop over the shunt resistor V_shunt, as the DC/DC converter supplies a constant V_out = V_shunt + V_load. The ultimate goal is to make a power supply that can ‘lock in’ a constant voltage independent of current drawn.

The obvious solution is to let the Arduino microcontroller control the potentiometer on the DC/DC converter, with a digital potentiometer. I got the MCP4151-103, a 10K digital potentiometer with 256 steps over SPI. The connection with Arduino is quite standard as described here. I found out in these schematics that the original trim pot on the DC/DC converter is actually not using its 3 legs independently, so that would call for a digital rheostat rather than a potentiometer, but the MCP4151 does the job too. DC/DC converter on the left with digital potentiometer on breadboard connected to an Arduino in the back. Output voltage is divided over a shunt 5ohm resistor (to be able to measure current later) and a simulated load of 40ohm. The load voltage goes into a voltage divider ; 1/3 of the load voltage goes into an analog pin of the Arduino (Aref = 5V).

The DC/DC converter is quite stable, so if we would map the digital potentiometer values to the output voltages, we could just use a table to set the pot value corresponding with the target voltage. However, if we want to measure current (with a shunt resistor), then the voltage over the shunt resistor V_shunt will vary according to the current, and also V_load will vary (V_out remaining stable). If we try to keep V_load stable, we can use a typical PID controller setup. Arduino has an excellent PID library. It uses 3 variables:

• input: output_voltage (in Volts)
• setpoint: target_voltage (in Volts)
• output: pot_level (to send to the digital potentiometer 0-255)

There are 3 parameters to tune the PID controller: Kp, Ki, Kd. The PID did work with the default values in the library example sketch, but it was very slow. I tried the PIDautotune library to find the optimal values for these 3 parameters, but couldn’t get that to work. To experiment with different values i really needed to see what was happening in a real-time graph. So i used a simple Processing sketch to visualise the output of the Arduino sketch (output_voltage). Processing graph showing PID control at work to reach various random voltages under constant load

The Arduino sketch changes the target_voltage every 5 seconds to a random integer value between 3V and 9V. With a good set of K parameters the transitions are very short, less than 1 second. The graph shows that increasing the voltage goes a lot faster than decreasing it.

Next step is to see how the PID control reacts to a varrying load when we use a shunt resistor. To keep the V_load constant, the PID will need to adjust the V_out. I used a 5V target with a load of 40ohm, drawing a 130mA current, and switching this load on and off quickly, causing the spikes. And for reference the current version of the Fritzing schematics of the above project. Arduino based digital power supply with PID control

I used an Industruino PROTO to give this project a nice permanent home and i am using it frequently as my testing power supply. Below the code for the basic PID sketch (without shunt):

```/* dig pot MCP4151
create voltages of 0-1-2-3-4-5V over wiper-GND
1: CS      D4
2: SCLK    D13 (on leonardo use ICSP header!! SCK)
3: SI      D11 (on leonardo use ICSP header!! MOSI)
4: GND
5: 5V
6: wiper
7: GND
8: 5V
Tom Tobback March 2015
*/
#include <SPI.h>
#include <PID_v1.h>

// Set digital pin 4 as slave select for digital pot:
const int pot_pin = 4;
double pot_level = 0;    // between 0-255                PID OUTPUT  (default output is 0-255 = correct)
double output_voltage;   // measured output voltage      PID INPUT
double target_voltage = 5;   // target output voltage        PID SETPOINT
long last_send = 0;      // for processing graph

// PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
PID myPID(&output_voltage, &pot_level, &target_voltage,2,5,1, DIRECT);

void setup()
{
//  analogReference(EXTERNAL);   // put 5V on AREF
pinMode(pot_pin, OUTPUT);
pinMode(3, INPUT);
SPI.begin();
Serial.begin(9600);
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(50);
myPID.SetTunings(10,200,0);
}
void loop()
{
if (Serial.available() > 0)
{
target_voltage = Serial.parseInt();
Serial.println(target_voltage);
}

if (digitalRead(3) == HIGH)   // manual switch during processing graph
{ target_voltage = 5; }
else
{ target_voltage = 3; }

output_voltage = 3 * 3.3 * float(read_voltage) / 1023;

myPID.Compute();
digitalPotWrite(pot_level);

if (millis() - last_send > 50)   // don't send to often to Serial for processing graph
{
Serial.println(output_voltage);
last_send = millis();
}
//    Serial.print("V\t");
//    Serial.println(pot_level);
//    delay(100);
}
int digitalPotWrite(int value)
{
// Take the SS/CS pin low to select the chip:
digitalWrite(pot_pin, LOW);
// Send in the address and value via SPI:
SPI.transfer(0);
SPI.transfer(value);
// Take the SS/CS pin high to de-select the chip:
digitalWrite(pot_pin, HIGH);
}

```

## 4 thoughts on “Digital power supply with PID control”

• 17/11/2016 at 01:26

Hello!
Are you willing to share your sketch?
I am working on a very similar project and am having trouble getting the code to work the way I want it to.
The PID library seems to need the input to be directly from an input pin, but I need it to do math to the value read from the input pin first and it just gives an output of 0 that way.

• 18/11/2016 at 08:17
• 