software copyright
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 自然写智能点阵笔嵌入式固件软件 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;
|
||||
}
|
||||
Reference in New Issue
Block a user