乐于分享
好东西不私藏

架构分层与接口封装 | APP 层设计方法

架构分层与接口封装 | APP 层设计方法

一、APP 层在整体架构中的定位

重温总图:

APP 层是整个系统的“大脑”:

  • 它不直接操作硬件;

  • 它聚焦功能逻辑和业务状态;

  • 所有底层均通过 HAL 层被抽象访问。

✅ 简言之:
BSP 负责通电,HAL 负责封装,APP 负责思考。


二、APP 层的设计核心思想

设计原则

含义

实现手段

模块化

每个功能单独成模块

app_motor.c / app_sensor.c

事件驱动

主动响应外部或系统事件

回调机制 / 消息队列

状态机

保持系统状态一致与可控

FSM / 枚举状态转移

解耦

不依赖硬件实现

调用 HAL API,通过接口操作

可测可扩展

易模拟、易替换

函数表、接口封装、Mock 测试


三、APP 层文件结构示例

app/├── app_main.c           // 系统启动入口├── app_task.c           // 主任务循环├── app_sensor.c         // 传感器采集逻辑├── app_comm.c           // 通信协议处理├── app_motor.c          // 电机控制逻辑├── app_ui.c             // 显示与键控管理└── app_event.h          // 系统事件定义

每个模块都是独立功能单元,互相通过事件而非直接调用协调。


四、APP 基础结构模板

APP 层的基本功能框架通常包含以下部分:

// app_main.c#include"hal.h"#include"app_sensor.h"#include"app_motor.h"#include"app_comm.h"#include"app_ui.h"voidapp_init(void){    hal_init();         // 初始化硬件抽象层    app_sensor_init();    app_motor_init();    app_comm_init();    app_ui_init();}voidapp_task_loop(void){    while (1) {        app_sensor_update();        app_motor_update();        app_comm_update();        app_ui_update();        hal_delay_ms(10);    }}

特点:

  • 每个模块独立封装,互不干扰

  • 主循环只负责周期性调度

  • 非实时任务可用事件或队列驱动


五、📡 示例1:事件驱动架构在 APP 层的应用

当系统中存在多种异步行为(如传感器数据、电机响应、通信中断),单纯的 while 循环会变复杂。
此时可采用事件驱动模型。

// app_event.htypedef enum {    EVENT_SENSOR_READY,    EVENT_COMM_RECEIVED,    EVENT_MOTOR_FEEDBACK,    EVENT_UI_KEY_PRESSED,    EVENT_NONEapp_event_t;
// app_event.c#include"app_event.h"#include"queue.h"QueueHandle_t g_appEventQueue;voidapp_event_post(app_event_t event){    xQueueSend(g_appEventQueue, &event, 0);}voidapp_event_loop(void){    app_event_t event;    while (xQueueReceive(g_appEventQueue, &event, portMAX_DELAY)) {        switch(event) {            case EVENT_SENSOR_READY:                app_sensor_handle();                break;            case EVENT_COMM_RECEIVED:                app_comm_handle();                break;            case EVENT_MOTOR_FEEDBACK:                app_motor_handle();                break;            case EVENT_UI_KEY_PRESSED:                app_ui_handle();                break;            default:                break;        }    }}

💬 说明:

  • 事件驱动设计让逻辑清晰,从“流程代码”转向“响应代码”。

  • 每个功能模块独立响应事件,不必关心其他模块细节。


六、🧠 示例2:在 APP 层实现状态机(FSM)

以电机控制为例:
电机可能有 停止 → 启动 → 运行 → 故障 等状态。

