Files
xiaozhi-esp32/main/boards/sp-esp32-s3-1.54-muma/power_manager.h
2025-05-22 14:30:44 +08:00

167 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef __POWER_MANAGER_H__
#define __POWER_MANAGER_H__
#include <driver/gpio.h>
#include <esp_adc/adc_oneshot.h>
#include <esp_log.h>
#include <esp_timer.h>
class PowerManager {
private:
// 电池电量区间-分压电阻为2个100k
static constexpr struct {
uint16_t adc;
uint8_t level;
} BATTERY_LEVELS[] = {{1980, 0}, {2519, 100}};
static constexpr size_t BATTERY_LEVELS_COUNT = 2;
static constexpr size_t ADC_VALUES_COUNT = 10;
esp_timer_handle_t timer_handle_ = nullptr;
gpio_num_t charging_pin_;
gpio_num_t bat_led_pin_;
adc_unit_t adc_unit_;
adc_channel_t adc_channel_;
uint16_t adc_values_[ADC_VALUES_COUNT];
size_t adc_values_index_ = 0;
size_t adc_values_count_ = 0;
uint8_t battery_level_ = 100;
bool is_charging_ = false;
static constexpr uint8_t MAX_CHANGE_COUNT = 8;
static constexpr uint32_t TIME_LIMIT = 2000000; // 2 seconds in microseconds
uint8_t change_count_ = 0; // 记录状态变化次数
uint64_t last_change_time_ = 0; // 最后一次状态变化的时间戳(微秒)
adc_oneshot_unit_handle_t adc_handle_;
void CheckBatteryStatus() {
uint64_t current_time = esp_timer_get_time(); // 获取当前时间(微秒)
// 如果时间间隔超过2秒则重置状态变化计数
if (current_time - last_change_time_ > TIME_LIMIT) {
change_count_ = 0;
}
if (change_count_ < MAX_CHANGE_COUNT) {
bool new_is_charging = gpio_get_level(bat_led_pin_) != 0; // 检查LED引脚状态
// 判断充电引脚状态
if (new_is_charging) {
new_is_charging = gpio_get_level(charging_pin_) == 1;
}
// 如果状态有变化
if (new_is_charging != is_charging_) {
is_charging_ = new_is_charging;
change_count_++; // 增加变化次数
last_change_time_ = current_time; // 更新最后变化时间
}
}
ReadBatteryAdcData();
}
void ReadBatteryAdcData() {
int adc_value;
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, adc_channel_, &adc_value));
adc_values_[adc_values_index_] = adc_value;
adc_values_index_ = (adc_values_index_ + 1) % ADC_VALUES_COUNT;
if (adc_values_count_ < ADC_VALUES_COUNT) {
adc_values_count_++;
}
uint32_t average_adc = 0;
for (size_t i = 0; i < adc_values_count_; i++) {
average_adc += adc_values_[i];
}
average_adc /= adc_values_count_;
CalculateBatteryLevel(average_adc);
// ESP_LOGI("PowerManager", "ADC值: %d 平均值: %ld 电量: %u%%", adc_value, average_adc,
// battery_level_);
}
void CalculateBatteryLevel(uint32_t average_adc) {
if (average_adc <= BATTERY_LEVELS[0].adc) {
battery_level_ = 0;
} else if (average_adc >= BATTERY_LEVELS[BATTERY_LEVELS_COUNT - 1].adc) {
battery_level_ = 100;
} else {
float ratio = static_cast<float>(average_adc - BATTERY_LEVELS[0].adc) /
(BATTERY_LEVELS[1].adc - BATTERY_LEVELS[0].adc);
battery_level_ = ratio * 100;
}
}
public:
PowerManager(gpio_num_t charging_pin, gpio_num_t bat_led_pin, adc_unit_t adc_unit = ADC_UNIT_2,
adc_channel_t adc_channel = ADC_CHANNEL_3)
: charging_pin_(charging_pin), bat_led_pin_(bat_led_pin), adc_unit_(adc_unit), adc_channel_(adc_channel) {
// 配置充电引脚
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << charging_pin_);
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
// 配置状态引脚
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pin_bit_mask = (1ULL << bat_led_pin_);
gpio_config(&io_conf);
// 定时器配置
esp_timer_create_args_t timer_args = {
.callback =
[](void* arg) {
PowerManager* self = static_cast<PowerManager*>(arg);
self->CheckBatteryStatus();
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
.name = "battery_check_timer",
.skip_unhandled_events = true,
};
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handle_));
ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle_, 500000)); // 1秒
// 初始化ADC
InitializeAdc();
}
void InitializeAdc() {
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = adc_unit_,
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle_));
adc_oneshot_chan_cfg_t chan_config = {
.atten = ADC_ATTEN_DB_12,
.bitwidth = ADC_BITWIDTH_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle_, adc_channel_, &chan_config));
}
~PowerManager() {
if (timer_handle_) {
esp_timer_stop(timer_handle_);
esp_timer_delete(timer_handle_);
}
if (adc_handle_) {
adc_oneshot_del_unit(adc_handle_);
}
}
bool IsCharging() { return is_charging_; }
uint8_t GetBatteryLevel() { return battery_level_; }
};
#endif // __POWER_MANAGER_H__