As Solar Samba continued its dance, it couldn't help but ponder over the readings on its digital display. "Ah, 12.5V," it thought, "the sun's been generous today." But as the clouds gathered, Solar Samba's display dimmed, mirroring the sky. "11.9V... time for me to shine!" it declared, springing into action.
With every dip in voltage, Solar Samba's resolve grew stronger. "I won't let the darkness win," it mused, as the display flickered with the rhythm of its charge. As night fell, Solar Samba's display became a beacon of hope, its numbers dancing in the dark, ensuring the battery bank stayed alive.
But Solar Samba knew its limits. When load shedding struck, its display read a somber "No Grid Power." It sighed, "Time for Plan C to take the stage." As the generator roared to life, Solar Samba whispered, "Rest now, my batteries, for tomorrow, we dance again."
Through every challenge, Solar Samba's digital display was its window to the world, a reflection of its thoughts and a guide for its next move. In the dance of light and darkness, it was more than just a charger; it was a thinker, a guardian, and a true solar samba dancer.
//So, for a voltage divider with a ratio of 11.0, you could use a 24.8kΩ resistor for R1 and a 2.48kΩ resistor for R2.
These are not standard resistor values, so you might use the closest standard values, which are 24kΩ for R1 and 2.4kΩ for R2.
This will give you a slightly different ratio, but it should be close enough for most purposes.
Always double-check the actual output voltage of your voltage divider with a multimeter to ensure it's safe for your microcontroller.
Battery+ (14.6V) ----[R1 (24kΩ)]----+----[R2 (2.4kΩ)]---- GND
|
+---- Output (to ESP32 analog pin, max 3.3V)
//
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "BluetoothSerial.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <ThingSpeak.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int currentSensorPin = 34; // Pin connected to the ACS712 output (ADC1)
const int voltageSensorPin = 35; // Pin connected to the voltage divider output (ADC1)
const int chargeControlPin = 32; // Pin connected to the gate of the MOSFET
const float voltageDividerRatio = 11.0; // Ratio of the voltage divider (R2/(R1+R2))
const float currentSensorSensitivity = 0.066; // Sensitivity of the ACS712 30A sensor in V/A
const float maxChargingCurrent = 30.0; // Maximum charging current in A
const float nightModeChargingCurrent = 15.0; // Maximum charging current in night mode
const float maxChargingVoltage = 14.6; // Maximum charging voltage for LiFePo4 battery
const float floatVoltage = 13.6; // Float voltage for LiFePo4 battery
const float minBatteryVoltage = 11.0; // Minimum voltage for 0% SOC
const float activationVoltage = 12.0; // Voltage threshold for activating charging
const unsigned long slowStartDuration = 5000; // Duration of the slow start in milliseconds
unsigned long slowStartTime = 0; // Timestamp when the slow start begins
bool slowStartActive = false; // Flag to indicate if slow start is active
bool nightMode = false; // Flag to indicate if night mode is active
bool chargingEnabled = false; // Flag to indicate if charging is enabled
bool chargeControl = true; // Flag to control charging based on Bluetooth command
BluetoothSerial SerialBT; // Bluetooth Serial object
// WiFi credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
// ThingSpeak credentials
unsigned long channelID = XXXXXX;
const char* writeAPIKey = "XXXXXXXXXXXXX";
WiFiClient client;
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32_Charger"); // Bluetooth device name
pinMode(chargeControlPin, OUTPUT);
ledcSetup(0, 5000, 8); // Channel 0, 5 kHz frequency, 8-bit resolution
ledcAttachPin(chargeControlPin, 0); // Attach chargeControlPin to channel 0
// Initialize the OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
// Initialize ThingSpeak
ThingSpeak.begin(client);
}
void loop() {
// Check for Bluetooth serial input
if (SerialBT.available()) {
char receivedChar = SerialBT.read();
if (receivedChar == '1') {
nightMode = true;
} else if (receivedChar == '0') {
nightMode = false;
} else if (receivedChar == '2') {
chargeControl = false; // Stop charging
}
}
float batteryVoltage = readBatteryVoltage();
float chargingCurrent = readChargingCurrent();
int batterySOC = calculateSOC(batteryVoltage);
// Check if the battery voltage is below the activation threshold and charging is controlled
chargingEnabled = (batteryVoltage <= activationVoltage) && chargeControl;
// Send data to ThingSpeak
ThingSpeak.setField(1, batteryVoltage);
ThingSpeak.setField(2, chargingCurrent);
ThingSpeak.setField(3, batterySOC);
ThingSpeak.setField(4, nightMode ? 1 : 0);
ThingSpeak.writeFields(channelID, writeAPIKey);
// Display battery voltage, charging current, SOC, and night mode status on OLED
display.clearDisplay();
display.setCursor(0,0);
display.print("Voltage: ");
display.print(batteryVoltage);
display.println(" V");
display.print("Current: ");
if (chargingCurrent < 0.09) {
display.print("0 A");
} else {
display.print(chargingCurrent);
display.println(" A");
}
display.print("SOC: ");
display.print(batterySOC);
display.println("%");
display.print("Night Mode: ");
display.println(nightMode ? "ON" : "OFF");
display.print("Charging: ");
display.println(chargingEnabled ? "ON" : "OFF");
display.display();
float currentLimit = nightMode ? nightModeChargingCurrent : maxChargingCurrent;
if (chargingEnabled && batteryVoltage < maxChargingVoltage) {
// Constant current mode
if (!slowStartActive) {
slowStartActive = true;
slowStartTime = millis();
}
if (chargingCurrent < currentLimit) {
if (millis() - slowStartTime < slowStartDuration) {
// Slow start phase
int dutyCycle = map(millis() - slowStartTime, 0, slowStartDuration, 0, 255);
ledcWrite(0, dutyCycle);
} else {
// Normal charging phase
ledcWrite(0, 255);
}
} else {
ledcWrite(0, 0); // Maintain charging current
}
} else if (chargingEnabled && batteryVoltage >= maxChargingVoltage && batteryVoltage < floatVoltage) {
// Constant voltage mode
slowStartActive = false;
ledcWrite(0, 127); // Adjust PWM to maintain voltage
} else {
// Float mode or charging disabled
slowStartActive = false;
ledcWrite(0, 0); // Stop charging
}
delay(1000);
}
float readBatteryVoltage() {
int sensorValue = analogRead(voltageSensorPin);
return sensorValue * (3.3 / 4095.0) * voltageDividerRatio;
}
float readChargingCurrent() {
int sensorValue = analogRead(currentSensorPin);
float voltage = sensorValue * (3.3 / 4095.0);
return (voltage - 2.5) / currentSensorSensitivity; // Adjust for sensor offset
}
int calculateSOC(float voltage) {
float soc = (voltage - minBatteryVoltage) / (maxChargingVoltage - minBatteryVoltage) * 100;
return constrain((int)soc, 0, 100); // Ensure SOC is within 0-100%
}

©Chemcool Electronics Privacy Policy