1+ #pragma once
2+ #include < vector>
3+ #include < functional>
4+
5+ #include < esp_timer.h>
6+ #include < driver/gpio.h>
7+ #include < esp_adc/adc_oneshot.h>
8+ #include < driver/adc.h>
9+ #include < esp_log.h>
10+
11+ class PowerManager {
12+ private:
13+ esp_timer_handle_t timer_handle_;
14+ std::function<void (bool )> on_charging_status_changed_;
15+ std::function<void (bool )> on_low_battery_status_changed_;
16+
17+ gpio_num_t charging_pin_;
18+ std::vector<uint16_t > adc_values_;
19+ uint32_t battery_level_ = 0 ;
20+ bool is_charging_ = false ;
21+ bool is_low_battery_ = false ;
22+ int ticks_ = 0 ;
23+ const int kBatteryAdcInterval = 60 ;
24+ const int kBatteryAdcDataCount = 3 ;
25+ const int kLowBatteryLevel = 20 ;
26+
27+ adc_oneshot_unit_handle_t adc_handle_;
28+ adc_channel_t adc_channel_;
29+
30+ void CheckBatteryStatus () {
31+ // Get charging status
32+ bool new_charging_status = gpio_get_level (charging_pin_) == 1 ;
33+ if (new_charging_status != is_charging_) {
34+ is_charging_ = new_charging_status;
35+ if (on_charging_status_changed_) {
36+ on_charging_status_changed_ (is_charging_);
37+ }
38+ ReadBatteryAdcData ();
39+ return ;
40+ }
41+
42+ // 如果电池电量数据不足,则读取电池电量数据
43+ if (adc_values_.size () < kBatteryAdcDataCount ) {
44+ ReadBatteryAdcData ();
45+ return ;
46+ }
47+
48+ // 如果电池电量数据充足,则每 kBatteryAdcInterval 个 tick 读取一次电池电量数据
49+ ticks_++;
50+ if (ticks_ % kBatteryAdcInterval == 0 ) {
51+ ReadBatteryAdcData ();
52+ }
53+ }
54+
55+ void ReadBatteryAdcData () {
56+ int adc_value;
57+ ESP_ERROR_CHECK (adc_oneshot_read (adc_handle_, adc_channel_, &adc_value));
58+
59+ // 将 ADC 值添加到队列中
60+ adc_values_.push_back (adc_value);
61+ if (adc_values_.size () > kBatteryAdcDataCount ) {
62+ adc_values_.erase (adc_values_.begin ());
63+ }
64+ uint32_t average_adc = 0 ;
65+ for (auto value : adc_values_) {
66+ average_adc += value;
67+ }
68+ average_adc /= adc_values_.size ();
69+
70+ // 定义电池电量区间 - 根据实际硬件调整这些值
71+ const struct {
72+ uint16_t adc;
73+ uint8_t level;
74+ } levels[] = {
75+ {1980 , 0 },
76+ {2081 , 20 },
77+ {2163 , 40 },
78+ {2250 , 60 },
79+ {2340 , 80 },
80+ {2480 , 100 }
81+ };
82+
83+ // 低于最低值时
84+ if (average_adc < levels[0 ].adc ) {
85+ battery_level_ = 0 ;
86+ }
87+ // 高于最高值时
88+ else if (average_adc >= levels[5 ].adc ) {
89+ battery_level_ = 100 ;
90+ } else {
91+ // 线性插值计算中间值
92+ for (int i = 0 ; i < 5 ; i++) {
93+ if (average_adc >= levels[i].adc && average_adc < levels[i+1 ].adc ) {
94+ float ratio = static_cast <float >(average_adc - levels[i].adc ) / (levels[i+1 ].adc - levels[i].adc );
95+ battery_level_ = levels[i].level + ratio * (levels[i+1 ].level - levels[i].level );
96+ break ;
97+ }
98+ }
99+ }
100+
101+ // Check low battery status
102+ if (adc_values_.size () >= kBatteryAdcDataCount ) {
103+ bool new_low_battery_status = battery_level_ <= kLowBatteryLevel ;
104+ if (new_low_battery_status != is_low_battery_) {
105+ is_low_battery_ = new_low_battery_status;
106+ if (on_low_battery_status_changed_) {
107+ on_low_battery_status_changed_ (is_low_battery_);
108+ }
109+ }
110+ }
111+
112+ ESP_LOGI (" PowerManager" , " ADC value: %d average: %ld level: %ld" , adc_value, average_adc, battery_level_);
113+ }
114+
115+ public:
116+ PowerManager (gpio_num_t charging_pin, adc_channel_t adc_channel)
117+ : charging_pin_(charging_pin), adc_channel_(adc_channel) {
118+ // 初始化充电引脚
119+ gpio_config_t io_conf = {};
120+ io_conf.intr_type = GPIO_INTR_DISABLE;
121+ io_conf.mode = GPIO_MODE_INPUT;
122+ io_conf.pin_bit_mask = (1ULL << charging_pin_);
123+ io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
124+ io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
125+ gpio_config (&io_conf);
126+
127+ // 创建电池电量检查定时器
128+ esp_timer_create_args_t timer_args = {
129+ .callback = [](void * arg) {
130+ PowerManager* self = static_cast <PowerManager*>(arg);
131+ self->CheckBatteryStatus ();
132+ },
133+ .arg = this ,
134+ .dispatch_method = ESP_TIMER_TASK,
135+ .name = " battery_check_timer" ,
136+ .skip_unhandled_events = true ,
137+ };
138+ ESP_ERROR_CHECK (esp_timer_create (&timer_args, &timer_handle_));
139+ ESP_ERROR_CHECK (esp_timer_start_periodic (timer_handle_, 100000 ));
140+
141+ // 初始化 ADC
142+ adc_oneshot_unit_init_cfg_t init_config = {
143+ .unit_id = ADC_UNIT_1,
144+ .ulp_mode = ADC_ULP_MODE_DISABLE,
145+ };
146+ ESP_ERROR_CHECK (adc_oneshot_new_unit (&init_config, &adc_handle_));
147+
148+ adc_oneshot_chan_cfg_t chan_config = {
149+ .atten = ADC_ATTEN_DB_12,
150+ .bitwidth = ADC_BITWIDTH_12,
151+ };
152+ ESP_ERROR_CHECK (adc_oneshot_config_channel (adc_handle_, adc_channel_, &chan_config));
153+ }
154+
155+ ~PowerManager () {
156+ if (timer_handle_) {
157+ esp_timer_stop (timer_handle_);
158+ esp_timer_delete (timer_handle_);
159+ }
160+ if (adc_handle_) {
161+ adc_oneshot_del_unit (adc_handle_);
162+ }
163+ }
164+
165+ bool IsCharging () {
166+ // 如果电量已经满了,则不再显示充电中
167+ if (battery_level_ == 100 ) {
168+ return false ;
169+ }
170+ return is_charging_;
171+ }
172+
173+ bool IsDischarging () {
174+ // 没有区分充电和放电,所以直接返回相反状态
175+ return !is_charging_;
176+ }
177+
178+ uint8_t GetBatteryLevel () {
179+ return battery_level_;
180+ }
181+
182+ void OnLowBatteryStatusChanged (std::function<void (bool )> callback) {
183+ on_low_battery_status_changed_ = callback;
184+ }
185+
186+ void OnChargingStatusChanged (std::function<void (bool )> callback) {
187+ on_charging_status_changed_ = callback;
188+ }
189+ };
0 commit comments