/*============================================================ * TC264 智能车 - 菜单设备层模块 (user_menu_device.c) * * 功能说明: * 提供菜单系统所需的设备数据采集与计算功能。 * 包括电池电压监测、CPU 占用率统计等底层支持。 * * 主要功能: * 1. battery_voltage_gather() - 采集电池电压并计算剩余电量百分比 * 2. cpu_usage_check() - 统计 CPU 占用率 *============================================================*/ #include "zf_common_function.h" /* 通用函数(数学运算等) */ #include "zf_driver_timer.h" /* 定时器驱动(system_start等) */ #include "zf_driver_delay.h" /* 延时函数 */ #include "zf_driver_gpio.h" /* GPIO 驱动 (蜂鸣器) */ #include "user_menu.h" /* 菜单头文件 */ #include "user_menu_device.h" /* 设备层头文件 */ /*============================================================ * 电池电压相关变量 *============================================================*/ float battery_voltage; /* 电池电压值 (V) */ float battery_percentage; /* 电池剩余百分比 (0-100) */ float battery_percentage_filter; /* 电池百分比(经低通滤波平滑后) */ /*============================================================ * CPU占用率相关变量 *============================================================*/ float cpu_usage_percentage; /* CPU占用率 (0-100) */ float cpu_usage_percentage_filter; /* CPU占用率(经低通滤波平滑后) */ /*============================================================ * 电池电压采集与电量计算 * * 计算原理: * 1. ADC 读取电压值 (0-4095) * 2. 根据分压电阻比例换算为实际电池电压 * V_bat = adc_val / 4096 * 36.3 * 校正系数 * 3. 根据锂电池特性估算剩余电量 * 单节锂电池电压范围:3.7V (空) ~ 4.23V (满) * 根据总电压判断串联锂电池节数 * 线性映射到 0-100% * 4. 低通滤波 (一阶惯性滤波) 平滑输出 * * 输入参数: * adc_get_data: ADC 采集的原始值 (0-4095) * * 输出 (全局变量): * battery_voltage - 当前电压值 (V) * battery_percentage - 当前电量百分比 * battery_percentage_filter - 滤波后的电量百分比 *============================================================*/ void battery_voltage_gather(uint16 adc_get_data) { uint8 cell_num = 0; /* 锂电池串联节数 */ float effective_voltage = 0; /* 有效电压范围 */ /* 计算实际电池电压 * 36.3 = 参考电压分压比 (需根据实际硬件电路调整) * VOLTAGE_RECTIFY_COEFFICIENT = 电压校正系数 */ battery_voltage = (float)adc_get_data / 4096.0f * 36.3f * VOLTAGE_RECTIFY_COEFFICIENT; /* 判断锂电池串联节数 (区间阈值法,避免 ceil 在临界值误判) * 1S: < 5.5V, 2S: 5.5~10.5V, 3S: 10.5~15.0V, 4S: > 15.0V */ if(battery_voltage < 5.5f) cell_num = 1; else if(battery_voltage < 10.5f) cell_num = 2; else if(battery_voltage < 15.0f) cell_num = 3; else cell_num = 4; /* 有效电压范围 = 0.5V * 节数 (留出余量) */ effective_voltage = 0.5f * (float)cell_num; /* 将电压线性映射到 0-100% * 基准电压 = 3.7V * 串联节数 (空电截止电压) */ battery_percentage = (func_limit_ab( (battery_voltage - 3.7f * (float)cell_num), 0.0f, effective_voltage) / effective_voltage * 100.0f); /* 一阶低通滤波:新值 = 旧值 * (49/50) + 当前值 * (1/50) * 用于平滑电量显示,避免显示值跳变 */ battery_percentage_filter = (battery_percentage_filter * 49.0f + battery_percentage) / 50.0f; } /*============================================================ * CPU 占用率统计 * * 实现原理: * 每帧处理完成后调用本函数,传入该帧的耗时(us)。 * 累积所有帧的耗时,每 1000ms 计算占比: * CPU占用率 = (累积耗时 / 总时长) * 100% * 使用一阶低通滤波平滑显示。 * * 示例: * 50fps 摄像头,每帧 20ms 周期,处理耗时 8ms * 在 1 秒内累积 50 * 8000us = 400000us * 占用率 = 400000 / (1000*1000) * 100 = 40% *============================================================*/ void cpu_usage_record_frame(uint32 frame_busy_us) { static uint32 cpu_busy_us = 0; /* 累积忙碌时间 (us) */ static uint32 cpu_last_ms = 0; /* 上次统计时刻 (ms) */ static uint8 cpu_timer_ok = 0; /* 系统定时器是否已启动 */ uint32 now; if(!cpu_timer_ok) { system_start(); cpu_timer_ok = 1; } cpu_busy_us += frame_busy_us; now = system_getval_ms(); /* 每 1000ms 统计一次 */ if(now - cpu_last_ms >= 1000) { uint32 elapsed_ms = now - cpu_last_ms; /* 占用率 = 忙时间 / 总时间 * 100 */ /* busy_us / (elapsed_ms * 1000us) * 100 = busy_us / (elapsed_ms * 10) */ cpu_usage_percentage = (float)cpu_busy_us / (float)(elapsed_ms * 10); if(cpu_usage_percentage > 100.0f) cpu_usage_percentage = 100.0f; cpu_busy_us = 0; cpu_last_ms = now; } /* 一阶低通滤波平滑显示 */ cpu_usage_percentage_filter = (cpu_usage_percentage_filter * 49.0f + cpu_usage_percentage) / 50.0f; } /*============================================================ * 低电量蜂鸣报警 * * 功能说明: * 当滤波后电量 <= 30% 时,蜂鸣器"滴滴滴"连响3声后停止。 * 电量回升到 35% 以上后重置,可再次触发。 * 使用 system_getval_ms() 非阻塞计时,不影响其他功能。 *============================================================*/ void low_battery_alarm_check(void) { static uint8 state = 0; /* 0=待机, 1=鸣响, 2=间歇, 3=冷却 */ static uint8 cnt = 0; /* 已响次数 */ static uint32 t0 = 0; /* 状态进入时刻 (ms) */ uint32 now = system_getval_ms(); switch(state) { case 0: /* 待机:电量过低且电池真实存在时触发 */ if(battery_voltage > 5.0f && battery_percentage_filter > 0.1f && battery_percentage_filter <= BATT_ALARM_THRESHOLD) { state = 1; cnt = 0; gpio_high(BEEP_PIN); t0 = now; } break; case 1: /* 鸣响中:持续 200ms 后关闭 */ if(now - t0 >= 200) { gpio_low(BEEP_PIN); cnt++; if(cnt >= 3) state = 3; /* 响完3声进入冷却 */ else state = 2; /* 进入间歇 */ t0 = now; } break; case 2: /* 间歇中:静音 200ms 后再次鸣响 */ if(now - t0 >= 200) { gpio_high(BEEP_PIN); state = 1; t0 = now; } break; case 3: /* 冷却:等待电量回升到 35% 以上,避免重复报警 */ if(battery_percentage_filter > BATT_ALARM_THRESHOLD + 5.0f) state = 0; break; } }