/*
This project is about charging system, due to i was not able to get
TP4056 in the Wokwi database, I have used slide switches the first one
is for start charging and sensond is for battery full indications.
You have all component you make an actual project and just use this
source code to program your ESP32.
Major componens list:
1- ESP32 WROOM 32 (Dev Board)
2- SSD1306 OLED DISPLAY
3- TP4056 CHARGING MODULE WITH BATTERY PROTECTION CIRCUIT
4- 10K RESISTORS = 3
5- 4.7L RESISTOR = 1
*/
#include <Arduino.h>
#include <Adafruit_SSD1306.h>
// SSD1306 OLED Display
#define OLED_RESET -1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SSD1306_I2C_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// PIN CONFIGURATIONS
#define CHRG_PIN 5 // Connect to TP4056 CHRG pin
#define STDBY_PIN 18 // Connect to TP4056 STDBY pin
#define BATT_LEVEL 35 // Connect to B+ via divider resistors
// Position variables for battery icon
const int batteryX = 44; // X position
const int batteryY = 32; // Y position
// FUNCTION PROTOTYPES
void displayBatteryStatus();
void drawBattery(int level, bool charging);
void setup() {
Serial.begin(115200);
pinMode(CHRG_PIN, INPUT);
pinMode(STDBY_PIN, INPUT);
pinMode(BATT_LEVEL, INPUT);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 25);
display.print("LOADING SYSTEM");
display.display();
// Display animation dots
for (int i = 0; i < 3; i++) {
delay(600); // 0.6 second delay
display.print(".");
display.display();
}
display.clearDisplay();
}
}
void loop() {
displayBatteryStatus();
delay(500);
}
void displayBatteryStatus() {
int chrg_status = digitalRead(CHRG_PIN);
int stdby_status = digitalRead(STDBY_PIN);
// Read battery level from ADC pin
int adcValue = analogRead(BATT_LEVEL);
// Convert ADC value to battery voltage
float batteryVoltage = adcValue * (3.3 / 4095.0); // Adjust according to the voltage divider ratio
batteryVoltage = batteryVoltage * (4700.0 + 10000.0) / 4700.0; // Adjust for the voltage divider ratio (4.7k from A0 to GND, 10k from battery to A0)
// Constrain battery voltage to realistic values
batteryVoltage = constrain(batteryVoltage, 3.0, 4.2);
// Map battery voltage to percentage level
int batteryLevel = map(batteryVoltage * 100, 300, 420, 0, 100); // Adjust the mapping based on your battery voltage range (3.0V to 4.2V)
// Display battery voltage, fine-tune voltage, and raw ADC value
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
// Display raw ADC value for debugging
display.print("RAW ADC: ");
display.println(adcValue);
// Display battery voltage
display.setCursor(0, 10);
display.print("VOLTAGE: ");
display.print(batteryVoltage, 2); // Display voltage with two decimal places
display.println("V");
// Draw battery status and level
display.setCursor(0, 20);
if (chrg_status == LOW) {
display.println("CHARGING");
drawBattery(batteryLevel, true);
} else if (stdby_status == LOW) {
display.println("BATTERY FULL");
drawBattery(batteryLevel, false);
} else {
display.println("NOT IN CHARGING");
drawBattery(batteryLevel, false);
}
display.display();
}
void drawBattery(int level, bool charging) {
// Draw battery outline
display.drawRect(batteryX, batteryY, 40, 20, SSD1306_WHITE);
display.drawRect(batteryX + 40, batteryY + 5, 5, 10, SSD1306_WHITE);
// Draw battery level
int fillWidth = map(level, 0, 100, 0, 38);
display.fillRect(batteryX + 1, batteryY + 1, fillWidth, 18, SSD1306_WHITE);
if (charging) {
// Calculate charging animation fill area
static unsigned long lastUpdateTime = 0;
static int chargingLevel = 0;
int animationSpeed = 20; // Milliseconds per frame
// Update charging level periodically
if (millis() - lastUpdateTime > animationSpeed) {
chargingLevel++; // Increment charging animation level
if (chargingLevel > fillWidth + 18) { // Reset animation to start from the left
chargingLevel = -18;
}
lastUpdateTime = millis();
}
// Calculate the start and end positions for animation fill
int startChargeX = batteryX + 1 + chargingLevel;
int startChargeY = batteryY + 1;
int endChargeX = startChargeX + 18;
int endChargeY = startChargeY + 18;
// Clip animation fill to stay within battery level bounds
if (startChargeX < batteryX + 1) {
startChargeX = batteryX + 1;
}
if (endChargeX > batteryX + 1 + fillWidth) {
endChargeX = batteryX + 1 + fillWidth;
}
// Draw charging animation fill
if (chargingLevel >= 0 && chargingLevel <= fillWidth) {
display.fillRect(startChargeX, startChargeY, endChargeX - startChargeX, endChargeY - startChargeY, SSD1306_WHITE);
}
}
}