typedef enum {    MOTOR_STATE_STOP,    MOTOR_STATE_STARTING,    MOTOR_STATE_RUNNING,    MOTOR_STATE_ERRORmotor_state_t;static motor_state_t g_motor_state = MOTOR_STATE_STOP;voidapp_motor_update(void){    switch (g_motor_state) {        case MOTOR_STATE_STOP:            if (hal_sensor_speed() > 0)                g_motor_state = MOTOR_STATE_STARTING;            break;        case MOTOR_STATE_STARTING:            hal_motor_enable();            g_motor_state = MOTOR_STATE_RUNNING;            break;        case MOTOR_STATE_RUNNING:            if (hal_sensor_fault())                g_motor_state = MOTOR_STATE_ERROR;            break;        case MOTOR_STATE_ERROR:            hal_motor_disable();            app_event_post(EVENT_UI_KEY_PRESSED);            break;    }}

状态机图:

✅ 状态机使逻辑流线化,可随时监测系统状态并保证行为一致。


七、🧩 示例3:模块化通信逻辑

独立的通信模块不该直接访问底层外设,只调用 HAL 层函数:

// app_comm.c#include"hal_uart.h"#include"app_event.h"voidapp_comm_init(void){    hal_uart_init(115200);}voidapp_comm_update(void){    uint8_t buf[32];    int len = hal_uart_read(buf, sizeof(buf));    if (len > 0) {        parse_data(buf, len);        app_event_post(EVENT_COMM_RECEIVED);    }}

💡 技巧:

  • 所有数据交互都通过 HAL 层实现;

  • APP 只负责通信协议与数据处理逻辑;

  • 上层逻辑完全独立于硬件接口的实现方式。


八、🎨 示例4:UI 管理与输入响应

键盘与屏幕更新往往是周期性任务,可归纳在 APP 层的 UI 模块

// app_ui.c#include"hal_lcd.h"#include"hal_key.h"voidapp_ui_update(void){    if (hal_key_pressed(KEY_OK)) {        hal_lcd_print("OK pressed!");    }}

✅ APP 层调用 HAL 层接口完成用户交互——逻辑简洁但职责明确。


九、🔄 模块间通信机制:事件 + 消息 + 回调

三种常见方法:

方法

说明

优势

缺点

事件队列

APP 主循环统一处理事件

结构清晰

队列维护略复杂

消息缓冲

模块间传递数据结构

支持复杂交互

存储占用较高

回调函数

模块间即刻响应

灵活性强

依赖回调定义

简例:回调注册机制:

// app_sensor.htypedefvoid(*sensor_data_callback_t)(int value);voidapp_sensor_register_callback(sensor_data_callback_t cb);
// app_sensor.cstatic sensor_data_callback_t sensor_cb = NULL;voidapp_sensor_register_callback(sensor_data_callback_t cb){    sensor_cb = cb;}voidapp_sensor_update(void){    int value = hal_adc_read();    if (sensor_cb) sensor_cb(value);}
// app_motor.cvoid motor_on_sensor_event(int val) {    if (val > 100hal_motor_enable();}void app_motor_init(void) {    app_sensor_register_callback(motor_on_sensor_event);}

⚙️ 通过回调机制,模块之间形成“低耦合响应链”,
类似软件信号通路,无需直接依赖全局变量或函数。


十、📊 APP 层的分层关系地图

通过这种树状分层图,可以清晰看到业务逻辑、模块职责与底层访问路径


十一、工程实战建议 ✏️

技巧

说明

🍀 

接口归一化

为 HAL 层接口定义统一命名规范与错误码

🪶 

APP 层不出现寄存器名

一旦代码出现 

GPIOx

,说明越层了

🧭 

使用枚举与结构体封装状态

避免硬编码状态判断

🧵 

任务线程可分等级

通信任务可独立线程,主任务循环不阻塞

🧩 

模块自测接口

每个 APP 模块预留 

*_test(void)

 自测函数


十二、总结

APP 层不是简单的“上层代码”,
而是整个系统逻辑的“组织者”和“调度者”。

关键特征

实现思想

解耦

不访问硬件寄存器;仅调用 HAL

模块化

功能单元隔离开发、易测试

可扩展

新增模块简洁接入系统事件

可维护

状态机和事件机制让逻辑透明

一致性

逻辑独立于硬件类型


🔜 下一篇预告

第3周:架构分层与接口封装

日期

主题

3月16日

三层模型(BSP / HAL / APP)

3月17日

HAL 层设计要点

3月18日

BSP 层作用

3月19日

APP 层设计方法

⏭️3月20日

接口封装与函数指针表

3月21日

依赖反转原则

3月22日

架构分层总览图

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 架构分层与接口封装 | APP 层设计方法

猜你喜欢

  • 暂无文章