picaxe controlled variable power supply

hippy

Technical Support
Staff member
There are also continuous rotary switches which can be used as +/- buttons; car radios, CB's and logic analysers often use them because where 'zero' is at turn on varies. They are usually a cheaper alternative to multi-turn pots and of course extremely accurate.

The down side is the need to determine what the switch is doing, noting when it's turned clockwise or anti-clockwise, plus software overhead so small and large change can be implemented in a way which feels comfortable ( like 'mouse acceleration' ). One has to be quite careful with that to ensure there isn't overshoot of the voltage required.

There is an advantage to a traditional pot though for a PSU; it can be turned to zero before the device is powered up. Otherwise connect the PSU to a circuit, turn it on, and you don't know what voltage will get dumped into the circuit, whatever it was last time. If it resets to 0V at power-on, that means having to adjust everytime the PSU is used.

Ergonomics is quite an important part of any design.
 

wapo54001

Senior Member
Now that the dust has settled, I'd like to raise some issues. I'll ask the questions in separate posts because a single post will get too long.

First issue -- in order for this circuit to live on an o8M in the real world where there will be other things going on besides just regulation, I need to find a way to reduce the W words used, because the software as written has consumed them all.

The most likely location to get some variable words back is at the input readADC, and I have come up with this bit of code which I will probably prefer to the current published version because my code uses only two word variables. The code is as follows (interestingly, in order for it to work when the commanded input value is higher than the existing average, I needed to add a constant to the readADC value that is equal to the multiplier in the averaging code in order for the averaged value to reach the commanded value):

Code:
'read input and average with previous reads
readADC10 4,W0
'if input commanding a larger value than existing average, add the value of the multiplier to input value
if W0 > W1 then
	W0 = W0 + 3
endif
W1 = W1 * 3 + w0 / 4
Even with widely separated W0 and W1, on the simulator the code reaches balance fairly quickly, with large jumps at the beginning and ending with two or three unitary changes at the very end.

I'd like to ask two things:

First, is there a problem with using this code that I can't see?

Second, is there a way to use the *20 and /20 technique here without using another word variable, and is it even worthwhile since we're not dealing with absolute values, but rather relative values?
 

wapo54001

Senior Member
My circuit card uses a single connection from the board to the adjust pin to carry both the mosfet control voltage and the split feedback back to the 08M. I am using the latest and greatest version of the software.

The result is really excellent, jitter is in the range of a few mV with a 220 ohm resistor plus an LED as load. The 'scope trace was very steady, with occasional corrections. Given the stability and accuracy of this one-wire circuit, I cannot see any advantage to taking feedback from output rather than adjust. However, I do see two advantages to taking both feedback and control from the adjust pin:

1) simpler wiring
2) no need to complicate calculations in order to deal with a regulator's minimum output above zero (1.25V for the LM317) because the adjust pin does go all the way to zero. I believe this would do away with the need for K_Div, D_Mul, K_Min, and the calculation involving these symbols.

I do encourage folks to test the single-wire combined control/feedback approach with current versions of the software to see if there is any improved accuracy in using separate lines for control and feedback and, if not, I suggest we make the single wire version the "standard" for publication. I think that there is no useful advantage in having a separate feedback wire to the output pin of the regulator.
 
Last edited:

Mycroft2152

Senior Member
I realize that you re tight on varialbles, but I'd like to get back to replacing the "big and little" pots with buttons. Why not takes Wilf's idea of switches and an ADC/resitor ladder to create 2 up buttons and 2 down buttones. Where one of the buttons does major steps and the other is for fine tuning?

At that point you are actully using the PICAxe control circuit. Right now, you are not doing anythng that could not be done with just a pot and the 317.

Myc
 

wapo54001

Senior Member
That's a worthwile control alternative. If convenience and the 'cool' factor are goals, I would suggest going with a keypad as someone has suggested, and keying in desired values.

Even with up & down buttons, you'd still have to free up some word variables, I think, to make it work.

The 08M can always be dedicated to the regulation task, and the process of selecting the output (and other duties) perhaps should be handed to an 18X.
 

Mycroft2152

Senior Member
Always include the 'cool factor as one of the goals. ;)

One other concern that I haven't seen discussed. What happens during power up, when the PICAXE is initalizing?

Myc
 

wapo54001

Senior Member
First command to the picaxe is to go full low with the voltage out. Stays that way until the program takes control.
 

BCJKiwi

