I am trying to figure out codes to control relays switches base on voltages of 2 battery.
First i will do the analogue read of the battery voltages, using the battery with the higher voltage to power a circuit and battery with the lower voltage to be charged from another circuit. Then the battery with lower voltage will be put in the charging position till it get to 14.5v or if the battery powering the circuit drops to 12.2v.
After the "if" conditions are sorted, and when it runs the "do..while" portion of the code, will it just loop the "do..while" portion code till the condition are met before it go back to the main loop?
Not sure if i am using the "do..while" correct. Do i need to add in the analogue read code for getting the value of vin1 and vin2 as part of the loop?
if (vin1 > vin2) {
goto state1;
return;
}
if (vin2 >= vin1) {
goto state2;
return;
}
state1:
do {
digitalWrite(Relaypin1, HIGH); // charging batt2
} while (vin1 >450 && vin2 <=538);
state2:
do {
digitalWrite(Relaypin1, LOW); // charging batt1
} while (vin2 >450 && vin1 <=538);
Yes, otherwise how is the loop to know that anything had changed?
You might want to put in some hysterisis also - perhaps read the 2 inputs once a minute and change which battery gets charged then, that way you don't end up in a situation where both are close to being fully charged and you end up oscillating back & forth rapidly.
While you incorporate Crossroads' suggestions, you might want to also get rid of, you know, those statements - wouldn't want to get a visit from the goto police
void loop(){
// read the value on analog input
Volt:
value1 = analogRead(analogInput1);
value2 = analogRead(analogInput2);
vout1 = (value1 * 5.0) / 1024.0;
vin1 = vout1 / (R2/(R1+R2));
vout2 = (value2 * 5.0) / 1024.0;
vin2 = vout2 / (R4/(R3+R4));
Serial.print(vin1);
Serial.println(" volt");
Serial.print(vin2);
Serial.println(" volt");
delay(refresh);
if (vin1 > vin2) {
state1;
return;
}
if (vin2 >= vin1) {
state2;
return;
}
if (vin1 >=538 && vin2 >=538){
state3;
return;
}
state1:
do {
digitalWrite(Relaypin1, HIGH); // charging batt2
} while (vin1 >450 && vin2 <=538);
state2:
do {
digitalWrite(Relaypin1, LOW); // charging batt1
} while (vin2 >450 && vin1 <=538);
state3:
digitalWrite(Relaypin2, LOW); // off power to charging circuit
goto sleep;
}
This is the code with the analogue read portion. Clarification, do i need to repeat the "value:" portion of the code within the "do...while" portion again?
Hi wildbill,
Do you meant that i can just skip the 'goto' as revised?
Using goto in C and languages like it is usually unnecessary and, these days, is frowned on because it makes the code harder to read and maintain. The algorithm you're trying to code certainly doesn't need any - you can do what you want with a few nested if statements.
As to your do while loops, don't forget that loop is being called repeatedly - they are unnecessary. If you do decide to use them though, all that code that reads the batteries and calculates vin1 and vin2 will need to be invoked inside them. Putting that code in a function would at least avoid having to copy it into your loops as is - you would just call the function in three places.
Best though is to let loop handle the repetition: get vin1 and vin2 every time through it and decide what to do & set the relay pins accordingly. To crossroads' point, use millis or delay to ensure that you're not turning relays on and off every few milliseconds when the batteries are near full charge.
My problem is this. At the start of the loop, say if vin1 is more than vin2. Then it goes to say charging state1, but during the charging state, vin2 can get higher than vin1 and cause a stop to the charging and jumps to charging state2 to charge the other battery. Hence i was thinking of using 'while' or 'do while' to create that charging loop to keep it charging till it met the condition.
void loop(){
// read the value on analog input
Volt:
value();
Serial.print(vin1);
Serial.println(" volt");
Serial.print(vin2);
Serial.println(" volt");
delay(refresh);
if (vin1 > vin2) {
state1;
return;
}
if (vin2 >= vin1) {
state2;
return;
}
if (vin1 >=538 && vin2 >=538){
state3;
return;
}
state1:
do {
value();
digitalWrite(Relaypin1, HIGH); // charging batt2
} while (vin1 >450 && vin2 <=538);
state2:
do {
value();
digitalWrite(Relaypin1, LOW); // charging batt1
} while (vin2 >450 && vin1 <=538);
state3:
digitalWrite(Relaypin2, LOW); // off power to charging circuit
goto sleep;
}
void value(){
value1 = analogRead(analogInput1);
value2 = analogRead(analogInput2);
vout1 = (value1 * 5.0) / 1024.0;
vin1 = vout1 / (R2/(R1+R2));
vout2 = (value2 * 5.0) / 1024.0;
vin2 = vout2 / (R4/(R3+R4));
}
So something like this:
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long elapsedMillis = 0;
unsigned long duration = 60000UL;
void setup(){
whatever you had here
}
void loop(){
value1 = analogRead(analogInput1);
value1 = analogRead(analogInput1); // read it twice to get an accurate value
value2 = analogRead(analogInput2);
value2 = analogRead(analogInput2); // read it twice to get an accurate value
vout1 = (value1 * 5.0) / 1024.0;
vin1 = vout1 / (R2/(R1+R2));
vout2 = (value2 * 5.0) / 1024.0;
vin2 = vout2 / (R4/(R3+R4));
currentMillis = millis(); // capture the "time"
elapsedMillis = currentMillis - previousMillis; // how much passed?
// I have seen several times that doing too much 'math' inside "if ( conditions)" doesn't work, so I do the unsigned long math seperately
// you can try this, it may work: if ( ( (currentMillis - previousMillis) >=duration) && (vin1 <538 || vin2 <538)){
if ( ( elapsedMillis >=duration) && (vin1 <538 || vin2 <538)){
// if one minute elapsed and either battery needs charging, then 1 of these will be valid each pass thru the loop
previousMillis = currentMillis; // reset the time
if ( (vin1>=vin2) && (vin1 >450 && vin2 <=538)){ // use >= just in case there's that 1 in a million occurrence of them being equal
digitalWrite(Relaypin1, HIGH); // charging batt2
}
if ( (vin2>vin1) && ((vin2 >450 && vin1 <=538) {
digitalWrite(Relaypin1, LOW); // charging batt1
}
} // end time check
} // end void loop
Say vin1 start more than vin2 so vin2 is put to charge. But during charge vin2 can go higher than vin1 but not fully charged, it will break the condition and jump to charge the other battery(vin1).
What i need the program to do is once the it determined which battery to charge, it will to continue to charge that battery till full or if the powering battery drops below 12.2v before going back to compare the vin1 and vin2 value again. Instead of flip flopping between the 2 batteries.
Not sure if i have misunderstood the suggested code.
I may have misunderstood your intended operation as well.
You can set a flag to indicate "charging battery 1", and then set your if conditions to keep charging battery if the flag is set, checking its state once a minute or as you see fit, once its full clear the flag,
then go back to checking if either needs charging.
Same for battery 2.
Maybe add a sanity check in there too - if the battery has been charging for xx hours, and still not charged, issue some kind of error statement and give battery 2 a chance to get back in the game.
What type of batteries are you using? You could just charge your batteries as you use them. Unless you are using NiCads or NiMh, I can't think of a reason to be switching batteries.
Cross Roads, thanks for the pointer. Did that correction quite a bit of other changes after that and seems to work ok now. The while command does make the charging goes to the full termination charge of 14.5v before switching state.
Added the serialprint line to check the function via the serial monitor. Quite useful. Perhaps the return has no meaning, i don't really know
Copied that from somewhere else.
Not really final but the basic stuff work in this one. I want to change the delay after each while loop to give a 30mins rest after each charge cycle before they switch role. Will add an additional relay to off the charge circuit entirely and figure out if there is an appropriate sleep mode that i can use when they both get fully charged.
// global variables for input pin and control Relay
int analogInput1 = 1; //initial primary batt sensor
int analogInput2 = 2; //initial charge or gen coil batt sensor
int Relaypin1 = 4;
int Relaypin2 = 5;
int Charging = 13;
int Charged = 12;
int refresh = 1000;
float vout1 = 0.0;
float vin1 = 0.0; // batt1 voltage
float vout2 = 0.0;
float vin2 = 0.0; // batt2 voltage
float R1 = 98600.0; // !! resistance of R1 !!
float R2 = 21800.0; // !! resistance of R2 !!
float R3 = 99720.0; // !! resistance of R3 !!
float R4 = 21820.0; // !! resistance of R4 !!
// variable to store the value
int value1 = 0;
int value2 = 0;
void setup(){
// declaration of pin modes
pinMode(analogInput1, INPUT);
pinMode(analogInput2, INPUT);
pinMode(Relaypin1, OUTPUT);
pinMode(Relaypin2, OUTPUT);
pinMode(Charging, OUTPUT);
pinMode(Charged, OUTPUT);
// begin sending over serial port
Serial.begin(9600);
}
void loop(){
// read the value on analog input
value();
if (value1 > value2) {
while (value1 >450 && value2 <=538){
value();
digitalWrite(Relaypin1, HIGH); // charging batt2
Serial.println("state1");
delay(refresh);
}
return;
}
if (value2 >= value1) {
while (value2 >450 && value1 <=538) {
value();
digitalWrite(Relaypin1, LOW); // charging batt1
Serial.println("state2");
delay(refresh);
}
return;
}
}
void value(){
value1 = analogRead(analogInput1);
value2 = analogRead(analogInput2);
vout1 = (value1 * 5.0) / 1024.0;
vin1 = vout1 / (R2/(R1+R2));
vout2 = (value2 * 5.0) / 1024.0;
vin2 = vout2 / (R4/(R3+R4));
Serial.print(vin1);
Serial.println(" volt Batt1");
Serial.print(vin2);
Serial.println(" volt Batt2");
delay(refresh);
}
Got an RTC in your system too?
You can go into powedown sleep mode, use the 1 Hz out of the RTC to interrupt/wakeup & checkt the time, then go back to sleep & wait some more.
Or if not actively sleeping, just read the time & watch for 30 minutes to go by.
Also use to determine if battery is not charging after some time & send up an error flag.
Of if you have current monitoring in place, check that current draw is not excessive, indicating a fault condition, bad battery, etc.