news 2026/3/30 23:08:26

分享一个通用嵌入式软件架构分层设计思想!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分享一个通用嵌入式软件架构分层设计思想!

关注+星标公众,不错过精彩内容

来源 | 嵌入式大杂烩

现在处理器性能和资源已经很强大了,很多时候,我们项目只用处理器10~20%的性能,Flash和RAM资源同样使用率很低。

因此,大部分项目都是建议用上软件框架,今天就来分享一下 “通用嵌入式软件架构分层” 这个实用技巧,顺便聊聊怎么把项目代码分层得明明白白的、维护起来不头疼~

1. Arch-Platform-Target三层抽象

嵌入式系统中的Arch-Platform-Target三层抽象是一种常用的软件架构设计模式,用于提高代码的可移植性和可维护性。

1.1 Arch层(架构支持层)

Arch架构支持层是最底层,与硬件直接相关。它包含了针对特定处理器架构的代码,例如ARM、MIPS等。这一层通常包括中断处理、上下文切换、内存管理单元(MMU)配置、缓存控制等。Arch层为上层提供了统一的硬件抽象接口。

主要职责:

  • CPU架构相关代码

  • 编译器/汇编器支持

  • 核心系统初始化

1.2 Platform层(平台抽象层)

Platform平台抽象层位于Arch层之上,Target层之下。通过Arch层提供的接口来访问硬件,同时为Target层提供统一的平台服务接口。

主要职责:

  • 硬件抽象和驱动封装

  • 提供统一的硬件访问接口

  • 屏蔽底层硬件差异

1.3 Target层(目标应用层)

Target目标应用层属于上层,实现具体的业务逻辑和功能。Target层通过Platform层提供的服务来访问硬件,因此当硬件平台改变时,只需要修改Platform层和Arch层,

而Target层的代码可以保持相对不变。

2. 实际项目常见分层思想

Arch-Platform-Target是个核心分层思想,实际项目中,可能还包含OSAL(系统抽象层)、Services(基础组件服务)等模块。

嵌入式小型项目(单一 RTOS、少量外设):Platform 下可能直接包含OSAL、Services,目录简单、上手快。如:

嵌入式中大型项目(可能换 RTOS/芯片):OSAL 、Services独立于 Platform,同属于中间层。Platform 专注板级与外设封装,OSAL 专注 RTOS API 抽象,Services专注于各种基础组件及中间件的管理。如:

进一步放大细分:

  • Arch:启动、异常、时基。

  • BSP/Platform:板级时钟、PinMux、外设驱动抽象。

  • OSAL:任务/同步/队列/内存适配。

  • Services/Middleware:log、cli/shell、kv/存储、文件系统、网络协议栈、OTA、安全等。

  • Target/App:业务域。

  • 可选:HAL(MCU 厂商层)与 Driver Framework(如 device tree/board cfg)单独放,防止业务碰到寄存器。

3. STM32+RTOS项目的分层设计案例

下面结合 STM32 + RTOS 给出一个体现 Arch-Platform-Target 的职责分离的目录规划和代码示例:

3.1 工程目录设计

stm32_project/ ├── arch/ # CPU/架构相关 │ └── arm/cortex-m0/ │ ├── startup_gcc.s # 启动与向量表 │ ├── system_stm32f0xx.c # 时钟/系统初始化 │ └── arch_port.c # SysTick、临界段封装 ├── platform/ # 平台/Board 支持 │ └── stm32f072/ │ ├── bsp_clock.c │ ├── bsp_gpio.c │ ├── bsp_uart.c │ └── platform_init.c # 统一平台初始化入口 ├── osal/ # OS 抽象层(屏蔽不同 RTOS) │ ├── osal.h # 统一任务/互斥/队列接口 │ ├── osal_freertos.c # FreeRTOS 适配实现 │ └── osal_port.h # 基础类型、错误码 ├── services/ # 常用系统组件 │ ├── log/ │ └── kv/ ├── external/ # 第三方库(协议栈/文件系统/安全等) │ ├── lwip/ │ ├── mbedtls/ │ └── littlefs/ ├── target/ # 业务/应用 │ └── app/ │ ├── main.c # 任务创建、启动调度 │ └── app_led.c # 具体业务 ├── freertos/ # FreeRTOS 内核与移植 │ ├── CMSIS/ # 官方 CMSIS 头文件 │ ├── portable/GCC/ARM_CM0/ # FreeRTOS Cortex-M0 移植层 │ └── FreeRTOSConfig.h └── drivers/ # MCU HAL 库 └── stm32f0xx_hal/