Senior Member
Additional code:-
If you have too many 'other things' going on in the program (and needing more variables suggests that), then the effectiveness of the control will be reduced as the cycle rate will be reduced and regulation will suffer.
Had always perceived this as basically a stand-alone subsystem with input coming from alternative places if desired.

A bigger/faster chip might alleviate some of the issues (and give more variables as well) but the additional code would still need to be relatively trivial so the cycle time was still of the same order as it is now. Test with a short pause somewhere and regulation goes off.

Reducing variables:-
Basic principles;
The purpose of this bit of code was to even out variations in the pot.
A running average would also do that but introduce a lag.

If three readings are averaged, stored, then one more reading added, averaged and the extra reading accounted for, a running average is maintained.
I assume this is what the new code is doing.

If however you maintain the last three readings and average those, you get the average of the last three readings.

e.g.
If the set point has been 0 for a long time, then changes instantly to max, it will take (theoretically) an infinite amount of cycles for the average reading to become the max.

However, if the last three readings are stored individually (throwing away the previous reading), and those three readings are averaged then it would take only three cycles for this average to reach max with the same step change from 0 to max.

So the question becomes;
a. do we need to do this at all with the present code, and,
b. if so, how to store the last three readings without using up variables?

The answer to a. is yes. Without this average of three, the output still hunts. This could be reduced by increasing the amount of damping but this would reduce the minimum change that could be set and the regulation.

The only other option for storage (with an 08M) is to use the registers. Unfortunately calculations cannot be done directly on data in the registers which must be poked from variables and peeked back into variables with calculations using the variables.
The best I could come up with at short notice is a saving of 3 Word Variables - two by using the registers, and one by re-using SetVar in place of Target (I think Target became a separate variable due to some other code variation which no longer applies).
This code would also allow the last three FIFO to be extended to any number (within reason). It was previously limited by the number of variables available.

Have also changed the code to work with the sense on Adj circuit which I have tested again and it is good with the same IRL520N/0.15uF values used for sense on Vout.
Have also tested it again with the VN2222l/0.i5uF and find the previous ringing at certain voltages ahs disappeard. Did re-route some of the jumpers around the LM317T but nothing that would obviously account for the change.
Code:
#PICAXE 08M
setfreq m8
SYMBOL Set  = 4    'ADC4 ~ the voltage setting Pot input
SYMBOL FeedBk  = 1    'ADC1 ~ the feedback loop input
SYMBOL Gate  = 2    'In/Out2 ~ output 'pump' to the R/C network on the MOSFET Gate
High Gate      'Drive Vout to minimum for safety on start-up!
SYMBOL SetVar = w0
SYMBOL SetVar_1 = 80   'Register address for FIFO buffer
SYMBOL SetVar_2 = 82   'Register address for FIFO buffer
SYMBOL SetVar_3 = 84   'Register address for FIFO buffer
SYMBOL FeedBkVar= w1
SYMBOL Temp_Var = w2   ' working temporary variable for peeks/pokes to FIFO
SYMBOL Damper   = w3
'
main:
 readadc10 Set,SetVar
 peek setvar_2, word Temp_Var : poke SetVar_3, word Temp_Var
 peek setvar_1, word Temp_Var : poke SetVar_2, word Temp_Var
 Setvar = SetVar * 20   : poke SetVar_1, word SetVar
 peek setvar_2, word Temp_Var : SetVar = SetVar + Temp_Var
 peek setvar_3, word Temp_Var : SetVar = SetVar + Temp_Var
 SetVar = SetVar / 60
 
'adjust:
 readadc10 FeedBk,FeedBkVar  'get voltage data from output
 if SetVar = FeedBkVar then
  input Gate    'hold Gate charge
  goto  main     'return as output matches target
 EndIf
'increase:
 if SetVar > FeedBkVar then 'Out put is too low so raise output
  Damper = SetVar - FeedBkVar
  If Damper < 2 then main 'If change is just 1 unit, skip ~ damps out 'hunting' around set point
  low Gate    'lower Gate V = Lower MOSFET R = Higher Current through Adj circuit = higher Vout
  goto main
 EndIf
'decrease:
   'if Target < FeedBkVar then ~ falls through to decrease if not increase! If...Endif not required
  Damper = FeedBkVar - SetVar
  If Damper < 2 then main 'If change is just 1 unit, skip ~ damps out 'hunting' around set point
  high Gate    'Higher Gate V = Higher MOSFET R = Lower Current through Adj circuit = Lower Vout
  goto main
