Move the battery power calculation part to the BatteryMonitor class

This commit is contained in:
m-RNA
2026-01-01 17:14:53 +08:00
parent 017474746f
commit 97b910a38c
5 changed files with 136 additions and 58 deletions

View File

@@ -71,3 +71,52 @@ int BatteryMonitor::getBatteryMilliVolts() const
return 0;
#endif
}
float BatteryMonitor::voltageToPercentage(int voltage_mv)
{
const float volts = static_cast<float>(voltage_mv);
// Handle boundary conditions
if (volts >= soc_lookup_.front().voltage_mv)
return soc_lookup_.front().soc;
if (volts <= soc_lookup_.back().voltage_mv)
return soc_lookup_.back().soc;
// Linear interpolation between lookup table points
for (size_t i = 0; i < soc_lookup_.size() - 1; ++i)
{
const auto &high = soc_lookup_[i];
const auto &low = soc_lookup_[i + 1];
if (volts <= high.voltage_mv && volts >= low.voltage_mv)
{
const float voltage_span = high.voltage_mv - low.voltage_mv;
if (voltage_span <= 0.0f)
{
return low.soc;
}
const float ratio = (volts - low.voltage_mv) / voltage_span;
return low.soc + ratio * (high.soc - low.soc);
}
}
return 0.0f;
}
BatteryStatus BatteryMonitor::getBatteryStatus() const
{
BatteryStatus status = {0, 0.0f, false};
#if CONFIG_MONITORING_BATTERY_ENABLE
const int mv = getBatteryMilliVolts();
if (mv <= 0)
return status;
status.voltage_mv = mv;
status.percentage = std::clamp(voltageToPercentage(mv), 0.0f, 100.0f);
status.valid = true;
#endif
return status;
}

View File

@@ -14,15 +14,31 @@
* +-----------------------+
*/
#include <algorithm>
#include <array>
#include <cmath>
#include "AdcSampler.hpp"
#include "sdkconfig.h"
#include <cmath>
/**
* @struct BatteryStatus
* @brief Battery status information
*/
struct BatteryStatus
{
int voltage_mv; // Battery voltage in millivolts
float percentage; // State of charge percentage (0-100%)
bool valid; // Whether the reading is valid
};
/**
* @class BatteryMonitor
* @brief Monitors battery voltage through a resistor divider
* @brief Monitors battery voltage and calculates state of charge for Li-ion batteries
*
* Uses AdcSampler (BSP layer) for hardware abstraction.
* Includes voltage-to-SOC lookup table for typical Li-ion/Li-Po batteries.
*
* Configuration is done via Kconfig options:
* - CONFIG_MONITORING_BATTERY_ENABLE
* - CONFIG_MONITORING_BATTERY_ADC_GPIO
@@ -39,10 +55,29 @@ public:
// Initialize battery monitoring hardware
bool setup();
// Read once, update filter, and return battery voltage in mV (after divider compensation), 0 on failure
/**
* @brief Read battery voltage (with divider compensation)
* @return Battery voltage in millivolts, 0 on failure
*/
int getBatteryMilliVolts() const;
// Whether monitoring is enabled by Kconfig and supported by BSP
/**
* @brief Calculate battery state of charge from voltage
* @param voltage_mv Battery voltage in millivolts
* @return State of charge percentage (0-100%)
*/
static float voltageToPercentage(int voltage_mv);
/**
* @brief Get complete battery status (voltage + percentage)
* @return BatteryStatus struct with voltage, percentage, and validity
*/
BatteryStatus getBatteryStatus() const;
/**
* @brief Check if battery monitoring is enabled and supported
* @return true if enabled and ADC is supported
*/
static constexpr bool isEnabled()
{
#ifdef CONFIG_MONITORING_BATTERY_ENABLE
@@ -53,6 +88,34 @@ public:
}
private:
float scale_{1.0f}; // Voltage divider scaling factor
/**
* @brief Li-ion/Li-Po voltage to SOC lookup table entry
*/
struct VoltageSOC
{
float voltage_mv;
float soc;
};
/**
* @brief Typical Li-ion single cell discharge curve lookup table
* Based on typical 3.7V nominal Li-ion/Li-Po cell characteristics
*/
static constexpr std::array<VoltageSOC, 12> soc_lookup_ = {{
{4200.0f, 100.0f}, // Fully charged
{4060.0f, 90.0f},
{3980.0f, 80.0f},
{3920.0f, 70.0f},
{3870.0f, 60.0f},
{3820.0f, 50.0f},
{3790.0f, 40.0f},
{3770.0f, 30.0f},
{3740.0f, 20.0f},
{3680.0f, 10.0f},
{3450.0f, 5.0f}, // Low battery warning
{3300.0f, 0.0f}, // Empty / cutoff voltage
}};
float scale_{1.0f}; // Voltage divider scaling factor
mutable AdcSampler adc_; // ADC sampler instance (BSP layer)
};

View File

@@ -127,10 +127,11 @@ void MonitoringManager::run()
#if CONFIG_MONITORING_BATTERY_ENABLE
if (BatteryMonitor::isEnabled() && now_tick >= next_tick_bat)
{
const int mv = bm_.getBatteryMilliVolts();
if (mv > 0)
const auto status = bm_.getBatteryStatus();
if (status.valid)
{
last_battery_mv_.store(mv);
std::lock_guard<std::mutex> lock(battery_mutex_);
last_battery_status_ = status;
}
next_tick_bat = now_tick + batt_period;
}
@@ -161,11 +162,14 @@ float MonitoringManager::getCurrentMilliAmps() const
return 0.0f;
}
float MonitoringManager::getBatteryVoltageMilliVolts() const
BatteryStatus MonitoringManager::getBatteryStatus() const
{
#if CONFIG_MONITORING_BATTERY_ENABLE
if (BatteryMonitor::isEnabled())
return static_cast<float>(last_battery_mv_.load());
{
std::lock_guard<std::mutex> lock(battery_mutex_);
return last_battery_status_;
}
#endif
return 0.0f;
return {0, 0.0f, false};
}

View File

@@ -19,6 +19,7 @@
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <atomic>
#include <mutex>
#include "BatteryMonitor.hpp"
#include "CurrentMonitor.hpp"
@@ -47,8 +48,8 @@ public:
// Latest filtered current in mA
float getCurrentMilliAmps() const;
// Latest battery voltage in mV
float getBatteryVoltageMilliVolts() const;
// Get complete battery status (voltage + percentage + validity)
BatteryStatus getBatteryStatus() const;
// Check if any monitoring feature is enabled
static constexpr bool isEnabled()
@@ -62,7 +63,8 @@ private:
TaskHandle_t task_{nullptr};
std::atomic<float> last_current_ma_{0.0f};
std::atomic<int> last_battery_mv_{0};
BatteryStatus last_battery_status_{0, 0.0f, false};
mutable std::mutex battery_mutex_; // Protect non-atomic BatteryStatus
CurrentMonitor cm_;
BatteryMonitor bm_;