杰理 SDK 文档中心
首页
首页
  • 项目概览

    • AD23N SDK 概述与芯片平台
    • 工程结构与模块划分
  • 快速开始

    • 开发环境搭建与工具链
    • 编译构建指南
    • 烧录与固件升级工具
  • 应用框架与产品工作流

    • 应用入口与模式调度
    • 音乐播放应用
    • MIDI 解码与键盘演奏
    • 录音应用
    • LINEIN 与扩音应用
    • USB 从设备应用
    • 待机、软关机与空闲检测
    • 公共 UI 与 LED 显示
  • 音频子系统

    • 音频解码器框架
    • 音频编码器框架
    • 音效算法库
    • 音频管理与输出通路
  • 存储与文件系统

    • 文件系统层
    • NOR Flash 与虚拟机存储
    • 设备与设备管理
  • 系统服务与运行时

    • 消息机制与事件分发
    • 按键扫描与输入处理
    • 电源管理与低功耗控制
    • 定时器与系统任务
  • 外设驱动与平台

    • CPU 平台与启动流程
    • USB 协议栈与主机/设备驱动
    • SPI 与通用外设接口
  • 固件升级与构建工具

    • 固件升级机制
    • 编译后处理与镜像打包
    • 构建系统与命令行工具

公共 UI 与 LED 显示

本页介绍 AD23N 固件 SDK 中「公共 UI 与 LED 显示」子系统:以 LED 5×7 点阵屏为输出载体、以菜单(Menu)状态机为核心的公共用户界面框架,覆盖从应用层 UI_menu() 调用到 LED 扫描驱动的完整链路。

Purpose and Scope

本页面向需要理解或扩展 AD23N 上 LED 显示逻辑的嵌入式工程师,内容覆盖:

  • sdk/app/src/mbox_flash/common/ui/ 目录下的 UI API 层(ui_api.h/c)与 LED 驱动层(led5x7_driver.h/c)以及公共工具层(ui_common.h/c)。
  • 菜单(Menu)枚举、UI_VAR 显示变量、菜单自动返回与定时刷新机制。
  • LED 显示缓存结构、状态图标位(LED_STATUS)、亮度/闪烁控制与 IO 端口映射。
  • 配置开关(UI_ENABLE、KEY_IR_EN、USB_DEVICE_EN 等)对编译行为的影响。

不属于本页范围(由其他目录页覆盖):具体的音乐播放逻辑(music_play.h)、文件系统扫描(play_file.h)、消息/按键事件分发(msg.h)、以及各业务模块(USB PC、FM、RTC、闹钟)本身的实现。本页只描述它们如何通过 UI_menu() 与 LED 显示子系统交互。

概述

在 AD23N 的 mbox_flash(音箱类)应用中,LED 5×7 点阵屏是主要的用户信息输出设备。系统没有图形化 UI,而是采用**「菜单 + 参数」模型**:任意业务模块(音乐播放、FM 收音、USB PC 模式、AUX、RTC 等)在需要改变显示内容时,只需调用统一的界面接口:

UI_menu(MENU_XXX, arg);

UI 层维护一个全局的 UI_VAR UI_var 结构,记录当前菜单、主菜单、返回计数器和当前参数;UI_menu_api() 根据菜单类型决定是切换显示还是仅在主界面刷新,随后分发到 LED5X7_show_*() 系列函数,将业务数据渲染成 5×7 点阵缓存(bShowBuff)。驱动层则通过定时扫描把缓存搬运到 GPIO 端口,完成动态扫描显示。

这种分层设计的目的:

  1. 解耦业务与显示:业务模块不关心点阵如何扫描,只发菜单事件;
  2. 集中管理显示状态:菜单自动返回、超时、主界面刷新等策略集中在 UI_menu_api() 一处实现;
  3. 低成本复用:LED5X7_show_* 函数族覆盖音乐、FM、音量、EQ、时钟等全部显示场景,新增显示只需增加一个菜单枚举和一个 show 函数。

架构