分层约束:

  • Arch 仅处理与核心架构相关的启动、时钟、异常向量、SysTick 驱动,不直接操作业务外设。

  • Platform 负责芯片外设封装(GPIO、UART、I2C 等)和板级资源命名,向 Target 暴露统一 API。

  • Target 只依赖 Platform 提供的接口做业务,不直接引用 HAL/寄存器。

3.2 关键代码示例

Arch 层:SysTick 驱动 FreeRTOS 时基

arch/arm/cortex-m0/arch_port.c

Arch 层只负责把内核时钟和中断接好,具体任务调度逻辑由 FreeRTOS 内核完成。更换 RTOS 时,Arch 层需要少量调整。

Platform 层:封装 LED

platform/stm32f072_nucleo/bsp_gpio.c

Platform 层对外暴露platform_led_*等统一接口,Target 层不感知 HAL 细节。

Target 层:创建任务并调用平台接口

target/app/app_led.c

target/app/main.c

Target 层只依赖 Platform 的初始化与业务 API,后续如果换成 GD32 或更换板载外设,仅需改动 Platform 与 Arch,不影响业务代码。

OSAL 层:统一 RTOS 抽象

osal/osal.h

osal/osal_freertos.c(适配 FreeRTOS)

#include"osal.h" #include"FreeRTOS.h" #include"task.h" #include"queue.h" #include"semphr.h" intosal_thread_create(osal_thread_t *t, constchar *name, osal_thread_entry_t entry, void *arg, uint16_t stack_words, uint8_t priority) { if (xTaskCreate(entry, name, stack_words, arg, priority, (TaskHandle_t *)t) != pdPASS) return OSAL_ERR_FAIL; return OSAL_OK; } voidosal_thread_delay_ms(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } voidosal_start_scheduler(void) { vTaskStartScheduler(); } intosal_mutex_create(osal_mutex_t *m) { *m = xSemaphoreCreateMutex(); return *m ? OSAL_OK : OSAL_ERR_FAIL; } intosal_mutex_lock(osal_mutex_t m, uint32_t timeout_ms) { return xSemaphoreTake((SemaphoreHandle_t)m, pdMS_TO_TICKS(timeout_ms)) == pdTRUE ? OSAL_OK : OSAL_ERR_TIMEOUT; } voidosal_mutex_unlock(osal_mutex_t m) { xSemaphoreGive((SemaphoreHandle_t)m); } intosal_queue_create(osal_queue_t *q, uint16_t item_size, uint16_t len) { *q = xQueueCreate(len, item_size); return *q ? OSAL_OK : OSAL_ERR_FAIL; } intosal_queue_send(osal_queue_t q, constvoid *item, uint32_t timeout_ms) { return xQueueSend(q, item, pdMS_TO_TICKS(timeout_ms)) == pdTRUE ? OSAL_OK : OSAL_ERR_TIMEOUT; } intosal_queue_recv(osal_queue_t q, void *item, uint32_t timeout_ms) { return xQueueReceive(q, item, pdMS_TO_TICKS(timeout_ms)) == pdTRUE ? OSAL_OK : OSAL_ERR_TIMEOUT; }

OSAL 封装线程、延时、互斥、队列,并对外暴露统一的错误码(在osal_port.h中定义OSAL_OK/OSAL_ERR_FAIL/OSAL_ERR_TIMEOUT)。若切换到 RT-Thread 或 Zephyr,仅需新增对应osal_xxx.c

