diff --git a/platformio.ini b/platformio.ini index 75a0c80..3b2e24c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,7 +16,6 @@ board_build.partitions = default_16MB.csv ; Libraries lib_deps = zinggjm/GxEPD2@^1.5.9 - https://github.com/pangodream/18650CL ; Build flags build_flags = diff --git a/src/BatteryMonitor.cpp b/src/BatteryMonitor.cpp new file mode 100644 index 0000000..7f40c4b --- /dev/null +++ b/src/BatteryMonitor.cpp @@ -0,0 +1,54 @@ +// BatteryMonitor.cpp +#include "BatteryMonitor.h" +#include "esp_adc_cal.h" + +BatteryMonitor::BatteryMonitor(uint8_t adcPin, float dividerMultiplier) + : _adcPin(adcPin), _dividerMultiplier(dividerMultiplier) +{ +} + +uint16_t BatteryMonitor::readPercentage() const +{ + return percentageFromMillivolts(readMillivolts()); +} + +uint16_t BatteryMonitor::readMillivolts() const +{ + const uint16_t raw = readRawMillivolts(); + const uint32_t mv = millivoltsFromRawAdc(raw); + return static_cast(mv * _dividerMultiplier); +} + +uint16_t BatteryMonitor::readRawMillivolts() const +{ + const uint16_t raw = analogRead(_adcPin); + return raw; +} + +double BatteryMonitor::readVolts() const +{ + return static_cast(readMillivolts()) / 1000.0; +} + +uint16_t BatteryMonitor::percentageFromMillivolts(uint16_t millivolts) +{ + double volts = millivolts / 1000.0; + // Polynomial derived from LiPo samples + double y = -144.9390 * volts * volts * volts + + 1655.8629 * volts * volts - + 6158.8520 * volts + + 7501.3202; + + // Clamp to [0,100] and round + y = max(y, 0.0); + y = min(y, 100.0); + y = round(y); + return static_cast(y); +} + +uint16_t BatteryMonitor::millivoltsFromRawAdc(uint16_t adc_raw) +{ + esp_adc_cal_characteristics_t adc_chars; + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_12, ADC_WIDTH_BIT_12, 1100, &adc_chars); + return esp_adc_cal_raw_to_voltage(adc_raw, &adc_chars); +} diff --git a/src/BatteryMonitor.h b/src/BatteryMonitor.h new file mode 100644 index 0000000..aea7a12 --- /dev/null +++ b/src/BatteryMonitor.h @@ -0,0 +1,33 @@ +// BatteryMonitor.h +#pragma once + +#include + +class BatteryMonitor +{ +public: + // Optional divider multiplier parameter defaults to 2.0 + explicit BatteryMonitor(uint8_t adcPin, float dividerMultiplier = 2.0f); + + // Read voltage and return percentage (0-100) + uint16_t readPercentage() const; + + // Read the battery voltage in millivolts (accounts for divider) + uint16_t readMillivolts() const; + + // Read raw millivolts from ADC (doesn't account for divider) + uint16_t readRawMillivolts() const; + + // Read the battery voltage in volts (accounts for divider) + double readVolts() const; + + // Percentage (0-100) from a millivolt value + static uint16_t percentageFromMillivolts(uint16_t millivolts); + + // Calibrate a raw ADC reading and return millivolts + static uint16_t millivoltsFromRawAdc(uint16_t adc_raw); + +private: + uint8_t _adcPin; + float _dividerMultiplier; +}; diff --git a/src/main.cpp b/src/main.cpp index cfaa120..97eb5a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ #include #include #include "image.h" -#include "Pangodream_18650_CL.h" +#include "BatteryMonitor.h" // Display SPI pins (custom pins for XteinkX4, not hardware SPI defaults) #define EPD_SCLK 8 // SPI Clock @@ -20,12 +20,9 @@ #define BTN_GPIO3 3 // Power button (digital) #define UART0_RXD 20 // Used for USB connection detection - #define BAT_GPIO0 0 // Battery voltage -#define READS 10 -#define CONV_FACTOR 1.5176 -Pangodream_18650_CL BL(BAT_GPIO0, CONV_FACTOR, READS); +static BatteryMonitor g_battery(BAT_GPIO0); static int rawBat = 0; @@ -44,7 +41,7 @@ volatile DisplayCommand displayCommand = DISPLAY_NONE; // GxEPD2 display - Using GxEPD2_426_GDEQ0426T82 // Note: XteinkX4 has 4.26" 800x480 display GxEPD2_BW display( - GxEPD2_426_GDEQ0426T82(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); + GxEPD2_426_GDEQ0426T82(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // FreeRTOS task for non-blocking display updates TaskHandle_t displayTaskHandle = NULL; @@ -78,6 +75,7 @@ volatile Button currentPressedButton = NONE; const unsigned long POWER_BUTTON_WAKEUP_MS = 1000; // Time required to confirm boot from sleep const unsigned long POWER_BUTTON_SLEEP_MS = 1000; // Time required to enter sleep mode + // Get button name as string const char *getButtonName(Button btn) { @@ -163,11 +161,11 @@ void drawBatteryInfo() display.printf("Power: %s", charging ? "Charging" : "Battery"); display.setCursor(40, 200); - display.printf("Raw: %i", rawBat); + display.printf("Raw: %i", g_battery.readRawMillivolts()); display.setCursor(40, 240); - display.printf("Volts: %.2f V", BL.getBatteryVolts()); + display.printf("Volts: %.2f V", g_battery.readVolts()); display.setCursor(40, 280); - display.printf("Charge: %i%%", BL.getBatteryChargeLevel()); + display.printf("Charge: %i%%", g_battery.readPercentage()); } // Display update task running on separate core @@ -410,14 +408,14 @@ void loop() Serial.println(""); - Serial.print("Value from pin: "); - Serial.println(rawBat); - Serial.print("Average value from pin: "); - Serial.println(BL.pinRead()); + Serial.print("Value from pin (raw/calibrated): "); + Serial.print(rawBat); + Serial.print(" / "); + Serial.println(BatteryMonitor::millivoltsFromRawAdc(rawBat)); Serial.print("Volts: "); - Serial.println(BL.getBatteryVolts()); + Serial.println(g_battery.readVolts()); Serial.print("Charge level: "); - Serial.println(BL.getBatteryChargeLevel()); + Serial.println(g_battery.readPercentage()); Serial.println(""); lastLogMs = now; }