flowchart TD
    subgraph sg_App["应用层 (mbox_flash)"]
        Music["音乐播放模块"] -->|"UI_menu(MENU_MUSIC_MAIN, arg)"| UIAPI
        FM["FM 收音模块"] -->|"UI_menu(MENU_FM_MAIN, arg)"| UIAPI
        PC["USB PC 模块"] -->|"UI_menu(MENU_PC_MAIN, arg)"| UIAPI
        IR["红外按键/消息"] -->|"UI_menu / post_msg"| UIAPI
    end

    subgraph sg_UI["UI 层 (common/ui)"]
        UIAPI["UI_menu_api()<br/>UI_VAR 状态机"]
        UIAPI -->|"分发 switch(bCurMenu)"| SHOW["LED5X7_show_*() 系列"]
    end

    subgraph sg_LED["LED 驱动层"]
        SHOW --> VAR["LED5X7_VAR<br/>bShowBuff / bBrightness"]
        SCAN["LED5X7_scan()<br/>定时扫描"]
        VAR --> SCAN
        SCAN -->|"动态扫描 GPIO"| HW
    end

    subgraph sg_HW["硬件层"]
        HW["LED 5x7 点阵屏<br/>LED_PORT0 ~ PORT6"]
    end

    subgraph sg_Common["公共工具"]
        UIAPI -.->|"字模/公共函数"| COMMON["ui_common.c/h"]
    end

架构说明:

  • 应用层是显示内容的"生产者":音乐、FM、PC、红外按键等模块通过 UI_menu(menu, arg) 请求显示,或通过 post_msg() 注入定时/超时消息(如 MSG_INPUT_TIMEOUT)。
  • UI 层是显示状态的"裁决者":UI_menu_api() 内部维护 bCurMenu/bMainMenu/bMenuReturnCnt/bCurArg,处理菜单切换、自动返回和刷新去重;随后按 bCurMenu 分发到具体渲染函数。
  • LED 驱动层是渲染与扫描的"执行者":LED5X7_show_*() 把业务参数转换成字模写入 bShowBuff,LED5X7_scan() 定时将缓存输出到 7 个端口位(LED_PORT0~LED_PORT6),实现动态扫描。
  • 公共工具层 ui_common 提供字模表和跨模块的公共渲染辅助函数,被 show 函数族复用。