切换 RTOS的要点:
  • 新增适配文件:osal/osal_xxx.c,实现与osal.h一致的 API。

  • 调整启动与时基:Arch层改为调用新RTOS的启动入口,并按新RTOS要求设置 SysTick/中断优先级;移除vTaskStartScheduler相关逻辑。

  • 配置与链接:替换 RTOS 源码与配置文件(如移除 FreeRTOS 源,加入新RTOS源),在构建脚本中切换编译宏(例如-DUSE_RTTHREAD)。

  • 检查栈/优先级语义:如果不同RTOS优先级数值方向不同,适配时需在 OSAL 内部转换,保证业务侧传入的“逻辑优先级”保持一致。

  • 队列/超时语义:确认阻塞超时单位(ms 或 tick),在 OSAL 内部做统一换算,避免业务层被不同 RTOS 语义影响。

4. 总结

嵌入式软件中,合理的分层设计可以提升可移植、可维护、可测试性。可以用 Arch/Platform/OSAL/Services/Target 分层隔离硬件差异、RTOS 差异与业务逻辑。

分层带来的实际收益:

  • 可移植:更换 MCU(F0 -> F4 或 GD32)时,Target 基本不变,只需更新 Arch/Platform。

  • 可维护:外设封装集中在 Platform,避免业务层散落 HAL 调用。

  • 可测试:Platform API 可在仿真或 PC Mock 中替换实现,便于单元测试业务逻辑。

4.1 QA

  1. Q:OSAL 是必须的吗?
    A:若项目只用一种 RTOS,可以不加 OSAL;但预期会换 RTOS(如 FreeRTOS ⇄ RT-Thread),建议在早期就放 OSAL,后续只需替换适配文件,业务无需改动。

  2. Q:Platform 层和驱动 HAL 的区别?
    A:HAL 是芯片厂的寄存器封装;Platform 层在 HAL 之上做二次封装并用统一命名(如platform_led_toggle),对 Target 暴露一致接口,避免业务代码直接依赖 HAL 细节。

------------END------------

分享一个提高MCU计算能力的神器!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/29 7:33:56

Spring中Bean的生命周期

文章目录 1. **生产(Production)**(1)定义 Bean(Bean Definition)(2)创建 Bean(Bean Instantiation & Initialization)(3)添加 Be…

作者头像 李华
网站建设 2026/3/30 7:58:16

Vivado2025逻辑综合优化技巧:时序收敛操作指南

Vivado 2025逻辑综合优化实战:从时序违例到一次收敛的进阶之路 你有没有遇到过这样的场景?RTL代码刚写完,信心满满地跑综合,结果打开 timing_summary 一看——建立时间违例-0.8ns。明明仿真波形完美,功能也没问题&am…

作者头像 李华
网站建设 2026/3/28 23:49:36

CSS 定位

一、相对定位 二、绝对定位 三、固定定位 四、粘性定位 五、定位层级

作者头像 李华
网站建设 2026/3/27 9:18:01

为客服系统赋能:接入anything-llm实现自动应答

为客服系统赋能:接入 AnythingLLM 实现自动应答 在企业服务的日常运转中,客服部门常常面临这样的窘境:一边是客户对“秒回”的期待越来越高,另一边却是人工坐席被重复性问题淹没,培训成本居高不下,回答口径…

作者头像 李华
网站建设 2026/3/27 20:23:34

VMD-Transformer-GRU组合模型锂电池剩余寿命预测(NASA电池数据集容量特征提取+RUL电池剩余寿命预测)MATLAB代码

代码功能 1. rongliangtiqu.m - 电池容量数据提取 主要功能: 从NASA电池数据集中提取放电容量数据并进行可视化分析 算法步骤: 导入四个电池数据集(B0005, B0006, B0007, B0018)遍历每个电池的循环数据,筛选放电循环提取放电容量数据并存…

作者头像 李华
网站建设 2026/3/28 4:29:16

wl_arm在过程控制中的典型架构:图解说明

从传感器到云端:一文讲透 wl_arm 在现代过程控制中的实战架构你有没有遇到过这样的场景?产线上的传统 PLC 看似稳定,但一旦要接入云平台、跑个预测性维护算法,或者扩展几十路模拟量输入时,立刻变得力不从心——通信慢、…

作者头像 李华