View Single Post
Old 03-22-2014, 03:52 PM   #10 (permalink)
mechman600
Master EcoModder
 
mechman600's Avatar
 
Join Date: Jul 2008
Location: Langley, BC
Posts: 1,228

Fusion - '16 Ford Fusion Hybrid SE
Thanks: 190
Thanked 275 Times in 168 Posts
Now on to the charger monitoring side. I paid a solid $14 for this Arduino and plan to get all my money's worth!

Currently (PUN!), I have six 12V chargers. They put out 10A up to 14.7V and then hold 14.7V until the current drops down enough to switch to a 13.8V float. Too see what's going on remotely, I go look at my Kill A Watt, which I have learned to interpret pretty well. But this involves going down to the garage. I know, I know, first world problem, but wouldn't it be nicer to simply look out the window and see an LED status light flashing in the car? Yes, yes it would.

I always look at the Kill A Watt at the beginning and end of a charge to make sure all chargers were working because I had a near fatal (from a battery's perspective) incident where a fuse popped in one charger without me noticing. I haven't gotten there yet, but my future code will watch for differences in voltages between banks and flag a warning LED and message (or text me if I buy a GSM Arduino shield?) if something is out of whack.

Anyway, here is a circuit simulation:


And here is the code for this part. Many things will cross over from the battery fuel gauge code, as they will share the same inputs and logic.

EDIT: I played around with it more and found that if the charger was turned off with the switch before it was finished, it would assume that it was on float and would start the float timer, permanently cutting off the charger relay (ch_enable pin) unless the arduino was reset. This, combined with possible reliability issues, has led me to use a SPDT switch - OFF, charge and charge with float timer, requiring two pins. I have changed the code below to reflect this.

Quote:
/*
The electric Booger charging monitor screen
This code monitors charging voltage and determines when a) volt limiting charging has been reached
(MODE 2) and when float has been reached (MODE 3), where a timer (turned on by ch_butt2) will automatically
turn the charger off with ch_enable.
*/

#include <LiquidCrystal.h>

const int voltPin = 0;
const int displ = 8; // Turn LCD screen on/off with acc power
const int ch_butt1 = 7; // Charge without float timer
const int ch_butt2 = 10; // Charge with float timer
const int ledPin = 6; // Charge indicator LED, mounted on right side of dash
const int ch_enable = 13; // 120V relay to power chargers

int float_delay = 0; // How long float charge will last
float amps = 0;
float c_amps = 0;
float volts = 0;
int watts = 0;
float ampHour = 0;
float kWh = 0;
long sample = 0;
long time = 0;
float totCharge = 0;
float avgAmps = 0;
long ch_count = 0;
int charge_mode = 0;
int charge_latch = 0;
int ledState = LOW;
long previousMillis = 0;
int ledInterval = 0;
int ch_en_latch = 0;
int ch_en_sig = 0;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
byte batt1[8] = { // These two together make a nice battery symbol
B01100,
B11111,
B10000,
B10010,
B10111,
B10010,
B11111,
};
byte batt2[8] = {
B00110,
B11111,
B00001,
B00001,
B11101,
B00001,
B11111,
};
byte timer[8] = {
B11111,
B10001,
B01110,
B00100,
B01010,
B10001,
B11111,
};

void setup() {
lcd.begin(20, 4);
pinMode(voltPin, INPUT);
pinMode(displ, INPUT_PULLUP);
pinMode(ch_butt1, INPUT_PULLUP);
pinMode(ch_butt2, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(ch_enable, OUTPUT);
lcd.createChar(0, batt1);
lcd.createChar(1, batt2);
lcd.createChar(2, timer);
}
void loop() {
if(digitalRead(displ) == LOW) {
lcd.noDisplay();
} else {
lcd.display();
}
if(digitalRead(ch_butt1) == LOW) { // Charge start button
ch_en_latch = 1;
float_delay = 90000;
} else if(digitalRead(ch_butt2) == LOW) {
ch_en_latch = 2;
float_delay = 25;
} else {
ch_en_latch = 0;
float_delay = 90000;
ch_count = 0;
}
amps = 0; // Simulated value for testing
volts = analogRead(voltPin) / 11.6; // Simulated volt value from 5K POT
c_amps = -amps; // If current goes backwards, start working/counting
if(c_amps < 0) {
c_amps = 0;
}
if(ch_en_latch == 1 || ch_en_latch == 2) { // Criteria for MODE 1
charge_mode = 1;
} else {
charge_mode = 0;
}
if(charge_mode == 1 && volts >= 87) { // Criteria for MODE 2
charge_mode = 2;
charge_latch = 1;
}
if(charge_latch == 1 && volts >= 83.5) { // Stay in MODE 2 until volts drop to float level
charge_mode = 2;
}
if(volts < 83.5 && charge_latch == 1) { // Criteria for MODE 3
charge_mode = 3;
ch_count = ch_count + 1;
}
if(ch_count > float_delay) { // Float timer
charge_mode = 4;
}
if(c_amps < 0) { // Reset charge Ah counter if I forget to reset
charge_mode = 0; // the Arduino and I start driving
}
if(ch_en_latch == 0) { // Start/stop charge button
digitalWrite(ch_enable, LOW);
charge_mode = 0;
}
watts = volts * c_amps; // Ah counter calculations; not sure if I will use all of these
sample = sample + 1;
time = millis() / 1000;
totCharge = totCharge + c_amps;
avgAmps = totCharge / sample;
ampHour = avgAmps * time / 3600;
kWh = volts * ampHour / 1000;

lcd.clear(); // LCD stuff
lcd.setCursor(0, 1);
lcd.print("Volt: ");
lcd.print(volts, 1);
lcd.setCursor(11, 1);
lcd.print("Amp: ");
lcd.print(c_amps, 1);
lcd.setCursor(0, 2);
lcd.print("Watt: ");
lcd.print(watts);
lcd.setCursor(10, 2);
lcd.print("kWH: ");
lcd.print(kWh);
lcd.setCursor(0, 3);
lcd.print("Mode: ");
lcd.print(charge_mode);
lcd.setCursor(9, 3);
lcd.write(byte(0));
lcd.write(byte(1));
lcd.print(" 0");
lcd.print(char(37));

if(charge_mode == 0) {
digitalWrite(ch_enable, LOW);
}
unsigned long currentMillis = millis(); // Counter for LED flashing
if(charge_mode == 1 || charge_mode == 2 || charge_mode == 3) { // All this so no delay() is required to flash the LED
if(currentMillis - previousMillis > ledInterval) {
// save the last time you blinked the LED
previousMillis = currentMillis; // if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
}
}
if(charge_mode == 1 || charge_mode == 2) {
lcd.setCursor(6, 0);
lcd.print("CHARGING");
digitalWrite(ch_enable, HIGH);
ledInterval = 2000;
}
if(charge_mode == 3) {
lcd.setCursor(6, 0);
lcd.print(" FLOAT ");
digitalWrite(ch_enable, HIGH);
ledInterval = 400;
}
if(charge_mode == 4) {
lcd.setCursor(2, 0);
lcd.print("CHARGE COMPLETE");
digitalWrite(ch_enable, LOW);
ledState = HIGH;
}
if(ch_en_latch == 1) {
lcd.setCursor(19, 0);
lcd.print(" ");
}
if(ch_en_latch == 2) {
lcd.setCursor(19, 0);
lcd.write(byte(2));
}
digitalWrite(ledPin, ledState);
delay(400);
}
So far this is using 21.6% of the ATmega328's memory. Still lots of room left.

Last edited by mechman600; 03-25-2014 at 12:12 AM..
  Reply With Quote
The Following 2 Users Say Thank You to mechman600 For This Useful Post:
Cobb (03-22-2014), Daox (03-22-2014)