UI 层所有代码通过段选择指令(#pragma code_seg(".led_ui.text") 等)放入独立的 .led_ui.* 段,便于链接期控制内存/代码布局(见 ui_api.c)。

核心控制流:从菜单事件到点阵刷新

sequenceDiagram
    participant Biz as 业务模块 (音乐/FM/PC/IR)
    participant UI as UI_menu_api() (ui_api.c)
    participant VAR as UI_VAR / LED5X7_VAR
    participant DRV as LED5X7_show_*()
    participant SCAN as LED5X7_scan() (定时器)
    participant HW as LED 端口 (PORT0~6)

    Biz->>UI: UI_menu(MENU_XXX, arg)
    activate UI
    UI->>UI: 处理 MENU_MAIN 自动返回 / 0x80 刷新判定
    UI->>VAR: 更新 bCurMenu / bCurArg / bMenuReturnCnt
    UI->>DRV: switch(bCurMenu) 分发
    deactivate UI
    DRV->>VAR: 写 bShowBuff[0..4] + bBrightness
    loop 每个扫描周期 (定时器中断/任务)
        SCAN->>VAR: 读取 bShowBuff / 闪烁标志
        SCAN->>HW: 输出位码到 LED_PORT0~6
        HW-->>SCAN: 硬件点亮对应 LED 点
    end

UI_menu_api() 决策逻辑

UI_menu_api(u8 menu, int arg) 是整个 UI 层的入口,定义于 ui_api.c。其决策过程分三档:

1. menu == MENU_MAIN(0xFF)—— 自动返回主界面

  • 若 bMenuReturnCnt < UI_RETURN(UI_RETURN 定义为 3,即 3×500ms = 1.5 秒),则累加计数器,并在计数到达 3 时执行真正的返回:先 LED5X7_clear_icon() 清图标,再切回 bMainMenu。
  • 在 KEY_IR_EN 使能时,若当前是 MENU_INPUT_NUMBER(数字输入),则不直接返回,而是 post_msg(1, MSG_INPUT_TIMEOUT) 投递输入超时消息,把"超时"作为业务事件交给消息循环处理——这是显示层与事件层解耦的典型做法。
  • 计数未满时保持 ui_arg = UI_var.bCurArg(沿用原参数),避免刷新主界面时参数丢失。
  • 计数器已满(≥3)后,若当前已回到主界面则直接返回(不重复刷新);否则切回 bMainMenu。

2. menu > 0x80 —— 定时刷新类菜单

这类菜单(MENU_200MS_REFRESH、MENU_100MS_REFRESH、MENU_HALF_SEC_REFRESH 等)表示"仅刷新,不切换界面"。代码要求当前菜单必须是主界面才执行刷新,否则直接忽略。这保证定时器驱动的周期性刷新不会打断用户正在浏览的二级界面(如音量、EQ)。

3. menu <= 0x80 且非 MENU_MAIN —— 普通界面切换

  • 先 LED5X7_clear_icon() 清除全部状态图标,避免旧图标残留;
  • 若目标菜单不是主菜单,则把 bMenuReturnCnt 清零,重新启动自动返回倒计时(等待 UI_RETURN 个周期后回主界面);
  • 更新 bCurMenu = menu、bCurArg = ui_arg。

无论哪条路径,最后都会 LED5X7_setX(0) 复位显示坐标,然后进入 switch (UI_var.bCurMenu) 分发(ui_api.c L85-L120):

分发组菜单渲染函数
系统/开机/等待MENU_POWER_UP、MENU_IDLE、MENU_WAIT、MENU_PC_MAIN、MENU_PC_VOL_UP、MENU_PC_VOL_DOWN、MENU_AUX_MAINLED5X7_show_string_menu()
公共信息MENU_MAIN_VOLLED5X7_show_volume()
音乐相关MENU_MUSIC_MAIN、MENU_PAUSELED5X7_show_music_main()
音乐相关MENU_FILENUMLED5X7_show_filenumber()
音效MENU_HW_EQ(条件编译)、MENU_DEC_EQLED5X7_show_hw_eq() / LED5X7_show_dec_eq()
数字输入MENU_INPUT_NUMBER(KEY_IR_EN)LED5X7_show_IR_number()

菜单枚举与分层语义

菜单枚举定义于 ui_api.h,其数值区间本身就是一种设计约定:

  • 0x00 ~ 0x7F:普通界面(可切换、带自动返回),如 MENU_POWER_UP=0、MENU_IDLE、MENU_PLAY、MENU_FM_MAIN 等;
  • 0x80 ~ 0xFE:刷新/设置类菜单(仅在主界面生效),如 MENU_200MS_REFRESH=0x80、MENU_100MS_REFRESH、MENU_SET_EQ、MENU_SET_PLAY_MODE、MENU_HALF_SEC_REFRESH、MENU_POWER_DOWN;
  • 0xFF:MENU_MAIN,特殊值,表示"回到主界面"。

UI_VAR 结构(ui_api.h L47-L52)集中保存显示状态:

typedef struct _UI_VAR {
    u8  bCurMenu;       //< 当前菜单
    u8  bMainMenu;      //< 主菜单(自动返回目标)
    u8  bMenuReturnCnt; //< 菜单返回计数器
    int  bCurArg;       //< 当前菜单参数
} UI_VAR;

bMainMenu 由业务模块通过 SET_UI_MAIN(x) 宏设置,决定"返回主界面"最终回到哪里——典型如音乐播放时主菜单为 MENU_MUSIC_MAIN,FM 模式下为 MENU_FM_MAIN。

对外宏封装与编译裁剪

ui_api.h L59-L68 提供宏封装,使业务代码无需关心底层实现:

#if UI_ENABLE
extern UI_VAR UI_var;       /*UI 显示变量*/
#define UI_init()	        UI_init_api()
#define UI_menu(x, y)		UI_menu_api(x, y)
#define SET_UI_MAIN(x)	    UI_var.bMainMenu = x
#else
#define UI_init(...)
#define UI_menu(...)
#define SET_UI_MAIN(...)
#endif

当 UI_ENABLE 未定义/为 0 时,所有 UI 调用被编译为空操作——这是产品级裁剪开关:无 LED 屏的低配机型可整体关闭显示功能,同时业务代码无需改动。UI_init() 用于初始化 UI_var 与 LED 驱动,UI_menu(x,y) 为全局显示入口。

LED 驱动层:显示缓存、状态位与端口映射

LED5X7_VAR 显示变量

驱动层的核心状态定义在 led5x7_driver.h L7-L14:

typedef struct _LED5X7_VAR {
    u8  bCoordinateX;       //<X 坐标
    u8  bFlashChar;         //<字符位闪烁
    u8  bFlashIcon;         //<图标闪烁
    u8  bShowBuff[5];       //<显示缓存
    u8  bBrightness;        //<亮度控制
    u8  bShowBuff1[8];
} LED5X7_VAR;

设计要点:

  • bShowBuff[5] 是主显示缓存,最多容纳 5 个字符的 5×7 点阵数据;bShowBuff1[8] 为辅助缓存(如滚动/扩展内容)。两个缓存 + bCoordinateX(当前 X 坐标)支持字符串/菜单的逐段渲染。
  • bFlashChar 与 bFlashIcon 分别是字符位闪烁与图标闪烁控制位,扫描时据此交替亮灭,实现"正在等待/输入中"等提示效果(如 LED5X7_show_waiting())。
  • bBrightness 提供亮度控制,配合 set_LED_fade_out()(渐灭)与 set_LED_all_on()(全亮)实现电源开关的柔和过渡动画。

LED_STATUS 宏把缓存最后一个字节作为图标状态寄存器:

#define LED_STATUS  LED5X7_var.bShowBuff[4]

#define LED_A   BIT(0)   ...   #define LED_H   BIT(7)

//for LED_STATUS —— 每个状态图标占用一个位
#define LED_PLAY    LED_A   // 播放图标
#define LED_PAUSE   LED_B   // 暂停图标
#define LED_USB     LED_C   // USB 图标
#define LED_SD      LED_D   // SD 卡图标
#define LED_2POINT  LED_E   // 冒号(时间分隔点)
#define LED_MHZ     LED_F   // MHz 单位
#define LED_MP3     LED_G   // MP3 图标
#define LED_FM      LED_H   // FM 图标

见 led5x7_driver.h L48-L67。这种位图式图标寄存器使多个状态(如"播放+USB")可以同时点亮,且业务层只需 LED_STATUS |= LED_PLAY 这类位操作即可控制图标,无需关心点阵细节。

端口映射与硬件适配

led5x7_driver.h L69-L90 用条件编译给出两套端口定义:

#if 1
#define LED_PORT0   BIT(12)   // 行扫描线映射到 32 位 IO 掩码
#define LED_PORT1   BIT(11)
#define LED_PORT2   BIT(10)
#define LED_PORT3   BIT(9)
#define LED_PORT4   BIT(7)
#define LED_PORT5   BIT(6)
#define LED_PORT6   BIT(4)
#define LED_PORT_ALL    (LED_PORT0 | LED_PORT1 | LED_PORT2 | LED_PORT3 | LED_PORT4 | LED_PORT5 | LED_PORT6)
#else
#define LED_PORT0   IO_PORTA_04   // 备选方案:直接映射到 GPIO 宏
...
#endif

第一套(默认启用)用 BIT(n) 位掩码描述端口,便于通过一次 32 位端口写操作同时控制 7 根扫描线;第二套映射到 IO_PORTA_xx 具体引脚宏。切换方案只需改动条件编译开关,硬件改版时驱动层零改动。LED5X7_scan() 按行/列分时驱动(动态扫描),利用人眼视觉暂留降低 IO 占用与功耗;实际扫描时序与字模表实现在 led5x7_driver.c 中(该文件同时包含 LED5X7_show_* 渲染函数族与 LED5X7_init)。

渲染函数族总览

函数用途
LED5X7_setX(u8 X)设置当前 X 坐标
LED5X7_show_string_menu(u8 menu)按菜单显示固定字符串(开机/PC/AUX 等)
LED5X7_show_char / show_number显示单字符/数字
LED5X7_show_music_main(int arg) / show_filenumber(int arg)音乐播放主界面、文件序号
LED5X7_show_volume() / show_dec_eq(u32 arg) / show_hw_eq()音量条、软件/硬件 EQ
LED5X7_show_playmode(int arg) / show_fm_main() / show_fm_station()播放模式、FM 频率/电台
LED5X7_show_alarm() / show_RTC_main() / show_pc_main() 等闹钟、时钟、PC 模式
LED5X7_show_pause() / show_waiting() / show_IR_number()暂停、等待动画、红外数字输入
LED5X7_clear_icon()清空图标位
set_LED_fade_out() / set_LED_all_on()渐灭 / 全亮(电源过渡)

函数声明集中在 led5x7_driver.h L17-L44。LED5X7_scan() 与 LED5X7_init() 是驱动入口,分别被定时器/主循环与系统初始化调用。

使用示例

1. 业务模块请求显示(以音乐播放为例)

业务侧的标准用法是直接调用宏,把菜单与参数交给 UI 层:

UI_menu(MENU_MUSIC_MAIN, cur_play_time);

对应 ui_api.h 中的宏定义:#define UI_menu(x, y) UI_menu_api(x, y),业务代码无需 #if 判断,裁剪由宏在编译期完成。参见 ui_api.h L59-L68。

2. UI 层分发到渲染函数(真实代码)

UI_menu_api() 根据当前菜单将参数转发给 LED 渲染函数:

void UI_menu_api(u8 menu, int arg)
{
    int ui_arg = arg;
    /*界面属性-非主界面自动返回*/
    if (menu == MENU_MAIN) {
        if (UI_var.bMenuReturnCnt < UI_RETURN) {
            UI_var.bMenuReturnCnt++;
            if (UI_var.bMenuReturnCnt == UI_RETURN) {
                LED5X7_clear_icon();
#if KEY_IR_EN
                if (UI_var.bCurMenu == MENU_INPUT_NUMBER) {
                    post_msg(1, MSG_INPUT_TIMEOUT);    //输入超时
                } else
#endif
                {
                    UI_var.bCurMenu = UI_var.bMainMenu;
                    UI_var.bCurArg = ui_arg;
                }
            } else {
                ui_arg = UI_var.bCurArg;
            }
        }
        ...
    }
    ...
    switch (UI_var.bCurMenu) {
    /*-----Common Info UI*/
    case MENU_MAIN_VOL:
        LED5X7_show_volume();
        break;
    /*-----Music Related UI*/
    case MENU_MUSIC_MAIN:
    case MENU_PAUSE:
        LED5X7_show_music_main(ui_arg);
        break;
    case MENU_FILENUM:
        LED5X7_show_filenumber(ui_arg);
        break;
    ...
}

来源:ui_api.c L36-L109。注意 MENU_MUSIC_MAIN 与 MENU_PAUSE 共用同一渲染函数、仅参数不同——这体现了"显示语义归菜单、渲染细节归驱动"的分层。

3. 设置主菜单(自动返回目标)

SET_UI_MAIN(MENU_MUSIC_MAIN);

宏展开为 UI_var.bMainMenu = MENU_MUSIC_MAIN,此后用户在音量/EQ 等二级界面停留超过 UI_RETURN(3×500ms)会自动回到音乐主界面。见 ui_api.h L63。

4. 图标位控制(驱动层)

LED_STATUS |= LED_PLAY;      // 点亮播放图标
LED_STATUS &= ~LED_SD;       // 熄灭 SD 图标

通过 LED_STATUS(即 bShowBuff[4])的位操作即可组合任意状态图标,扫描时由驱动一并输出。定义见 led5x7_driver.h L48-L67。

配置选项

配置项类型默认/典型值说明
UI_ENABLE宏开关定义则启用整体裁剪 UI:为 0 时 UI_init/UI_menu/SET_UI_MAIN 编译为空操作(ui_api.h L59-L68)
KEY_IR_EN宏开关依机型使能红外按键:启用后 MENU_INPUT_NUMBER 有效,且输入超时改为投递 MSG_INPUT_TIMEOUT 消息(ui_api.c L45-L49)
USB_DEVICE_EN宏开关依机型决定 MENU_PC_MAIN/MENU_PC_VOL_UP/MENU_PC_VOL_DOWN 菜单是否编译(ui_api.h L11-L15)
AUDIO_HW_EQ_EN / PCM_SW_EQ_EN宏开关依音频配置任一使能时编译 MENU_HW_EQ 显示分支(ui_api.c L111-L115)
UI_RETURN宏常量3自动返回延时计数(n×500ms),#define UI_RETURN 3(ui_api.h L54)
LED_PORT0~6 / LED_PORT_ALL端口宏BIT(12)…BIT(4)LED 扫描线 IO 掩码,备选方案映射 IO_PORTA_xx(led5x7_driver.h L69-L90)
段选择 #pragma编译指令.led_ui.*UI 层代码/数据放入独立段,便于 ROM/RAM 布局管理(ui_api.c L1-L5)

API 参考

void UI_menu_api(u8 menu, int arg) — UI 显示界面处理函数

说明:全局显示入口。menu == MENU_MAIN 触发自动返回逻辑;menu > 0x80 表示仅刷新(须处于主界面);其余为界面切换。随后按 bCurMenu 分发到 LED5X7_show_*()。

参数:

  • menu (u8):目标菜单,取值见 ui_api.h L7-L45 的 MENU_* 枚举(普通界面 0x00~0x7F、刷新类 0x80~0xFE、MENU_MAIN=0xFF);
  • arg (int):菜单参数,如播放时间、文件序号、音量值、EQ 档位等。

返回:无。副作用:更新 UI_var、清除图标、调用渲染函数。

注意:MENU_INPUT_NUMBER 超时路径在 KEY_IR_EN 下通过 post_msg(1, MSG_INPUT_TIMEOUT) 转交消息循环,不会在本函数内直接返回主界面(ui_api.c L46-L48)。

void UI_init_api(void) — UI 初始化

说明:初始化 UI_var 与 LED 驱动(LED5X7_init),由 UI_init() 宏在系统启动时调用。

void LED5X7_scan(void) — LED 动态扫描

说明:驱动层扫描入口,定时读取 LED5X7_VAR(显示缓存、闪烁标志、亮度)并输出到 LED_PORT0~6,实现动态扫描显示。应周期性调用(定时器中断或主循环轮询)。

void LED5X7_show_*(...) — 渲染函数族

说明:led5x7_driver.h 中声明的全部 LED5X7_show_* 函数(show_music_main、show_volume、show_dec_eq(u32 arg)、show_IR_number、show_playmode(int arg)、show_fm_main、show_alarm、show_RTC_main、show_waiting 等)均以业务参数(int/u32)为输入,将对应内容渲染进 bShowBuff/bShowBuff1 并设置图标位。完整列表见 led5x7_driver.h L17-L44。

void LED5X7_setX(u8 X) / LED5X7_clear_icon(void) / set_LED_fade_out(void) / set_LED_all_on(void)

  • LED5X7_setX:设置渲染起始 X 坐标;
  • LED5X7_clear_icon:清零 LED_STATUS(bShowBuff[4]),界面切换前调用以清除旧图标;
  • set_LED_fade_out / set_LED_all_on:电源过渡效果(渐灭/全亮)。

故障模式、边界情况与并发

  • 刷新丢失(时序竞争):menu > 0x80 的定时刷新仅在 bCurMenu == bMainMenu 时生效。若业务在二级界面(如 EQ 设置)期间发送 MENU_200MS_REFRESH,该刷新被静默丢弃——这是有意的设计(避免打断用户浏览),但依赖方须接受"定时刷新可能不立即生效"。
  • 自动返回与参数保留:MENU_MAIN 计数未满时强制 ui_arg = UI_var.bCurArg,保证倒计时期间参数不被外部传入值覆盖;返回动作在计数等于 UI_RETURN(3)的当次调用执行,之后计数保持 ≥3,避免重复返回。
  • 红外输入超时:MENU_INPUT_NUMBER 场景下,MENU_MAIN 不直接回主界面,而是 post_msg(MSG_INPUT_TIMEOUT)。若消息循环未及时处理该消息,输入界面会短暂停留在超时状态——业务层应保证消息及时消费。
  • 图标残留:普通界面切换前统一 LED5X7_clear_icon(),但刷新类(0x80 段)菜单不清图标,因此"主界面+图标"组合(如播放时显示 USB/SD 图标)可保持;若某刷新内容需隐藏图标,须由对应 show 函数自行处理。
  • 并发模型:UI_var 与 LED5X7_var 均为全局单实例,典型调用上下文为单线程(主循环/消息循环)+定时扫描。若从 ISR 直接调用 UI_menu/LED5X7_show_*,需要自行加临界区保护,源码未内置锁。
  • 硬件差异:#if 1 与 #else 两套端口宏并存,若未按实际 PCB 匹配端口方案,扫描会显示错乱(花屏/暗屏)。改版时务必同步检查 LED_PORT0~6 映射。

性能与运维注意

  • 扫描开销:LED5X7_scan() 每次输出 7 根线的位码,5 字符点阵 + 图标共 8×7 个点,单次扫描开销极小;主要成本在扫描频率(闪烁/亮度表现)与占用定时器节拍。若需降低功耗,可降低扫描频率或利用 bBrightness 做占空比调光。
  • 代码/数据段布局:UI 层通过 #pragma 强制放入 .led_ui.text/.led_ui.data 段。链接脚本若未正确保留这些段名,会出现链接错误或段溢出——新增 UI 文件时需保持相同的段声明。
  • ROM 占用:ui_common 字模表(5×7 字符/图标)是静态常量,属可预估的固定开销;新增字符/图标主要增加 .led_ui.text.const 段体积。

扩展点

  1. 新增菜单:在 ui_api.h 枚举中追加值(普通界面 0x00~0x7F 或刷新类 0x80~0xFE),并在 ui_api.c 的 switch (UI_var.bCurMenu) 中增加 case 分支分发到新的 show 函数。
  2. 新增渲染函数:在 led5x7_driver.h 声明、led5x7_driver.c 实现,写入 bShowBuff 并控制 LED_STATUS 图标位即可;字形复用 ui_common 字模。
  3. 新增状态图标:LED_STATUS 字节目前用到 LED_A~LED_H(BIT(0)~BIT(7))共 8 位,已满;如需更多图标须扩展 bShowBuff[4] 之外的空间或增加缓存字节,并同步修改 LED5X7_scan() 的输出逻辑。
  4. 新的业务模块接入:无需改动驱动,只需在业务代码中调用 UI_menu(MENU_XXX, arg) 并(必要时)SET_UI_MAIN() 指定返回目标,即可获得自动返回、定时刷新等全部 UI 语义。
  5. 平台裁剪:通过 UI_ENABLE 可整体关闭 UI;KEY_IR_EN/USB_DEVICE_EN/EQ 相关宏按产品特性裁剪菜单分支。

测试情况

源码目录未发现针对本子系统的独立单元测试文件(MCU 固件项目通常依赖整机验证)。建议的验证路径:开机自检(LED5X7_init 后全亮/渐灭)、各 MENU_* 切换与自动返回计时(3×500ms)、图标位组合显示(播放+USB/SD)、红外数字输入超时消息(MSG_INPUT_TIMEOUT)、定时刷新(200ms/100ms/500ms)在主/非主界面的行为差异。

相关链接

  • ui_api.h — 菜单枚举与 UI 宏
  • ui_api.c — UI 菜单状态机实现
  • led5x7_driver.h — LED 驱动接口与端口映射
  • led5x7_driver.c — LED 扫描与渲染实现
  • ui_common.h / ui_common.c — 公共字模与渲染工具
Prev
待机、软关机与空闲检测