Files
system-design/software-copyright/12-writech-pen-firmware/task/power_monitor_task.c
T
2026-03-22 15:24:40 +08:00

429 lines
12 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.
/*
* 自然写智能点阵笔嵌入式固件软件 V1.0
* power_monitor_task.c - 电源监测与低功耗管理任务
*
* 功能说明:
* 1. 电池电压ADC采样与电量百分比估算
* 2. 充电检测与充电状态管理
* 3. 低电量告警与自动关机保护
* 4. 低功耗状态机(Active → Light Sleep → Deep Sleep
* 5. USB充电IC状态监测
*/
#include <stdint.h>
#include <stdbool.h>
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
#include "semphr.h"
#include "hal_adc.h"
#include "hal_gpio.h"
#include "power_manager.h"
#include "led_driver.h"
/* ========== 电池参数定义 ========== */
/* 电池满充电压(mV):锂聚合物3.7V标称 */
#define BATTERY_FULL_MV 4200
/* 电池截止电压(mV):低于此值必须关机保护 */
#define BATTERY_CUTOFF_MV 3300
/* 低电量告警阈值(百分比) */
#define LOW_BATTERY_THRESHOLD 10
/* 极低电量关机阈值 */
#define CRITICAL_BATTERY_THRESHOLD 3
/* ADC参考电压(mV */
#define ADC_VREF_MV 3300
/* ADC分辨率(12位) */
#define ADC_MAX_VALUE 4095
/* 电池电压分压比(电阻分压器:R1=100K, R2=100K → 2:1 */
#define BATTERY_DIVIDER_RATIO 2
/* 电压采样滤波窗口大小 */
#define VOLTAGE_FILTER_WINDOW 8
/* 电源监测周期(毫秒) */
#define POWER_MONITOR_PERIOD_MS 5000
/* 自动休眠超时(毫秒):笔静止超过此时间自动进入深度睡眠 */
#define AUTO_SLEEP_TIMEOUT_MS 300000 /* 5分钟 */
/* ========== 电源状态枚举 ========== */
typedef enum {
POWER_STATE_ACTIVE, /* 活跃状态(正常工作) */
POWER_STATE_LIGHT_SLEEP, /* 轻度睡眠(BLE保持连接) */
POWER_STATE_DEEP_SLEEP, /* 深度睡眠(仅保留RTC唤醒) */
POWER_STATE_CHARGING, /* 充电中 */
POWER_STATE_SHUTDOWN /* 关机保护 */
} PowerState;
/* ========== 外部引用 ========== */
extern EventGroupHandle_t g_ble_event_group;
extern SemaphoreHandle_t g_system_mutex;
/* 系统状态结构体(在main.c中定义) */
typedef struct {
bool pen_is_down;
bool ble_connected;
bool is_charging;
uint8_t battery_percent;
uint32_t total_strokes;
uint32_t uptime_seconds;
uint8_t error_flags;
} SystemState;
extern SystemState g_system_state;
/* ========== 静态变量 ========== */
/* 当前电源状态 */
static PowerState s_power_state = POWER_STATE_ACTIVE;
/* 电压采样滤波缓冲区 */
static uint16_t s_voltage_buffer[VOLTAGE_FILTER_WINDOW];
static uint8_t s_voltage_buffer_index = 0;
static bool s_voltage_buffer_full = false;
/* 最后一次活动时间(用于自动休眠判断) */
static uint32_t s_last_activity_time = 0;
/* ========== 电压采样与滤波 ========== */
/**
* 读取电池原始ADC值并转换为电压(mV)
*/
static uint16_t read_battery_voltage_mv(void) {
/* 读取ADC原始值 */
uint16_t adc_raw = hal_adc_read(ADC_CHANNEL_BATTERY);
/* ADC值 → 分压后电压 → 实际电池电压 */
uint32_t voltage_mv = (uint32_t)adc_raw * ADC_VREF_MV / ADC_MAX_VALUE;
voltage_mv *= BATTERY_DIVIDER_RATIO;
return (uint16_t)voltage_mv;
}
/**
* 移动平均滤波
* 对连续采样的电压值取平均,消除ADC噪声
*
* @param new_sample 新采样的电压值(mV
* @return 滤波后的电压值
*/
static uint16_t voltage_filter(uint16_t new_sample) {
s_voltage_buffer[s_voltage_buffer_index] = new_sample;
s_voltage_buffer_index = (s_voltage_buffer_index + 1) % VOLTAGE_FILTER_WINDOW;
if (s_voltage_buffer_index == 0) {
s_voltage_buffer_full = true;
}
uint8_t count = s_voltage_buffer_full ? VOLTAGE_FILTER_WINDOW : s_voltage_buffer_index;
uint32_t sum = 0;
uint8_t i;
for (i = 0; i < count; i++) {
sum += s_voltage_buffer[i];
}
return (uint16_t)(sum / count);
}
/* ========== 电量百分比估算 ========== */
/**
* 根据电池电压估算电量百分比
* 使用分段线性插值模拟锂电池放电曲线
*
* 锂聚合物电池典型放电曲线(近似分段线性):
* 4200mV → 100%
* 4060mV → 90%
* 3920mV → 80%
* 3830mV → 70%
* 3750mV → 60%
* 3680mV → 50%
* 3620mV → 40%
* 3570mV → 30%
* 3500mV → 20%
* 3400mV → 10%
* 3300mV → 0%
*/
static uint8_t estimate_battery_percent(uint16_t voltage_mv) {
/* 放电曲线查找表(电压mV → 百分比) */
static const struct {
uint16_t voltage;
uint8_t percent;
} discharge_curve[] = {
{4200, 100},
{4060, 90},
{3920, 80},
{3830, 70},
{3750, 60},
{3680, 50},
{3620, 40},
{3570, 30},
{3500, 20},
{3400, 10},
{3300, 0}
};
const uint8_t table_size = sizeof(discharge_curve) / sizeof(discharge_curve[0]);
/* 边界检查 */
if (voltage_mv >= discharge_curve[0].voltage) {
return 100;
}
if (voltage_mv <= discharge_curve[table_size - 1].voltage) {
return 0;
}
/* 分段线性插值 */
uint8_t i;
for (i = 0; i < table_size - 1; i++) {
if (voltage_mv >= discharge_curve[i + 1].voltage) {
uint16_t v_high = discharge_curve[i].voltage;
uint16_t v_low = discharge_curve[i + 1].voltage;
uint8_t p_high = discharge_curve[i].percent;
uint8_t p_low = discharge_curve[i + 1].percent;
/* 线性插值 */
uint16_t v_range = v_high - v_low;
uint16_t v_offset = voltage_mv - v_low;
return p_low + (uint8_t)((uint32_t)v_offset * (p_high - p_low) / v_range);
}
}
return 0;
}
/* ========== 充电检测 ========== */
/**
* 检测USB充电状态
* 通过GPIO读取充电IC的状态引脚
*
* @return 0=未充电, 1=充电中, 2=充满
*/
static uint8_t detect_charging_state(void) {
/* STAT1引脚:低电平=充电中,高电平=充满或未充电 */
bool stat1 = hal_gpio_read(GPIO_CHARGE_STAT1);
/* STAT2引脚:低电平=充满 */
bool stat2 = hal_gpio_read(GPIO_CHARGE_STAT2);
/* USB电源检测引脚 */
bool usb_power = hal_gpio_read(GPIO_USB_DETECT);
if (!usb_power) {
return 0; /* USB未连接,未充电 */
}
if (!stat1) {
return 1; /* 充电中 */
}
if (!stat2) {
return 2; /* 充满 */
}
return 0;
}
/* ========== LED状态指示 ========== */
/**
* 根据电源状态和电量更新LED指示
*/
static void update_led_indication(uint8_t battery_percent, uint8_t charge_state) {
if (charge_state == 1) {
/* 充电中:绿色呼吸灯 */
led_set_mode(LED_MODE_BREATH_GREEN);
} else if (charge_state == 2) {
/* 充满:绿色常亮 */
led_set_mode(LED_MODE_SOLID_GREEN);
} else if (battery_percent <= LOW_BATTERY_THRESHOLD) {
/* 低电量:红色慢闪 */
led_set_mode(LED_MODE_BLINK_RED);
} else if (battery_percent <= CRITICAL_BATTERY_THRESHOLD) {
/* 极低电量:红色快闪 */
led_set_mode(LED_MODE_FAST_BLINK_RED);
} else if (g_system_state.ble_connected) {
/* 已连接:蓝色常亮 */
led_set_mode(LED_MODE_SOLID_BLUE);
} else {
/* 未连接:蓝色慢闪 */
led_set_mode(LED_MODE_BLINK_BLUE);
}
}
/* ========== 低功耗管理 ========== */
/**
* 进入轻度睡眠模式
* 关闭不必要的外设,降低CPU频率
* BLE连接保持,可被笔尖触摸或BLE命令唤醒
*/
static void enter_light_sleep(void) {
if (s_power_state == POWER_STATE_LIGHT_SLEEP) {
return;
}
/* 关闭摄像头 */
camera_power_off();
/* 关闭SPI(传感器通信) */
hal_spi_disable(SPI_PORT_1);
/* 降低CPU频率到16MHz */
SystemClock_SetLow();
/* LED关闭 */
led_set_mode(LED_MODE_OFF);
s_power_state = POWER_STATE_LIGHT_SLEEP;
}
/**
* 进入深度睡眠模式
* 关闭所有外设和BLE,仅保留RTC和GPIO唤醒
* 适用于长时间不使用的场景
*/
static void enter_deep_sleep(void) {
/* 断开BLE连接 */
ble_gatt_disconnect();
ble_gatt_stop_advertising();
/* 关闭所有外设 */
camera_power_off();
hal_spi_disable(SPI_PORT_1);
hal_i2c_disable(I2C_PORT_1);
hal_adc_disable(ADC_CHANNEL_BATTERY);
/* 保存系统状态到Flash */
offline_storage_flush();
/* 配置唤醒源(笔尖GPIO中断唤醒) */
hal_gpio_set_wakeup(GPIO_PEN_TIP_PIN, GPIO_WAKEUP_RISING);
/* 进入MCU深度睡眠模式(不应返回) */
hal_enter_deep_sleep();
}
/**
* 从轻度睡眠唤醒,恢复正常工作状态
*/
static void wake_from_light_sleep(void) {
/* 恢复CPU频率 */
SystemClock_Config();
/* 重新使能SPI */
hal_spi_enable(SPI_PORT_1);
s_power_state = POWER_STATE_ACTIVE;
s_last_activity_time = xTaskGetTickCount();
}
/* ========== 电源监测主任务 ========== */
/**
* 电源监测任务(FreeRTOS任务函数)
*
* 运行流程:
* 1. 定期读取电池电压并估算电量
* 2. 检测充电状态
* 3. 低电量告警和自动关机保护
* 4. 更新LED状态指示
* 5. 自动休眠判断
*/
void power_monitor_task(void *pvParameters) {
(void)pvParameters;
TickType_t last_wake_time = xTaskGetTickCount();
s_last_activity_time = last_wake_time;
while (1) {
/* 读取并滤波电池电压 */
uint16_t raw_mv = read_battery_voltage_mv();
uint16_t filtered_mv = voltage_filter(raw_mv);
/* 估算电量百分比 */
uint8_t battery_percent = estimate_battery_percent(filtered_mv);
/* 检测充电状态 */
uint8_t charge_state = detect_charging_state();
/* 更新全局系统状态 */
if (xSemaphoreTake(g_system_mutex, pdMS_TO_TICKS(100)) == pdTRUE) {
g_system_state.battery_percent = battery_percent;
g_system_state.is_charging = (charge_state == 1);
xSemaphoreGive(g_system_mutex);
}
/* 更新LED指示 */
update_led_indication(battery_percent, charge_state);
/* 低电量告警处理 */
if (battery_percent <= LOW_BATTERY_THRESHOLD && charge_state == 0) {
/* 通知上位机低电量 */
xEventGroupSetBits(g_ble_event_group, EVT_LOW_BATTERY);
}
/* 极低电量自动关机保护 */
if (battery_percent <= CRITICAL_BATTERY_THRESHOLD && charge_state == 0) {
enter_deep_sleep();
}
/* 充电状态变化通知 */
if (charge_state > 0) {
xEventGroupSetBits(g_ble_event_group, EVT_CHARGING);
s_power_state = POWER_STATE_CHARGING;
s_last_activity_time = xTaskGetTickCount();
}
/* 自动休眠检查:笔没有书写且BLE空闲超时 */
if (!g_system_state.pen_is_down && charge_state == 0) {
uint32_t idle_time = (xTaskGetTickCount() - s_last_activity_time)
* portTICK_PERIOD_MS;
if (idle_time > AUTO_SLEEP_TIMEOUT_MS) {
if (s_power_state == POWER_STATE_ACTIVE) {
enter_light_sleep();
} else if (idle_time > AUTO_SLEEP_TIMEOUT_MS * 2) {
/* 静止超过10分钟,进入深度睡眠 */
enter_deep_sleep();
}
}
} else {
/* 有活动,重置计时器 */
s_last_activity_time = xTaskGetTickCount();
if (s_power_state == POWER_STATE_LIGHT_SLEEP) {
wake_from_light_sleep();
}
}
/* 休眠到下一个监测周期 */
vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(POWER_MONITOR_PERIOD_MS));
}
}
/* ========== 外部查询接口 ========== */
/** 获取当前电量百分比(供其他模块调用) */
uint8_t power_get_battery_percent(void) {
return g_system_state.battery_percent;
}
/** 获取当前电源状态 */
uint8_t power_get_state(void) {
return (uint8_t)s_power_state;
}