end
Had considered a keypad but if code is added to store the successive keystokes to arrive at the value of Voltage, then convert it to a 0-1023 range, then cycle time and regulation will be compromised.

It is very simple to read button presses for up/down, and have additional button/resistor combos for different size jumps. The problem I discovered before when testing this is that a single manual button push is way too long as the program cycles so fast that the shortest human button press duration last many program cycles. So additional external hardware would need to be used (a one shot or similar) as you can't use software techniques because you want to kmow about every button press. The one-shot has issues as well as you also want to be able to hold the button down, not have to press it repeatedly to move a long way.

I'm sure someone has an answer for this but nothing was suggested when this was covered astarting post #164 and specifically #173
 
Last edited:

wapo54001

Senior Member
Here is the schematic. The 240R and capacitors are with the regulator at the heatsink, all other circuit components are on a pcb board.
 

BCJKiwi

Senior Member
All good and as just noted, have good test results with this and the code above (post #210) is good for this circuit.

Just have not been able to get my head around how to make the buttons work well.

Also (guess I'm just old fashioned) but I don't actually have problems with using a pot for this application (if manual input is required), it is very intuitive.
 

BCJKiwi

Senior Member
OK code watchers, here's the PB option favoured by many.

Utilises 2 pins and the Button command - only way I could find to get controlled small increments. At Vout max of 10V, minimum increment is around 0.01~0.02V which is about the best that could be expected as controlling factor is the ReadADC10 on the feedback circuit (10 / 1023 = 0.009 and could be +-1 of this.

Using the BUTTON command de-bounces and sets the delay before a repeat begins,

So with a single button for up and another for down, there is control per press for small increments, and large increments if the PB is held down.

Takes about 4 secs to go from Min Vout to Max Vout at the fastest repeat rate.
Currently set near the longest delay to ensure a single increment for a single brief PB press.

As there is no Pot involved and feed back is being compared with a an actual number that is stable unless being intentionally altered, the Damper in the adjust code is no longer required - takes a little longer to settle but once settled does not vary.

Code:
#PICAXE 08M
setfreq M8
SYMBOL Up_PB    = 4             'Input4 PB Up
SYMBOL Dn_PB    = 3             'Input3 PB Dn
SYMBOL FeedBk   = 1             'ADC1   FeedBack
SYMBOL Gate     = 2             'In/Out2
High Gate                       'Drive Vout to minimum for safety!
SYMBOL Dn_Var   = b8            'Button Command Repeat storage variable
SYMBOL Up_Var   = b9            'Button Command Repeat storage variable
SYMBOL Set_Var  = w5
SYMBOL FeedBk_Var= w6
Set_Var = 1                     'Preset Program to Minimum Vout for safety
main:
'BUTTON pin   ,downstate,delay,rate,bytevariable,targetstate,address
Button  Dn_PB ,1        ,250  ,1   ,Dn_Var      ,1          ,Vout_Dn 'Delay ~ Max=255, Rate ~ Min=1=fastest
Button  Up_PB ,1        ,250  ,1   ,Up_Var      ,1          ,Vout_Up
goto adjust      'If no button pressed, goto Adjust:
Vout_Dn:
   Set_Var = Set_Var - 1 Min 1  'If min not set at 1, 0-1=65535 ~ underflows Set_Var to 65535!
   goto Adjust
Vout_Up:
   Set_Var = Set_Var + 1 Max 1023
adjust:
   readadc10 FeedBk,FeedBk_Var  'get voltage data from output via 240R and Vout
   if Set_Var = FeedBk_Var then
      input Gate                'hold Gate charge
      goto  main                'return, output matches target
   EndIf
increase:
   if Set_Var > FeedBk_Var then 'Out put is too low so raise output
      low Gate                  'lower Gate V = Lower MOSFET R = Higher Current through Adj circuit = higher Vout
      goto main
   EndIf
decrease:
   'if Target < FeedBk_Var then ~ falls through to decrease if not increase! If...Endif not required
      high Gate                 'Higher Gate V = Higher MOSFET R = Lower Current through Adj circuit = Lower Vout
      goto main
end
Circuit
Code:
'08M controlled 3pin adjustable voltage regulator
'NOTE!! PICAXE supply must on prior to LM317T Vin else Vout will float to Vin as there is no control on Adj!
'
'   PUSH BUTTON INPUT CIRCUIT
'
'         PB
'         ---   +-----+
'   V+  --+ +---+ 10k +----+
'               +-----+    |
'                          |
' 08M Input ---------------+
'                          |
'               +-----+    |
'   0V  --------+ 10k +----+
'               +-----+
'   (same circuit Legs 3 & 4)
'
'
'
' FEEDBACK and REGULATOR OUTPUT ADJUSTMENT
'           +-----+
'08M Leg6 --+ 10k +---------------+
' (ADC1)    +-----+               |
'                                 |
'                                 |
'                        +-----+  |  +-----+       Divider not required for 5Vout
'   0V  -----------------+ 10k +--+--+ 10k +--+    Divider 0V--10k--+--10k--Vout for 10Vout
'                        +-----+     +-----+  |    Divider 0V--10k--+--20k--Vout for 15Vout
'                                             |    Divider 0V--10k--+--30k--Vout for 20Vout
'                                             |    Divider 0V--10k--+--30k--Vout for 20Vout
'                                             |
'      +--------------------------------------+
'      |
'      |
'      |                Leg3+---------+Leg2
'      | Vin ---------------+ LM317T  +-------+--+ Vout ~ LM317T, A, LM338 or other similar 3 pin regulator
'      | Vin = Vout-3V      +----+----+       |  |        Caps may be required for Regulator
'      |                     Leg1|            |  |       
'      |                     Adj |  +------+  |  |
'      +-------------------------+--+ 240R +--+  |
'                                |  +------+
'                     See Notes  |              LOAD (Minimum 3.5mA ~ 10mA, MAX 1,5A depending on Vout and HEATSINK)
'                     +--0.2 uF--+
'                     |          |               |
'                     |          |Drain          |
'           +------+  |  Gate+---+----+          |
'08M Leg5 --|  1M  |--+------+ IRL520 |          | low power, logic level, fast switching,
'           +------+         +---+----+          |    enhanced N-Channel MOSFET
'                                |Source         |      Voltage = Vout plus safety
'                                |               |      Current ~ 50 to 100uA Adj Current, check the regulator specs
'                                |               |
'   0V  -------------------------+---------------+
'
' NOTES:-
' MOSFET
'  Some MOSFETs seem unstable - 
'  If rate of change of R to Gate voltage is too great oscillation may occur
'  IRL520N and 2N7000 tested OK
' Gate Capacitor ~ 0.2uF
'  Change 0.2uF capacitor to suit MOSFET ~ Range from 0.1uF to 0.47uF can be expected
'  High value slows response to step change
'  Low value increases tendency to hunt around set point.
 
Last edited:

BCJKiwi

Senior Member
Updated code and circuit options

Latest code and circuits posted to 'USER Projects - Miscellaneous'.

Input options include single Pot, coarse/fine Pots and Push Buttons.

Code differs for Pots or Push Buttons.
Code for Pots includes input smoothing (two options) and damping output to MOSFET gate.

Push Button code could be modified to accept the setting number (which should be from 0 to 1023 to match the ReadADC10 on the Feedback side) by replacing (or adding to) the button code, an input routine to receive the setting number.
 
Last edited:

talusd

New Member
I know this is an old thread, but I have a question that concerns me. What happens when there is a short circuit at the output? The voltage will be continually "bumped up" in an attempt to meet the target voltage without ever getting an ADC reading above 0. Then when the short is gone, the voltage could be at the max momentarily, until it corrects itself. This could damage the connected circuit.
 

Dippy

Moderator
Aha. Your mission, should you wish to accept it... :)

If that is the case, the this could be your job then to modify the circuit / code to detect overload and switch off the juice. Easy peasy.
 

Dom B

New Member
Not sure if it has been covered or if i missed the boat on this conversation but as you need to control a pair of resistors i made use of a digital potential divider using a pwmout and a 4066B Quad Bilateral Switch. The pwm can be used quite successfully to make each switch work as a variable resistor, a little bit of circuitry could make the second switch follow in an opposite fashion and hey presto a digital pot.
 

picnoel

New Member
...Three years on
How about using the TOUCH input command for controll - jazz up the front of a PSU a bit, and add an LCD display. I've been toying with adding adjustable current limiting... anyone have any thoughts? would need to go to a 20M2 ore somesuch as we'd run out of pins on an 08M though!
Some code to ponder.. and dissect! Note I have a serial LCD display that uses different values from the SIM LCD in the programming editor.


Code:
 '20M2
SerTxD ("PSU Control by Noel Feb 2012 using 20M2 PicAxe")
SerTxD ("+5V->300R->LineV->FETsource: LineV->0u33->FETgate: LineV->10k->ADC")
SerTxD ("FETgate->1M->lo/hi PIN.  FET=2N7000.")
SYMBOL  LineV = W1
SYMBOL LineI = W2
SYMBOL  Vset = W3
SYMBOL  Iset = W4
SYMBOL  LCD = C.0
SYMBOL  BAUD = T4800_8
'SYMBOL  ESC = 0     'CONTROL Code for REAL LCD
SYMBOL  ESC = 254     'CONTROL Code for SIM LCD
LET   Vset = 50     'Initial Volts * 10
LET  Iset = 020     'Initial Amps  * 10
setfreq M8
pause 1000
High LCD
'SerOUT LCD,BAUD,(esc,esc)    'CLEAR code for REAL LCD
SerOUT LCD,BAUD,(esc,1)     'CLEAR code for SIM LCD

MAIN:
 IF pinB.1=1 THEN LET Vset=Vset+10 endif
 IF pinB.2=1 THEN LET Vset=Vset-10 endif
 IF pinB.3=1 THEN LET Iset=Iset+10 endif
 IF pinB.4=1 THEN LET Iset=Iset-10 endif
TEST:
 'ReadADC10 C.1,LineV    'Read Line (output) Volts
 'ReadADC10 C.2,LineI    'Read Line (output) Amps
 LET LineV = 428     'BOGUS ADC VALUES FOR TESTING
 LET LineI = 22
 
  
Adjust:
  'Scale LineV ADC Value
 LET LineV = LineV*61    'Calculate Voltage 0-1023 : 1-12
 LET LineV = LineV/519    '5.2V => 52 : 12.6V => 126
  
  'LOAD VOLTAGE Decimalisation
 LET B19= VSet/10    'integer math drops decimal portion
 LET B20= VSet//10    'modulus // drops leading 0s
 IF B19< 10 then let B18 = 193 endif'so shift display start if V<10
 IF B19>=10 then let B18 = 192 endif
 
  'SET VOLTAGE Decimalisation
 LET B13= LineV/10    'integer math drops decimal portion
 LET B14= LineV//10    'modulus // drops leading 0s
 IF B13< 10 then let B12 = 129 endif'so shift display start if V<10
 IF B13>=10 then let B12 = 128 endif
  'ADJUST Voltage
 IF Vset > LineV then gosub IncreaseV
 IF Vset < LineV then gosub DecreaseV
 
  'Scale LineI ADC Value
 LET LineI = LineI*82    'Calculate Amps 0-255 : 0-10
 LET LineI = LineI/100    '1.05A => 105
 
  'LOAD CURRENT Decimalisation
 LET B16= LineI/100     'integer math drops decimal portion
 LET B17= LineI//100    'modulus // drops leading 0s
 
  'SET CURRENT Decimalisation
 LET B21= ISet/100     'integer math drops decimal portion
 LET B22= ISet//100    'modulus // drops leading 0s
 
  'ADJUST Current
 IF Iset > LineI then gosub IncreaseI
 IF Iset < LineI then gosub DecreaseI
 
GOTO  DISPLAY
DecreaseV:
 HIGH C.3     'Decreases LineV
 INPUT C.3     'tri-state pin2 and hold LineV
 RETURN
IncreaseV:  
 LOW C.3     'Increase LineV
 INPUT C.3     'tri-state pin2 and hold LineV
 RETURN
DecreaseI:
 HIGH C.4     'Decreases LineI
 INPUT C.4     'tri-state pin6 and hold LineI
 RETURN
IncreaseI:
 LOW C.4     'Increase LineI
 INPUT C.4     'tri-state pin6 and hold LineI
 RETURN
DISPLAY:
  'LOAD VALUES DISPLAY
 SerOUT LCD,BAUD,(esc,B12,#B13,".",#B14,"V LOAD ",#B16,".")
 IF B17<10 then 
  SerOUT LCD,BAUD,("0",#B17,"A") 
 else 
  SerOUT LCD,BAUD,(#B17,"A") 
 endif
 
  'SET VALUES DISPLAY
 SerOUT LCD,BAUD,(esc,B18,#B19,".",#B20,"V MAX  ",#B21,".")
 IF B22<10 then 
  SerOUT LCD,BAUD,("0",#B22,"A") 
 else 
  SerOUT LCD,BAUD,(#B22,"A") 
 endif
 
GOTO MAIN
 
Top