首页 / 游戏 / 正文

createmutex(通用嵌入式软件架构分层设计思想)

放大字体  缩小字体 来源:2026年冬奥会在哪里举行 2026-04-17 17:11  浏览次数:8

大家好,我是杂烩君。最近后台好多朋友催更呀~

有人说 “能不能聊聊 STM32、GD32 这些常用单片机的代码分层设计?写项目时总乱糟糟的”!

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

这不就安排上了~ 今天咱们就聚焦 “通用嵌入式软件架构分层” 这个实用技巧,聊聊怎么把项目代码分层得明明白白的、维护起来不头疼~

1. Arch-Platform-Target三层抽象

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

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

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,目录简单、上手快。如:

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

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

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

进一步放大细分:

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

  • 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

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

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

Platform 层:封装 LED

platform/stm32f072_nucleo/bsp_gpio.c

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

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

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

target/app/app_led.c

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

target/app/main.c

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

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

OSAL 层:统一 RTOS 抽象

osal/osal.h

通用嵌入式软件架构分层设计思想nerror="javascript:errorimg.call(this);">

osal/osal_freertos.c(适配 FreeRTOS)

#include "osal.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "semphr.h"int osal_thread_create(osal_thread_t *t, const char *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;}void osal_thread_delay_ms(uint32_t ms){    vTaskDelay(pdMS_TO_TICKS(ms));}void osal_start_scheduler(void){    vTaskStartScheduler();}int osal_mutex_create(osal_mutex_t *m){    *m = xSemaphoreCreateMutex();    return *m ? OSAL_OK : OSAL_ERR_FAIL;}int osal_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;}void osal_mutex_unlock(osal_mutex_t m){    xSemaphoreGive((SemaphoreHandle_t)m);}int osal_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;}int osal_queue_send(osal_queue_t q, const void *item, uint32_t timeout_ms){    return xQueueSend(q, item, pdMS_TO_TICKS(timeout_ms)) == pdTRUE ? OSAL_OK : OSAL_ERR_TIMEOUT;}int osal_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 细节。
打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心