Control Fans and output voltage of Power Supply via PWM, please check my code

Hi!

This is my first posting here, so I hope I am doing everything alright.
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:

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 50A
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/geradedurchzweipunkte.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.

Thanks for reading,

Julez

###############

void setup()
{
  pinMode( 2, OUTPUT);
  pinMode( 3, OUTPUT);
  pinMode( 2 , OUTPUT);
  pinMode( 3 , OUTPUT);
  delay( 5000 );

  analogWrite(3 , 0);

  analogWrite(2 , 255);

  delay( 2500 );

  analogWrite(3 , 255);

  delay( 2000 );

}

void loop()
{
  if (( ( analogRead(1) ) < ( 140 ) ))
  {
    analogWrite(2 , 77);
  }
  else
  {
    analogWrite(2 , ( ( ( 178 / 163 ) * analogRead(1) ) - ( 12903 / 163 ) ));
  }
  if (( ( analogRead(1) ) < ( 800 ) ))
  {
    analogWrite(3 , 255);
  }
  else
  {
    analogWrite(3 , ( ( ( -255 / 82 ) * analogRead(1) ) + ( 114495 / 41 ) ));
  }
}

You should invest $10 (for ADS1015 12-bit adc) or $18 (for the ADS1115 16-bit ADC ) from adafruit. I just tested my ADS1115 last night. For 5V input , I read 26500 counts. With the built in adc on the arduino , you will read 1023. The resolution is 25 times greater
Which would you rather have 150A divided into 1023 counts or 150A divided into 22,790 counts ?

Hello raschemmel,

thanks for your input. I just calculated that I will have 163 steps for the fan control (0,7 to 1,5V), and 83 steps for the current control (4.0 to 4.4V).

Do you think that this resolution is not enough? Things are rather noisy in such a power supply anyhow. 60mV ripple is not unheard of. This is the output, so not strictly relating to the CS voltage, but as this is measured against the output negative, I would gess that the resolution of 0,0049V and the ripple of 0,06V mean that the readings will already be affected by noise, and increased resolution will not improve things.
(Mental note: Connect Pin 1 to ground with a capacitor, and put resistor in cable from CS Pin).

Regards,

Julez

I'm just saying that if you would rather have crappy resolution than spend $10 - $20 then more power to you. You only have as much noise as you are willing to put up with. If you don't want the noise then do something about it instead just accepting it laying down. There's two ways to do things , the half-assed way , and the right way. If you can't afford the ADC then that's another story , but if you can afford all that expensive RC crap (my garage is full of it) , then you can afford a lousy $10 or $20 ADC.
I's up to you You're only controling fans so it's not like it's mission critical or anything, but the way you presented your idea it sure
made it sound like everything revolved around sensing the CS. I just thought that it would be obvious that the response time of a PID or feedback loop would be a function of the precision (and sampling time) of the "sense" function. It's a trade off. The arduino can sample 10,000 times per second (10-bit resolution), while the ADS1115 can only sample 860 times /sec because it's 16-bit resolution. You have to decide what's more important, resolution or speed. You can't have both.

Thanks for helping.
If, during testing, I should get the feeling that there are problems because of the lowish input resolution, I will get back to you. :slight_smile:

Meanwhile, I have improved the code a little.
First problem was that I got an output not in the range of 0 to 255 for the analog pins, which is not admissable, I think.

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:

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);
}
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);

}

click the MODIFY button in the upper right of the post window.
Highlight all you code.
click the "#" CODE TAGS button on the toolbar above just to the left of the QUOTE button.
click SAVE (at the bottom).
When you post code on the forum, please make a habit of using the code tags "#" button.

As far as resolution, that's probably good enough for you.
Regarding the noise. Adding filter caps should smooth out the ripple, the largest ones you can afford.
Also , for the ripple , the way to tell if it affects your readings is to see if the values go up and down. If they are filtered somehow then they won't show up in the data but if the data shows the voltage "zig-zagging " up and down instead of following a steady rate then I would say the ripple is a factor but your curve does not show that. It shows a steady increase so the ripple is not a problem.