diff --git a/libs/hardware/BatteryMonitor/include/BatteryMonitor.h b/libs/hardware/BatteryMonitor/include/BatteryMonitor.h new file mode 100644 index 0000000..f5ae338 --- /dev/null +++ b/libs/hardware/BatteryMonitor/include/BatteryMonitor.h @@ -0,0 +1,30 @@ +#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/libs/hardware/BatteryMonitor/library.json b/libs/hardware/BatteryMonitor/library.json new file mode 100644 index 0000000..dcc03e5 --- /dev/null +++ b/libs/hardware/BatteryMonitor/library.json @@ -0,0 +1,15 @@ +{ + "name": "BatteryMonitor", + "version": "1.0.0", + "description": "Get battery voltage and percentage", + "authors": [ + { + "name": "Serge Baranov", + "email": "sbaranov@gmail.com", + "url": "https://github.com/CrazyCoder" + } + ], + "dependencies": {}, + "platforms": "espressif32", + "frameworks": ["arduino", "espidf"] +} diff --git a/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp b/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp new file mode 100644 index 0000000..c202335 --- /dev/null +++ b/libs/hardware/BatteryMonitor/src/BatteryMonitor.cpp @@ -0,0 +1,53 @@ +#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); +}