ok programming is complete for now here it is in all its gore.
This is the first time I have seen anything like this on the net... so I have tried to make it as complete as possible
There is some interest in the AC coupled version of this which I will do soon.
========================================================================================
/*program to use for driving a 3 stage charging device via pwm.
The program will use the floatVolts,bulkCharge and absorbCharge values to control the set points.
pin3analog will be the voltage sense from a 0-5v input from a voltage divider for measuring the
voltage from the battery. Standard 1602 LCD is assumed.
Stay in bulk until 59v, then run absorb for a few hpours, and then float at 57 for the rest of the day.
The time is in the long timedOut constant. If the battery voltage drops to less than startAllOverAgain ( nominal 860 for about 50volts ) then it reverts to bulk
charge again, ready for the next day etc.
Voltage read is the " lcd.print (val/16.99);" line, the 16.99 can be changed to calibrate the voltage to match the real world.
output is from pin6. It can drive a opto or totem pole driver for the fet.
Also is simple 5 stage averaging
........oztules
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);//define lcd pins 12,ll control 10-7 data
int R1=0;
int R2=0; // these R ints are simply for reading multiple times for averaging
int R3=0; // this shows a fear of arrays and for routines
int R4=0;
int R5=0;
int realValue=0;
int inputPin=3;
long fullTime=0; // timer for float stage #2
long bulkTime=0; //timer for stage 1 bulk
int ledPin = 6; // fet gate connected to this pin via totem or similar driver digital pin 6
int stage1pin =2;
int stage2pin =3; // led pin outputs for visual display from distance
int stage3pin =4;
int analogPin = 3; // divided voltage from battery or transformer if thats your go;
int val = 0; // value of voltage query
int count=0; // count for display timing.... stop screen jitter
int pulseVal = 0; // initilise the pulse width to zero of 255.... won't help really as the thing will run for three minutes before kick off
long floaTime=0; // initialise the time to zero for the absorb
int floatVolts = 970; // compared to the figure of the bulk and absorb...
int bulkCharge = 1004; // figured that 1000 would do as the set point for absorb voltage
int absorbCharge =1004; // voltage equivalent for the absorb voltage.... same as bulk.... funny about that.
int startAllOverAgain = 850; // probably in the 49v range
long timedOut = 54000; // time delay for absorb and step rate will change this...54000=2hrs.. sort of...
int increment = 10; // how much to change each pulse width for voltage control definition
int weAreHereNow=0; // initialize the start stage as zero
void setup() // this is where the story starts...
{
lcd.begin(16, 2);
pinMode(ledPin, OUTPUT); // sets the pin 6 as an output for the fet drive
pinMode(stage1pin, OUTPUT);
pinMode(stage2pin, OUTPUT); // set led pins as outputs
pinMode(stage3pin, OUTPUT);
Serial.begin(9600);
}
void loop() // and this is where the story really starts
{
Serial.print("pulseVal =" ); // This display on the laptop tells us a bit about what it sees so as to calibrate
Serial.print(pulseVal); // what the pulse value will mean to other parameters
Serial.print(" real value ="); //show and tell time is another word for this routine
Serial.print(realValue); // shows the averaged value
Serial.print(" val value ="); //show and tell time is another word for this routine
Serial.print(val); // shows the averaged value
//example of line ....pulseVal =240 read value =413 bulktime value =0 absorb time value =0 float time value =0 weAreHereNow =0
// pulseVal=pwm pulse output
// read value is the actual value the nano sees on pin 3... so we can equate all things to this, ie voltage.. then calculate puse width etc
// the rest are values of current timers in use at the time.
Serial.print(" bulktime value =");
Serial.print(bulkTime);
Serial.print(" absorb time value ="); //three timers
Serial.print(floaTime);
Serial.print(" float time value =");
Serial.print(fullTime);
Serial.print(" weAreHereNow =" ); // stage number currently displaying
Serial.println (weAreHereNow);
delay(10); // use this to speed things up and down.... responsible for the timing number calculation
//===========show the current volts with slow up routine called count.==========
if (count==10) // every 10 counts, we will display only to keep screen stable
{
if (val<startAllOverAgain )
{
lcd.setCursor(0,1);
lcd.print("Pre-bulk volts");
}
if (weAreHereNow==0 && val>startAllOverAgain) // if stage 1 then we do this routine
{
lcd.setCursor(0,1);
lcd.print("Bulk = ");
lcd.setCursor (8,1);
lcd.print(bulkTime/450); // makes it about a minute update at 450.. ish
lcd.print(" min");
}
if (weAreHereNow==1) // if stage 2 then we do this screen routine
{
lcd.setCursor(0,1);
lcd.print("Absorb ");
lcd.setCursor (8,1);
lcd.print(floaTime/450); // makes it about a minute update at 450.. ish
lcd.print(" min ");
}
if (weAreHereNow==2)
{
lcd.setCursor(0,1);
lcd.print("Float ");
lcd.setCursor (8,1);
lcd.print(fullTime/450); // makes it about a minute update at 450.. ish
lcd.print(" min ");
}
lcd.setCursor(0, 0);
lcd.print("Volts = "); // print the volts out
lcd.setCursor (8,0); // the if count is to slow the screen update to the value of if count=x
lcd.print (val/16.99);// voltage correction.... change the number
count=0;
}
count=(count+1); // increment the counter for printing to stop wobble
//====================this section just for song and dance and twinkly lights
if (weAreHereNow==0)
{
digitalWrite (stage1pin,1); //digital pin 8 will light up for the bulk charge bit
}
else
{
digitalWrite (stage1pin,0);
}
if (weAreHereNow==1) // this lights up digital pin 9 to signal stage 2 the absorb cycle
{
digitalWrite (stage2pin,1); // this is all to light up leds to see where we are in the cycle
}
else
{
digitalWrite (stage2pin,0);
}
if (weAreHereNow==2)
{
digitalWrite (stage3pin,1); //this lights up stage 3.. the float cycle pin 10
}
else
{
digitalWrite (stage3pin,0); // remember if we drop below about 48v it will reset everything, the leds will show this too.
}
//======================================================= =========================================
R1= analogRead(inputPin); // we go and read the input pin 5 times in rapid succession
R2= analogRead(inputPin);
R3= analogRead(inputPin); // poor mans averaging routine. probably as fast or more than normal ones.
R4= analogRead(inputPin); // having read the same pin 5 times, we can go and average the result... my sort of simple averaging.
R5= analogRead(inputPin);
realValue=(R1+R2+R3+R4+R5)/5; // we do the average here
val = realValue; // it all hinges on this value. 5 readings averaged
if (val>=bulkCharge && weAreHereNow==0) // if we achieve 59v (bulk chg) AND we were in stage zero then change weAreHereNow to 1 as a flag ie absorb
{
weAreHereNow=1; // weAreHereNow=1 is absorb status
}
//=============bulk routine==============
if ( weAreHereNow==0) // if in stage 1 then check voltage against bulk charge constant ... can be set in definitions
{
bulkTime=bulkTime+1;
if (val< bulkCharge)
{
pulseVal=pulseVal + increment; // was not up to bulkCharge, then increase pulse width incrementally
}
if (val>bulkCharge)
{
pulseVal=pulseVal-increment; // if over the preset bulk voltage ... then back the pwm off a bit
}
if ( pulseVal>=255)
{
pulseVal=255; // if pulse width calculation exceeds 255 then just make it 255
}
if ( pulseVal<=0)
{
pulseVal=0; //if pulse width calculation is below zero, then make it zero instead
}
}
//==========absorb routine==============
if ( weAreHereNow==1) // if we are in absorb then do this
{
{
floaTime=floaTime+1; // check if time elapsed in absorb is up or not (timedOut constant)
}
if (floaTime>=timedOut) // once we reach timedOut, we have finished our absorb sequence, change status flag weAreHereNow to 2, and change the voltage now to float value
{
weAreHereNow=2;
}
if (val< absorbCharge)
{
pulseVal=pulseVal + increment; // was not up to bulkCharge, then increase pulse width incrementally
}
if (val>absorbCharge)
{
pulseVal=pulseVal-increment;
}
if ( pulseVal>=255)
{
pulseVal=255; // seen all this before
}
if ( pulseVal<=0)
{
pulseVal=0;
}
}
//=========float routine=======
if ( weAreHereNow==2) // are we in float charge stage
{
fullTime=fullTime+1; // increment float timer
if (val< floatVolts)
{
pulseVal=pulseVal + increment; // was not up to bulkCharge, then increase pulse width incrementally
}
if (val>floatVolts)
{
pulseVal=pulseVal-increment; // keeping charge in the float band....floatVolts is the constant we use
}
if ( pulseVal>=255)
{
pulseVal=255;
}
if ( pulseVal<=0)
{
pulseVal=0;
}
}
//==============================write the pulse to the fet======================
analogWrite (ledPin,pulseVal); // actually write the data to the fet via pin 6 ...
//=============================================
if (val<startAllOverAgain) // panic/reset routine when voltage drops back to 48 volts or so.
{
weAreHereNow=0;
bulkCharge=absorbCharge;
floaTime=0;
bulkTime=0;
fullTime=0;
}
}
//thats all folks
For the sake of completedness, this is the circuit board that it refers to and works with.
jumper added for GTI use compared to the last one
click to increase size
.............oztules