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.

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).

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.

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) int read_voltage; // analog read 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; } read_voltage = analogRead(A0); 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); }
Pingback:Industruino digital power supply | Cassiopeia Ltd
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.
hi, i have included a basic sketch above, hope that helps.
thanks for the explanation!