1、新增电池电量ADC检测;

2、ScreenSet界面的电量进度条实施更新和电量文本显示实施更新
This commit is contained in:
Rdzleo 2026-02-10 10:42:03 +08:00
parent 43bda5954a
commit 99aef2c4e5
5 changed files with 274 additions and 0 deletions

View File

@ -8,6 +8,7 @@ idf_component_register(
"./fatfs/fatfs.c"
"./pages/pages.c"
"./ble/ble.c"
"./battery/battery.c"
"./ui/ui.c"
"./ui/components/ui_comp_hook.c"
"./ui/screens/ui_ScreenHome.c"
@ -31,6 +32,7 @@ idf_component_register(
"./fatfs/include/"
"./pages/include/"
"./ble/include/"
"./battery/include/"
"./ui/"
"./ui/screens/"
# "./axis/include/"

234
main/battery/battery.c Normal file
View File

@ -0,0 +1,234 @@
#include "battery.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_lvgl_port.h"
#include "../ui/screens/ui_ScreenSet.h"
#include "../ui/screens/ui_ScreenHome.h"
#include <stdio.h>
static const char *TAG = "BAT";
// ADC句柄
static adc_oneshot_unit_handle_t adc_handle = NULL;
static adc_cali_handle_t cali_handle = NULL;
static bool cali_enabled = false;
// 当前电池数据
static uint32_t bat_voltage_mv = 0;
static uint8_t bat_level = 0;
// 锂电池放电曲线查找表基于典型3.7V单节锂电池放电特性)
// 电压单位:毫伏,电量单位:百分比
typedef struct {
uint16_t voltage_mv;
uint8_t level;
} bat_curve_point_t;
static const bat_curve_point_t bat_curve[] = {
{4200, 100},
{4150, 95},
{4110, 90},
{4080, 85},
{4020, 80},
{3980, 75},
{3950, 70},
{3910, 65},
{3870, 60},
{3840, 55},
{3800, 50},
{3760, 45},
{3730, 40},
{3700, 35},
{3680, 30},
{3650, 25},
{3630, 20},
{3600, 15},
{3570, 10},
{3530, 5},
{3400, 2},
{3000, 0},
};
#define BAT_CURVE_SIZE (sizeof(bat_curve) / sizeof(bat_curve[0]))
// 电压转电量(线性插值,提高精度)
static uint8_t voltage_to_level(uint32_t voltage_mv)
{
// 超出上限
if (voltage_mv >= bat_curve[0].voltage_mv) {
return 100;
}
// 低于下限
if (voltage_mv <= bat_curve[BAT_CURVE_SIZE - 1].voltage_mv) {
return 0;
}
// 在查找表中线性插值
for (int i = 0; i < BAT_CURVE_SIZE - 1; i++) {
if (voltage_mv >= bat_curve[i + 1].voltage_mv) {
uint32_t v_range = bat_curve[i].voltage_mv - bat_curve[i + 1].voltage_mv;
uint32_t l_range = bat_curve[i].level - bat_curve[i + 1].level;
uint32_t v_offset = voltage_mv - bat_curve[i + 1].voltage_mv;
return bat_curve[i + 1].level + (uint8_t)((v_offset * l_range) / v_range);
}
}
return 0;
}
// 初始化ADC校准
static void battery_cali_init(void)
{
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
// ESP32-S3 使用曲线拟合校准
adc_cali_curve_fitting_config_t cali_cfg = {
.unit_id = ADC_UNIT_1,
.chan = BAT_ADC_CHANNEL,
.atten = ADC_ATTEN_DB_11,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
esp_err_t ret = adc_cali_create_scheme_curve_fitting(&cali_cfg, &cali_handle);
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
// 备用:线性拟合校准
adc_cali_line_fitting_config_t cali_cfg = {
.unit_id = ADC_UNIT_1,
.atten = ADC_ATTEN_DB_11,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
esp_err_t ret = adc_cali_create_scheme_line_fitting(&cali_cfg, &cali_handle);
#else
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
#endif
if (ret == ESP_OK) {
cali_enabled = true;
ESP_LOGI(TAG, "ADC校准初始化成功");
} else {
ESP_LOGW(TAG, "ADC校准不可用将使用原始值换算");
}
}
esp_err_t battery_init(void)
{
// 初始化ADC单元
adc_oneshot_unit_init_cfg_t unit_cfg = {
.unit_id = ADC_UNIT_1,
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
ESP_RETURN_ON_ERROR(adc_oneshot_new_unit(&unit_cfg, &adc_handle),
TAG, "ADC单元初始化失败");
// 配置ADC通道11dB衰减量程约0~2500mV
adc_oneshot_chan_cfg_t chan_cfg = {
.atten = ADC_ATTEN_DB_11,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
ESP_RETURN_ON_ERROR(adc_oneshot_config_channel(adc_handle, BAT_ADC_CHANNEL, &chan_cfg),
TAG, "ADC通道配置失败");
// 初始化校准
battery_cali_init();
ESP_LOGI(TAG, "电池ADC初始化完成 (GPIO%d, ADC1_CH%d, 分压比=%d)",
PIN_BAT_ADC, BAT_ADC_CHANNEL, BAT_VOLTAGE_DIVIDER);
return ESP_OK;
}
uint32_t battery_get_voltage_mv(void)
{
return bat_voltage_mv;
}
uint8_t battery_get_level(void)
{
return bat_level;
}
// 读取ADC并计算电池电压和电量
static void battery_read(void)
{
int adc_sum = 0;
int valid_count = 0;
// 多次采样取平均,滤除噪声
for (int i = 0; i < BAT_SAMPLE_COUNT; i++) {
int raw;
if (adc_oneshot_read(adc_handle, BAT_ADC_CHANNEL, &raw) == ESP_OK) {
adc_sum += raw;
valid_count++;
}
vTaskDelay(pdMS_TO_TICKS(2));
}
if (valid_count == 0) {
ESP_LOGE(TAG, "ADC采样全部失败");
return;
}
int adc_avg = adc_sum / valid_count;
// 使用校准值或原始换算得到ADC引脚电压
int adc_voltage_mv = 0;
if (cali_enabled) {
adc_cali_raw_to_voltage(cali_handle, adc_avg, &adc_voltage_mv);
} else {
// 无校准时按3300mV参考电压线性换算
adc_voltage_mv = (adc_avg * 3300) / 4095;
}
// 乘以分压系数得到实际电池电压
bat_voltage_mv = (uint32_t)adc_voltage_mv * BAT_VOLTAGE_DIVIDER;
// 查找表+插值计算电量百分比
bat_level = voltage_to_level(bat_voltage_mv);
ESP_LOGI(TAG, "ADC原始值=%d, ADC电压=%dmV, 电池电压=%lumV, 电量=%d%%",
adc_avg, adc_voltage_mv, (unsigned long)bat_voltage_mv, bat_level);
}
// 更新UI电量显示线程安全
static void battery_update_ui(void)
{
if (!lvgl_port_lock(100)) {
return;
}
char buf[8];
snprintf(buf, sizeof(buf), "%d%%", bat_level);
// 更新ScreenSet界面的电量圆弧和标签
if (ui_ArcPowerLevel) {
lv_arc_set_value(ui_ArcPowerLevel, bat_level);
}
if (ui_LabelPowerLevel) {
lv_label_set_text(ui_LabelPowerLevel, buf);
}
// 同步更新ScreenHome界面的电量圆弧和标签
if (ui_Arc1) {
lv_arc_set_value(ui_Arc1, bat_level);
}
if (ui_Label1) {
lv_label_set_text(ui_Label1, buf);
}
lvgl_port_unlock();
}
// 电池监控任务
static void battery_monitor_task(void *pvParameters)
{
while (1) {
battery_read();
battery_update_ui();
vTaskDelay(pdMS_TO_TICKS(BAT_MONITOR_INTERVAL_MS));
}
}
void battery_monitor_start(void)
{
xTaskCreate(battery_monitor_task, "bat_mon", 2048, NULL, 3, NULL);
ESP_LOGI(TAG, "电池监控任务已启动,更新间隔%dms", BAT_MONITOR_INTERVAL_MS);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "esp_err.h"
#include <stdint.h>
// 电池ADC引脚配置
#define PIN_BAT_ADC 3 // GPIO3
#define BAT_ADC_CHANNEL ADC_CHANNEL_2 // ADC1_CH2
// 分压比(实际电池电压 = ADC测量电压 * 此系数)
// 根据硬件电路中的分压电阻调整1:1分压器设为2
#define BAT_VOLTAGE_DIVIDER 2
// 采样次数(取平均值,提高精度)
#define BAT_SAMPLE_COUNT 32
// 监控间隔(毫秒)
#define BAT_MONITOR_INTERVAL_MS 5000
// 初始化电池ADC检测
esp_err_t battery_init(void);
// 获取电池电压(毫伏)
uint32_t battery_get_voltage_mv(void);
// 获取电池电量百分比0-100
uint8_t battery_get_level(void);
// 启动电池监控任务周期性读取ADC并更新UI
void battery_monitor_start(void);

View File

@ -24,6 +24,7 @@
#define SPI_LCD_HOST SPI2_HOST // SPI 主机编号 2
#define PIN_MOTOR_EN -1 // 电机使能
#define PIN_BAT_ADC 3 // 电池ADC检测引脚ADC1_CH2
void test_display(esp_lcd_panel_handle_t panel_handle);
void test_gpio();

View File

@ -16,6 +16,7 @@
#include "fatfs.h"
#include "pages.h"
#include "ble.h"
#include "battery.h"
#include "ui/ui.h"
@ -196,6 +197,13 @@ void app_main(void)
ESP_LOGI("MAIN", "10. 渲染步骤 %d 已完成", i+1);// 渲染步骤已完成
}
ESP_LOGI("MAIN", "UI渲染完成");// UI渲染完成
// 初始化电池ADC检测并启动监控任务
ESP_ERROR_CHECK(battery_init());
ESP_LOGI("MAIN", "10. 电池ADC已初始化");
battery_monitor_start();
ESP_LOGI("MAIN", "11. 电池监控任务已启动");
ESP_LOGI("MAIN", "系统初始化完成成功!");// 系统初始化完成成功
// =====================================================================