May 24, 2014, 05:25 AM
Proud to eat Kraut ;-)
Germany
Joined Dec 2003
5,356 Posts
Help!
Arduino:Control Fans and output voltage of Power Supply via PWM, please check my code

Hi!

So far, I have practically no coding experience, but I found the
"ardublock" software, so this is where my code comes from.

Basically, I have two tasks to perform. Both are related to this power
supply, a DPS-2000BB:

http://www.rcgroups.com/forums/showp...&postcount=611

I will use the PS to power my armada of RC chargers.

I want to make a fan control depending on the output current, and I want
to lower the output voltage when the PS is near it's limit, which is
around 160A.
Thankfully, the PS has a so-called "current share" pin called "CS" from
now on. Here, the voltage rises when the current rises, so it would be
possible to roughly estimate the current depending on the voltage here.
It is a bit non-linear at the beginning:
0.36V at 0A
0.78V at 2A
1,50V at 52A
4,30V at 150A

Also, one can raise the output voltage from 12.5V to 14.5V by connecting
the 5V output (I also intend to power the arduino from) to the sense pin
via a trimmer, which can be adjusted, and so the voltage can be
adjusted. This will later be important for the current control.

Let's assume in the program that Pin 1 reads analog the CS voltage, Pin
2 writes analog PWM to control the fan, and Pin 3 writes analog PWM to
lower the output voltage.

My thinking so far on the fan control:

I want the fan to run at 30% when the CS voltage is <0.7V. I want it to
run at 100% when the CS voltage is >= 1,50V.
I informed myself a little about the math the arduino does when reading
analog and writing analog PWM, and created a formula which will convert
any CS voltage in the range of 0.7 to 2.0V into a PWM value between 30%
and 100% in a linear manner.
I used this graph calculator to determine the mathematical function which converts the analog input to the desired PWM output in a linear manner:
http://www.arndt-bruenner.de/mathe/9...zweipunkte.htm

This PWM I will feed to a NPN transistor which will control my fan(s).

Output voltage control:

First, one has to understand that my RC chargers are programmed to lower
their input current when their input voltage (=output voltage of the PS)
approaches 12.5V, similar to a supply battery which has lower voltage
when being drained.

So, I am going to read the CS voltage, and when I reach and overshoot a level which
corresponds to around 140A output (4.0V), I want to gradually reduce the PWM on
Pin 3 from 100% to 0%. 0% is when the current approaches 157A (4.4V).

To achieve this, I will not connect the sense pin with a trimmer
directly to 5V as usual, but to Pin 3 of the Arduino (trimmer still in between).

If the current is below 140A, this Pin will provide a steady 5V, so the
power supply will have 14.5V, as if the sense pin was connected directly
to the 5V.

If the current is at 157A, the PWM will arrive at 0%, meaning 0V, and
thus the PS will only have 12.5V, as if the sense Pin was NOT connected
to the 5V.

In between, the PWM will vary, and so the PS output voltage will depend
on the load between 140A and 157A, to avoid rapid changes, which the
chargers don't like.

One question of the PWM in general: I read it works with around 490Hz,
but the arduino works with 16MHz. So, multiply cycles are computed while
the PWM creates just one pulse. How often is the PWM updated then? It
can't possibly be within one pulse.

Another thing which would be nice is a feature to prevent oscillations in the range where the output voltage gets reduced. It would be nice if the PWM could be reduced as quick as possible, when the overcurrent situation exists. But without overcurrent, it should be able to rise only 5% per second once it was reduced, so for example it would take 20s to rise from 0% to 100%.

OK, enough talk, here is my first program. Does it look ok and will
perform as I intend?

I just ordered an Arduino Uno, 5 pieces Mini, some breadboars and jumper cables today, so it will need a week or two until I can do practical tests.

Julez

###############
Code:
```void setup()
{
pinMode( 2, OUTPUT);
pinMode( 3, OUTPUT);
pinMode( 2 , OUTPUT);
pinMode( 3 , OUTPUT);  no idea what this is
delay( 5000 ); allow PS to boot properly

analogWrite(3 , 0); set voltage to 12.5V

analogWrite(2 , 255); set fans to 100% PWM

delay( 2500 ); wait for the fans to spool up

analogWrite(3 , 255);  set voltage to 14.5V

delay( 2000 ); wait for fans to spool up with the higher voltage

}

void loop()
{
if (( ( analogRead(1) ) < ( 140 ) ))  if CS below 0.7V
{
analogWrite(2 , 77); then set fan PWM to 30%
}
else
{
analogWrite(2 , ( ( ( 178 / 163 ) * analogRead(1) ) - ( 12903 / 163 ) )); else set Fan PWM % according to CS voltage
}
if (( ( analogRead(1) ) < ( 800 ) )) if CS is less than 4V (140A)
{
analogWrite(3 , 255); set voltage control PWM to 100%
}
else
{
analogWrite(3 , ( ( ( -255 / 82 ) * analogRead(1) ) + ( 114495 / 41 ) )); Else reduce voltage control PWM according to CS voltage
}
}```

# Images

Last edited by Julez; May 25, 2014 at 12:57 PM.
May 24, 2014, 07:22 PM
We want... Information!
Hastings, New Zealand
Joined Jan 2001
5,191 Posts
Quote:
 Originally Posted by Julez How often is the PWM updated then? It can't possibly be within one pulse.
It will only change once per cycle, but can be 'updated' multiple times during that cycle. PWM is generated by comparing a timer to a register. If the register is updated before the timer reaches a match then the PWM ratio will change in the current cycle, otherwise it has to wait until the next cycle.

Quote:
 OK, enough talk, here is my first program. Does it look ok and will perform as I intend?
