Arduino Uno: Lead-Acid Battery Monitor with Resistor Divider Calculations

Detailed Description

This project demonstrates how to monitor the voltage of lead-acid batteries (12V and 24V) using an Arduino Uno. The voltage input is scaled using a resistor divider to ensure that the battery voltage, which can reach up to 32V, is within the 0-5V range of the Arduino's ADC.

Resistor Divider Calculation

We use a simple voltage divider circuit with two resistors (R1 and R2) to scale the input voltage (up to 32V) down to a voltage the Arduino can measure (0-5V). The voltage divider equation is:

Vout = Vin × (R2 / (R1 + R2))

For this project, we use the following resistor values:

To calculate the maximum voltage that the Arduino will read, we rearrange the formula:

If the ADC input range is 0-5V, the maximum input voltage (Vin) is: Thus, this voltage divider scales down a maximum battery voltage of 32V to 5V for the Arduino's ADC input.

LED Indicators

The following LEDs indicate the battery charge level:

Arduino Code


/*
 * Arduino Uno: Lead-Acid Battery Monitor with LEDs and Resistor Divider
 * Voltage divider setup: 56kΩ (R1) and 10kΩ (R2) to measure up to 32V
 * © 2024 Copyright Peter I. Dunne, all rights reserved
 * Prepared for educational use
 * Released under the Mozilla Public License
 */
 
const int analogPin = A0;    // Pin connected to battery voltage divider
const int greenLED = 9;      // Green LED for full charge
const int yellowLED = 10;    // Yellow LED for mid-range charge
const int redLED = 11;       // Red LED for low or overcharge indication

// Voltage divider resistor values
const float R1 = 56000.0;    // Resistor connected to battery (56kΩ)
const float R2 = 10000.0;    // Resistor connected to ground (10kΩ)

// Battery voltage thresholds (in Volts)
const float lowThreshold12V = 11.4;
const float highThreshold12V = 14.4;
const float lowThreshold24V = 22.8;
const float highThreshold24V = 28.8;

// Timing variables for non-blocking pulsing
unsigned long previousMillis = 0;
unsigned long ledInterval = 500; // Default to 2Hz (500ms on/off)

// Maximum voltage the Arduino can read
const float maxVoltage = 32.0;

void setup() {
    pinMode(greenLED, OUTPUT);
    pinMode(yellowLED, OUTPUT);
    pinMode(redLED, OUTPUT);
    Serial.begin(115200);
    Serial.println("Code by Peter Ivan Dunne, ©2024, all rights reserved");
    Serial.println("Released under the Mozilla Public License");
    Serial.println("https://jazenga.com/educational");
    Serial.println("Monitor Lead Acid batteries with auto detection of 12v/24v systems");
}

void loop() {
    // Read analog value from ADC
    int sensorValue = analogRead(analogPin);
    
    // Convert the analog reading to battery voltage
    float voltage = sensorValue * (5.0 / 1023.0) * ((R1 + R2) / R2);

    // Determine battery type (12V or 24V)
    bool is24V = voltage >= 16;

    // Calculate charge level
    float chargeLevel = calculateChargeLevel(voltage, is24V);
   if (chargeLevel<0){
      chargeLevel=0;
      }
    if (chargeLevel>100){
      chargeLevel=100;
      }
     // Handle LED behavior based on voltage thresholds
    handleLEDs(voltage, is24V);

    // Print the voltage and charge level to the Serial Monitor
    Serial.print(is24V ? "24v system" : "12V system");
    Serial.print(" Battery Voltage: ");
    Serial.print(voltage);
    Serial.print(" V, Charge Level: ");
    Serial.print(chargeLevel);
    Serial.println("%");

    delay(1000); // Wait for 1 second before the next reading
}

// Function to calculate charge level percentage
float calculateChargeLevel(float voltage, bool is24V) {

    float maxVoltage = is24V ? highThreshold24V : highThreshold12V;
    float minVoltage = is24V ? lowThreshold24V : lowThreshold12V;
    return((voltage - minVoltage) / (maxVoltage - minVoltage)) * 100.0;
}

// Function to handle LED indicators based on battery status
void handleLEDs(float voltage, bool is24V) {
    float lowThreshold = is24V ? lowThreshold24V : lowThreshold12V;
    float highThreshold = is24V ? highThreshold24V : highThreshold12V;

    unsigned long currentMillis = millis();

    // Green LED for fully charged battery
    if (voltage >= highThreshold) {
        digitalWrite(greenLED, HIGH);  // Full charge: solid green
        digitalWrite(yellowLED, LOW);
        digitalWrite(redLED, LOW);
    } 
    // Yellow LED for mid-range charge (pulsing at 2Hz)
    else if (voltage > lowThreshold && voltage < highThreshold) {
        digitalWrite(greenLED, LOW);
        if (currentMillis - previousMillis >= ledInterval) {
            previousMillis = currentMillis;
            digitalWrite(yellowLED, !digitalRead(yellowLED)); // Toggle yellow LED
        }
        // Pulse the yellow LED based on charge level
        ledInterval = 1000 - (calculateChargeLevel(voltage, is24V) * 10); // Proportional duty cycle
        digitalWrite(redLED, LOW);
    } 
    // Red LED for low or over-voltage conditions
    else {
        digitalWrite(greenLED, LOW);
        digitalWrite(yellowLED, LOW);
        if (currentMillis - previousMillis >= ledInterval) {
            previousMillis = currentMillis;
            digitalWrite(redLED, !digitalRead(redLED)); // Toggle red LED
        }
        // Pulse the red LED at 1Hz for under-voltage, 3Hz for over-voltage
        ledInterval = (voltage < lowThreshold) ? 1000 : 333;
    }
}