Refactor BatterySensor and Display classes to integrate MAX17048 and SH110X support
This commit is contained in:
@@ -7,9 +7,10 @@ monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
adafruit/Adafruit GFX Library
|
||||
adafruit/Adafruit SSD1306
|
||||
adafruit/Adafruit SH110X
|
||||
adafruit/Adafruit VEML7700 Library
|
||||
adafruit/Adafruit MPU6050
|
||||
adafruit/Adafruit MAX1704X
|
||||
bblanchon/ArduinoJson
|
||||
|
||||
; board_build.filesystem = spiffs
|
||||
|
||||
@@ -1,109 +1,64 @@
|
||||
#include "BatterySensor.h"
|
||||
#include <math.h>
|
||||
|
||||
void BatterySensor::begin() {
|
||||
pinMode(PIN_BATTERY_ADC, INPUT);
|
||||
pinMode(PIN_LBO, INPUT);
|
||||
pinMode(PIN_CHG, INPUT_PULLUP); // CHG is LOW when charging
|
||||
_ok = _maxlipo.begin();
|
||||
if (!_ok) {
|
||||
Serial.println("[Battery] MAX17048 not detected");
|
||||
return;
|
||||
}
|
||||
|
||||
analogReadResolution(12); // 12-bit ADC (0-4095)
|
||||
|
||||
Serial.println("[Battery] Initialized");
|
||||
Serial.println("[Battery] ADC on GPIO 2, LBO on GPIO 5, CHG on GPIO 4");
|
||||
|
||||
// Initial reading
|
||||
_voltage = readBatteryVoltage();
|
||||
_percent = voltageToPercent(_voltage);
|
||||
_isLow = (_voltage < VOLTAGE_LOW);
|
||||
Serial.println("[Battery] MAX17048 initialized on I2C");
|
||||
refresh();
|
||||
|
||||
Serial.print("[Battery] Initial voltage: ");
|
||||
Serial.print(_voltage);
|
||||
Serial.print(_voltage, 2);
|
||||
Serial.print("V, ");
|
||||
Serial.print(_percent);
|
||||
Serial.println("%");
|
||||
}
|
||||
|
||||
void BatterySensor::loop() {
|
||||
if (!_ok) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
if (now - _lastCheckMs < CHECK_INTERVAL_MS) return;
|
||||
_lastCheckMs = now;
|
||||
|
||||
float prevVoltage = _voltage;
|
||||
int prevPercent = _percent;
|
||||
bool wasLow = _isLow;
|
||||
bool wasCharging = _isCharging;
|
||||
|
||||
// Read battery voltage via ADC
|
||||
_voltage = readBatteryVoltage();
|
||||
_percent = voltageToPercent(_voltage);
|
||||
refresh();
|
||||
|
||||
// Check CHG pin (LOW when charging)
|
||||
bool chgLow = !digitalRead(PIN_CHG);
|
||||
_isCharging = chgLow;
|
||||
|
||||
// Check LBO pin as backup confirmation
|
||||
bool lboHigh = digitalRead(PIN_LBO);
|
||||
bool lboIndicatesLow = !lboHigh;
|
||||
|
||||
// Battery is low if either voltage is low OR LBO pin indicates low (and not charging)
|
||||
_isLow = ((_voltage < VOLTAGE_LOW) || lboIndicatesLow) && !_isCharging;
|
||||
|
||||
// Log significant changes
|
||||
if (abs(_percent - prevPercent) >= 5 || _isLow != wasLow || _isCharging != wasCharging) {
|
||||
if (abs(_percent - prevPercent) >= 2 || _isLow != wasLow || _isCharging != wasCharging) {
|
||||
Serial.print("[Battery] Voltage: ");
|
||||
Serial.print(_voltage, 2);
|
||||
Serial.print("V (");
|
||||
Serial.print(_percent);
|
||||
Serial.print("%) ");
|
||||
Serial.print("%)");
|
||||
|
||||
if (_isCharging) {
|
||||
Serial.print("CHARGING ");
|
||||
}
|
||||
|
||||
Serial.print("LBO: ");
|
||||
Serial.println(lboHigh ? "OK" : "LOW");
|
||||
|
||||
if (_isLow && !wasLow && !_isCharging) {
|
||||
Serial.println("[Battery] ⚠️ LOW BATTERY WARNING - Please recharge!");
|
||||
}
|
||||
|
||||
if (_isCharging && !wasCharging) {
|
||||
Serial.println("[Battery] 🔌 Charging started");
|
||||
} else if (!_isCharging && wasCharging) {
|
||||
Serial.println("[Battery] ✓ Charging complete or disconnected");
|
||||
}
|
||||
if (_isCharging) Serial.print(" CHARGING");
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
float BatterySensor::readBatteryVoltage() {
|
||||
// Take multiple samples and average them for stability
|
||||
long sum = 0;
|
||||
for (int i = 0; i < SAMPLES; i++) {
|
||||
sum += analogRead(PIN_BATTERY_ADC);
|
||||
delay(5);
|
||||
void BatterySensor::refresh() {
|
||||
float v = _maxlipo.cellVoltage();
|
||||
float p = _maxlipo.cellPercent();
|
||||
float rate = _maxlipo.chargeRate();
|
||||
|
||||
if (!isnan(v) && isfinite(v) && v > 0.0f) _voltage = v;
|
||||
|
||||
if (!isnan(p) && isfinite(p)) {
|
||||
int pct = (int)lroundf(p);
|
||||
if (pct < 0) pct = 0;
|
||||
if (pct > 100) pct = 100;
|
||||
_percent = pct;
|
||||
}
|
||||
int avgRaw = sum / SAMPLES;
|
||||
|
||||
// Convert ADC value to voltage at the pin
|
||||
// ESP32-C3 ADC: 12-bit (0-4095) maps to 0-3.3V
|
||||
float adcVoltage = (avgRaw / 4095.0) * 3.3;
|
||||
|
||||
// Multiply by divider ratio to get actual battery voltage
|
||||
float batteryVoltage = adcVoltage * DIVIDER_RATIO;
|
||||
|
||||
return batteryVoltage;
|
||||
}
|
||||
|
||||
int BatterySensor::voltageToPercent(float voltage) {
|
||||
// Clamp voltage to valid range
|
||||
if (voltage >= VOLTAGE_MAX) return 100;
|
||||
if (voltage <= VOLTAGE_MIN) return 0;
|
||||
|
||||
// Linear mapping from voltage to percentage
|
||||
// This is a simplified model; LiPo discharge curves are non-linear
|
||||
// For better accuracy, you could use a lookup table
|
||||
float percent = ((voltage - VOLTAGE_MIN) / (VOLTAGE_MAX - VOLTAGE_MIN)) * 100.0;
|
||||
|
||||
return constrain((int)percent, 0, 100);
|
||||
_isLow = (_voltage < VOLTAGE_LOW) || (_percent < 15);
|
||||
_isCharging = (!isnan(rate) && isfinite(rate) && rate > CHARGE_RATE_MIN_PCT_PER_HR);
|
||||
}
|
||||
|
||||
bool BatterySensor::shouldBlink() const {
|
||||
@@ -112,7 +67,5 @@ bool BatterySensor::shouldBlink() const {
|
||||
}
|
||||
|
||||
int BatterySensor::iconFillWidth(int maxWidth) const {
|
||||
// Calculate fill width for battery icon
|
||||
// Returns 0 to maxWidth based on percentage
|
||||
return (_percent * maxWidth) / 100;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_MAX1704X.h>
|
||||
|
||||
class BatterySensor {
|
||||
public:
|
||||
@@ -17,27 +18,18 @@ public:
|
||||
int iconFillWidth(int maxWidth) const;
|
||||
|
||||
private:
|
||||
static constexpr int PIN_BATTERY_ADC = 2; // Voltage divider input
|
||||
static constexpr int PIN_LBO = 5; // PowerBoost LBO pin
|
||||
static constexpr int PIN_CHG = 4; // PowerBoost CHG pin (LOW when charging)
|
||||
|
||||
static constexpr unsigned long CHECK_INTERVAL_MS = 2000;
|
||||
static constexpr int SAMPLES = 10; // Number of ADC samples to average
|
||||
|
||||
// LiPo voltage thresholds
|
||||
static constexpr float VOLTAGE_MIN = 3.0; // 0%
|
||||
static constexpr float VOLTAGE_MAX = 4.2; // 100%
|
||||
static constexpr float VOLTAGE_LOW = 3.2; // Low battery threshold
|
||||
|
||||
// Voltage divider: R1=100k, R2=100k (2:1 ratio)
|
||||
static constexpr float DIVIDER_RATIO = 2.0;
|
||||
static constexpr float CHARGE_RATE_MIN_PCT_PER_HR = 0.2f; // heuristic
|
||||
|
||||
int _percent = 100;
|
||||
float _voltage = 3.7;
|
||||
bool _isLow = false;
|
||||
bool _isCharging = false;
|
||||
unsigned long _lastCheckMs = 0;
|
||||
bool _ok = false;
|
||||
Adafruit_MAX17048 _maxlipo;
|
||||
|
||||
float readBatteryVoltage();
|
||||
int voltageToPercent(float voltage);
|
||||
void refresh();
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
void Display::begin() {
|
||||
Wire.begin(PIN_SDA, PIN_SCL);
|
||||
_ok = _oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR, true, false);
|
||||
_ok = _oled.begin(OLED_ADDR, true);
|
||||
if (!_ok) return;
|
||||
_displayEnabled = true;
|
||||
setContrast(_contrast);
|
||||
@@ -25,8 +25,8 @@ void Display::showStatus(const String& line1, const String& line2) {
|
||||
void Display::setContrast(uint8_t contrast) {
|
||||
if (!_ok) return;
|
||||
_contrast = contrast;
|
||||
_oled.ssd1306_command(SSD1306_SETCONTRAST);
|
||||
_oled.ssd1306_command(_contrast);
|
||||
_oled.oled_command(SH110X_SETCONTRAST);
|
||||
_oled.oled_command(_contrast);
|
||||
}
|
||||
|
||||
void Display::setDisplayEnabled(bool enabled) {
|
||||
@@ -35,12 +35,12 @@ void Display::setDisplayEnabled(bool enabled) {
|
||||
|
||||
_displayEnabled = enabled;
|
||||
if (enabled) {
|
||||
_oled.ssd1306_command(SSD1306_DISPLAYON);
|
||||
_oled.oled_command(SH110X_DISPLAYON);
|
||||
setContrast(_contrast);
|
||||
} else {
|
||||
_oled.clearDisplay();
|
||||
_oled.display();
|
||||
_oled.ssd1306_command(SSD1306_DISPLAYOFF);
|
||||
_oled.oled_command(SH110X_DISPLAYOFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_SH110X.h>
|
||||
|
||||
class Display {
|
||||
public:
|
||||
void begin();
|
||||
Adafruit_SSD1306& oled() { return _oled; }
|
||||
Adafruit_SH1106G& oled() { return _oled; }
|
||||
bool ok() const { return _ok; }
|
||||
|
||||
void showStatus(const String& line1, const String& line2);
|
||||
@@ -21,7 +21,7 @@ private:
|
||||
static constexpr int PIN_SDA = 6;
|
||||
static constexpr int PIN_SCL = 7;
|
||||
static constexpr uint8_t OLED_ADDR = 0x3C; // try 0x3D if blank
|
||||
Adafruit_SSD1306 _oled = Adafruit_SSD1306(128, 64, &Wire, -1);
|
||||
Adafruit_SH1106G _oled = Adafruit_SH1106G(128, 64, &Wire, -1);
|
||||
bool _ok = false;
|
||||
bool _displayEnabled = true;
|
||||
uint8_t _contrast = 0xCF;
|
||||
|
||||
Reference in New Issue
Block a user