#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Variables for voltage, current, power, and other calculations
float vo = 0, vi = 0, current = 0, current1 = 0;
float cutoff = 0, p = 0, p1 = 0, ef = 0;
int pwm = 0, battery#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD I2C address
// Variables for voltage, current, power calculations
float vo = 0, vi = 0, currentBat = 0, currentPV = 0;
float cutoff = 0, pBat = 0, pPV = 0, efficiency = 0;
int pwmValue = 0, batteryType = 0, readCounter = 0;
// Button debounce timing
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
// Pins
const int pwmPin = 9;
const int buttonPin1 = 10; // Mode toggle
const int buttonPin2 = 11; // Increase battery type
const int buttonPin3 = 12; // Decrease battery type
void setup() {
// LCD initialization
lcd.init();
lcd.backlight();
// Set PWM frequency for pin 9
TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9
// Serial communication
Serial.begin(115200);
// Pin setup
pinMode(pwmPin, OUTPUT);
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
pinMode(buttonPin3, INPUT_PULLUP);
// Read saved battery type from EEPROM
batteryType = EEPROM.read(0);
if (batteryType > 2) batteryType = 0;
// Set cutoff based on battery type
setBatteryCutoff();
}
void loop() {
readCounter++;
// Read sensor values and calculate power if not in configuration mode
if (readCounter > 30) {
readCounter = 0;
readSensorValues();
calculatePowerAndEfficiency();
controlPWM();
displayDataOnLCD();
printDataToSerial();
}
// Handle button presses for toggling modes and battery selection
handleButtonPresses();
delay(10); // Prevent CPU overuse
}
void setBatteryCutoff() {
switch (batteryType) {
case 0:
cutoff = 15.4; // Flooded
break;
case 1:
cutoff = 14.8; // AGM
break;
case 2:
cutoff = 14.0; // Gel
break;
}
}
void readSensorValues() {
// Reset values
currentBat = 0;
currentPV = 0;
vo = 0;
vi = 0;
// Take multiple readings to average
for (int i = 0; i < 100; i++) {
currentBat += (.049 * analogRead(A2) - 25); // Battery current
currentPV += (.049 * analogRead(A3) - 25); // PV current
vo += analogRead(A0); // Battery voltage
vi += analogRead(A1); // PV voltage
delayMicroseconds(100);
}
// Normalize readings
currentBat = max(currentBat / 60, 0.0); // Prevent negative readings
currentPV = max(currentPV / 70, 0.0);
vo = (vo * 0.03) / 100;
vi = (vi * 0.3) / 80;
// Adjust PV input voltage
vi = (vo * 10) - vi;
}
void calculatePowerAndEfficiency() {
// Calculate power
pBat = currentBat * vo;
pPV = currentPV * vi;
// Calculate efficiency
if (pPV != 0) {
efficiency = (pBat / pPV) * 100;
} else {
efficiency = 0;
}
}
void controlPWM() {
// PWM adjustment based on voltage
if (vo > cutoff) {
pwmValue = max(pwmValue - 1, 0); // Decrease PWM if voltage exceeds cutoff
}
if (vo < cutoff + 1) {
pwmValue = min(pwmValue + 1, 200); // Increase PWM if below cutoff
}
analogWrite(pwmPin, pwmValue); // Set PWM output
}
void displayDataOnLCD() {
lcd.clear();
// Display PV (input) voltage, current, and power
lcd.setCursor(0, 0);
lcd.print("P ");
lcd.print((int)vi);
lcd.print("V ");
lcd.print(currentPV, 1);
lcd.print("A ");
lcd.print((int)pPV);
lcd.print("W");
// Display Battery (output) voltage, current, and power
lcd.setCursor(0, 1);
lcd.print("B ");
lcd.print((int)vo);
lcd.print("V ");
lcd.print(currentBat, 1);
lcd.print("A ");
lcd.print((int)pBat);
lcd.print("W");
}
void printDataToSerial() {
// Print data to serial monitor for debugging
Serial.print("Input Voltage: ");
Serial.print(vi, 1);
Serial.print("V, Input Current: ");
Serial.print(currentPV, 1);
Serial.print("A, Input Power: ");
Serial.print(pPV, 1);
Serial.println("W");
Serial.print("Battery Voltage: ");
Serial.print(vo, 1);
Serial.print("V, Battery Current: ");
Serial.print(currentBat, 1);
Serial.print("A, Battery Power: ");
Serial.print(pBat, 1);
Serial.println("W");
}
void handleButtonPresses() {
if (millis() - lastDebounceTime > debounceDelay) {
if (!digitalRead(buttonPin1)) {
lastDebounceTime = millis();
if (!m) EEPROM.update(0, batteryType); // Save battery type to EEPROM
m = !m; // Toggle mode
}
if (m) { // Battery type selection mode
if (!digitalRead(buttonPin2)) {
lastDebounceTime = millis();
batteryType = (batteryType + 1) % 3;
setBatteryCutoff();
}
if (!digitalRead(buttonPin3)) {
lastDebounceTime = millis();
batteryType = (batteryType - 1 + 3) % 3; // Wrap-around
setBatteryCutoff();
}
// Display battery type on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Battery Type ");
lcd.setCursor(0, 1);
switch (batteryType) {
case 0:
lcd.print(" Flooded ");
break;
case 1:
lcd.print(" AGM ");
break;
case 2:
lcd.print(" Gel ");
break;
}
}
}
}
Type = 0, j = 0;
// State and mode variables
bool st = false, m = false;
// Pins
const int pwmPin = 9;
const int buttonPin1 = 10; // Toggle button
const int buttonPin2 = 11; // Increase battery type
const int buttonPin3 = 12; // Decrease battery type
// Debounce objects
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();
void setup() {
// Initialize LCD and backlight
lcd.init();
lcd.backlight();
// Set PWM frequency for pin 9
TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9
// Begin serial communication
Serial.begin(115200);
// Setup pin modes
pinMode(pwmPin, OUTPUT);
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
pinMode(buttonPin3, INPUT_PULLUP);
// Attach debouncers to buttons
debouncer1.attach(buttonPin1);
debouncer1.interval(50);
debouncer2.attach(buttonPin2);
debouncer2.interval(50);
debouncer3.attach(buttonPin3);
debouncer3.interval(50);
// Read saved battery type from EEPROM
batteryType = EEPROM.read(0);
if (batteryType > 2) batteryType = 0;
// Set cutoff based on battery type
setBatteryCutoff();
}
void loop() {
j++;
// Only read values when not in configuration mode
if (!m) {
readSensorValues();
// Calculate power and efficiency, and update PWM
calculatePowerAndEfficiency();
controlPWM();
// Display updated readings on LCD every 30 cycles
if (j > 30) {
j = 0;
displayDataOnLCD();
}
// Print data to Serial
printDataToSerial();
}
// Handle button presses for toggling modes and battery type selection
handleButtonPresses();
delay(10); // Small delay to prevent CPU overuse
}
void setBatteryCutoff() {
switch (batteryType) {
case 0:
cutoff = 15.4; // Flooded battery
break;
case 1:
cutoff = 14.8; // AGM battery
break;
case 2:
cutoff = 14.0; // Gel battery
break;
}
}
void readSensorValues() {
// Reset variables for new readings
current = 0;
current1 = 0;
vo = 0;
vi = 0;
// Average multiple readings for more accurate results
for (int i = 0; i < 100; i++) {
current += (.049 * analogRead(A2) - 25); // For 20A mode
current1 += (.049 * analogRead(A3) - 25); // For 20A mode
vo += analogRead(A0); // Battery voltage
vi += analogRead(A1); // Input voltage
delayMicroseconds(100);
}
// Normalize the readings
current = max(current / 60, 0.0); // Prevent negative currents
current1 = max(current1 / 70, 0.0);
vo = (vo * 0.03) / 100;
vi = (vi * 0.3) / 80;
// Adjust `vi` based on `vo` for more accuracy
vi = (vo * 10) - vi;
}
void calculatePowerAndEfficiency() {
// Calculate power and efficiency
p = current * vo;
p1 = current1 * vi;
// Prevent division by zero in efficiency calculation
if (p1 != 0) {
ef = (p / p1) * 100;
} else {
ef = 0; // Set efficiency to 0 if input power is too low
}
}
void controlPWM() {
// Adjust PWM based on battery voltage
if (vo > cutoff) {
pwm = max(pwm - 1, 0); // Reduce PWM if voltage exceeds cutoff
}
if (vo < cutoff + 1) {
pwm = min(pwm + 1, 200); // Increase PWM if voltage is below cutoff
}
// Write adjusted PWM value to output
analogWrite(pwmPin, pwm);
}
void displayDataOnLCD() {
lcd.clear();
// Display Input (vi) Voltage, Current, and Power
lcd.setCursor(0, 0);
lcd.print("P ");
lcd.print((int)vi);
lcd.print("V ");
lcd.print(current1, 1);
lcd.print("A ");
lcd.print((int)p1);
lcd.print("W");
// Display Battery (vo) Voltage, Current, and Power
lcd.setCursor(0, 1);
lcd.print("B ");
lcd.print((int)vo);
lcd.print("V ");
lcd.print(current, 1);
lcd.print("A ");
lcd.print((int)p);
lcd.print("W");
}
void printDataToSerial() {
// Print values to Serial in a readable format
Serial.print("Input Voltage: ");
Serial.print(vi, 1);
Serial.print("V, Input Current: ");
Serial.print(current1, 1);
Serial.print("A, Input Power: ");
Serial.print(p1, 1);
Serial.print("W\n");
Serial.print("Battery Voltage: ");
Serial.print(vo, 1);
Serial.print("V, Battery Current: ");
Serial.print(current, 1);
Serial.print("A, Battery Power: ");
Serial.print(p, 1);
Serial.print("W\n");
}
void handleButtonPresses() {
// Update debouncer states
debouncer1.update();
debouncer2.update();
debouncer3.update();
if (debouncer1.fell()) {
st = !st;
if (!m && EEPROM.read(0) != batteryType) {
EEPROM.update(0, batteryType); // Save battery type to EEPROM only if it has changed
}
m = !m; // Toggle between modes
}
if (m) { // Battery type selection mode
if (debouncer2.fell()) {
batteryType = (batteryType + 1) % 3;
setBatteryCutoff();
}
if (debouncer3.fell()) {
batteryType = (batteryType - 1 + 3) % 3; // Wrap around
setBatteryCutoff();
}
// Display battery type on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Battery Type ");
lcd.setCursor(0, 1);
switch (batteryType) {
case 0:
lcd.print(" Flooded ");
break;
case 1:
lcd.print(" AGM ");
break;
case 2:
lcd.print(" Gel ");
break;
}
}
}