Your code looks good, but it may not work as well as you hoped. The difference between 140A and 157A is not much, and your code has no delay to ensure that the power supply (and chargers!) can keep up with the rate of voltage change. The result will probably be (as your feared) oscillation in this region.

Quote:
 pinMode( 2, OUTPUT); pinMode( 3, OUTPUT); pinMode( 2 , OUTPUT); pinMode( 3 , OUTPUT); no idea what this is
The code is setting pins 2 and 3 to output mode twice, which is redundant.
May 24, 2014, 08:12 PM
We want... Information!
Hastings, New Zealand
Joined Jan 2001
5,191 Posts
Quote:
 Originally Posted by Julez analogWrite(3 , ( ( ( -255 / 82 ) * analogRead(1) ) + ( 114495 / 41 ) )); Else reduce voltage control PWM according to CS voltage
I checked your math and it doesn't seem to work out.

255/82 = 3
114495/41 = 2792

If analogread(1) = 800 then the resulting PWM ratio is 392, which is higher than the maximum permissible (255).

At the other end you have a problem if current exceeds 157A, because the PWM ratio could go negative. You should limit the scaled current value to 2792 max, to ensure that the PWM ratio can't go below zero.
 May 25, 2014, 06:45 AM Proud to eat Kraut ;-) Germany Joined Dec 2003 5,356 Posts Hi Bruce, thanks for your comments, they help me a lot. My math works, but only in the range I intend to control. So far, I assumed that any PWM value >255 would result in 255, and any value <0 would result in 0. Is this wrong? If so, I would have to define a precise range in which the formulas are applied, and manually set the PWM to 0 or 255 out of that range. Do you have any idea what could be done about the oscillations? It would be great if the volage reduction would work instantly, but the voltage increase was pretty slow, as I described. Edit: I think that I have now resolved both issues. Instead of assigning a value to the analog Pins directly, I now work with variables. At the end of the computations, the variables are checked if they are in the range of 0 to 255, and if not, they are brought to that range. <0 -->0 >255 -->255 Concerning the oscillations, I have abandoned the idea of defining a range in which the voltage is regulated according to the current. I have defined a max treshold (150A), over which the voltage is reduced quickly with each computing cycle. The whole range (255 to 0) would be covered in 5sec. I have also defined a min treshold (140A), under which the voltage is increased slowly with each computing cycle. The whole range (0 to 255) would be covered in 25sec. In the range of 140A-150A no voltage change takes place. This way, the operating point is pushed into this window from both sides with different speeds, which should provide enough dampening to prevent any oscillations. Here is the code: Code: ```int _ABVAR_1_voltage = 0 ; int _ABVAR_2_fan = 0 ; void setup() { pinMode( 5, OUTPUT); pinMode( 6, OUTPUT); delay( 5000 ); analogWrite(6 , 0); analogWrite(5 , 255); delay( 2500 ); analogWrite(6 , 255); delay( 2000 ); _ABVAR_1_voltage = 255 ; _ABVAR_2_fan = 255 ; } void loop() { if (( ( analogRead(1) ) < ( 140 ) )) { _ABVAR_2_fan = 77 ; } else { _ABVAR_2_fan = ( ( ( 178 / 163 ) * analogRead(1) ) - ( 12903 / 163 ) ) ; } if (( ( _ABVAR_2_fan ) < ( 0 ) )) { _ABVAR_2_fan = 77 ; } else { if (( ( _ABVAR_2_fan ) > ( 255 ) )) { _ABVAR_2_fan = 255 ; } } analogWrite(5 , _ABVAR_2_fan); if (( ( analogRead(1) ) > ( 917 ) )) { _ABVAR_1_voltage = 0 ; } else { if (( ( analogRead(1) ) > ( 878 ) )) { _ABVAR_1_voltage = ( _ABVAR_1_voltage - 1 ) ; delay( 20 ); } if (( ( analogRead(1) ) < ( 817 ) )) { _ABVAR_1_voltage = ( _ABVAR_1_voltage + 1 ) ; delay( 100 ); } } if (( ( _ABVAR_1_voltage ) < ( 0 ) )) { _ABVAR_1_voltage = 0 ; } else { if (( ( _ABVAR_1_voltage ) > ( 255 ) )) { _ABVAR_1_voltage = 255 ; } } analogWrite(6 , _ABVAR_1_voltage); }``` Last edited by Julez; May 25, 2014 at 12:57 PM.
May 25, 2014, 04:00 PM
We want... Information!
Hastings, New Zealand
Joined Jan 2001
5,191 Posts
Looks good. Now you just have to try it out!

Quote:
 Originally Posted by Julez I assumed that any PWM value >255 would result in 255, and any value <0 would result in 0. Is this wrong?
In programming it is never a good idea to assume that out of bound values will be properly handled by the compiler or operating system.

The Arduino documentation for analogWrite says
"value: the duty cycle: between 0 (always off) and 255 (always on)."
Since its response to values outside this range is not documented, that means it is undefined and could do anything.

Looking into the source code for analogWrite (wiring_analog.c) we see that the signed 16 bit integer 'val' is jammed directly into the 8 bit Output Compare Register. Therefore any value less than 0 or greater then 255 will 'wrap around' (eg. -1 becomes 255).

You might, ask why didn't the Arduino designers put in some code to limit the range to sensible values? The reasons are:-

1. It would unnecessarily slow down the function and increase code size.

2. Out of range values won't damage the hardware or crash the firmware.

3. The documentation states that it must be between 0 and 255.
 May 25, 2014, 04:17 PM Proud to eat Kraut ;-) Germany Joined Dec 2003 5,356 Posts Thanks, good to know! I tested the code in an Arduino simulator, and it should work es intended. Now I just have to wait for the hardware in the mail.