# MCU_Project_OOP **Repository Path**: Geek_Yang/mcu_project_oop ## Basic Information - **Project Name**: MCU_Project_OOP - **Description**: 本项目是一个基于STM32F103ZET6的面向对象四层架构嵌入式开发框架,采用C语言模拟面向对象设计,实现了 HAL层、Driver层、Service层、App层 的清晰分离,旨在提高代码的可维护性、可移植性和可复用性。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-28 - **Last Updated**: 2026-02-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 单片机面向对象四层架构框架 ## 项目简介 本项目是一个基于STM32F103ZET6的面向对象四层架构嵌入式开发框架,采用C语言模拟面向对象设计,实现了 **HAL层、Driver层、Service层、App层** 的清晰分离,旨在提高代码的可维护性、可移植性和可复用性。 ### 设计目标 - **面向对象设计**:采用不透明指针(Opaque Pointer)设计模式,实现完全封装 - **四层架构**:HAL → Driver → Service → App 严格分层 - **硬件无关抽象**:HAL层采用依赖注入,更换芯片只需新增实现文件 - **事件驱动**:事件总线实现发布-订阅模式,模块间松耦合 - **对象池管理**:静态内存分配,无需动态内存管理 - **体积小巧**:适合小资源MCU,无需RTOS ### 适用场景 - **情景A**:产品主控芯片需要更换 → 只需新增HAL层平台实现文件 - **情景B**:使用同款芯片开发新产品 → 只需修改App层业务逻辑 ## 架构设计 ``` ┌─────────────────────────────────────────────────────────────┐ │ Application Layer (应用层) │ │ 业务逻辑 | 状态机 | 算法模块 │ │ app_led.c | app_button.c │ └─────────────────────────────────────────────────────────────┘ ↓ 调用 ┌─────────────────────────────────────────────────────────────┐ │ Service Layer (服务层) │ │ 事件总线 | 任务调度 | 通信协议栈 │ │ event_bus.c | task_scheduler.c │ └─────────────────────────────────────────────────────────────┘ ↓ 调用 ┌─────────────────────────────────────────────────────────────┐ │ Driver Layer (驱动层) │ │ LED驱动 | 按键驱动 | 传感器驱动 │ │ drv_led.c | drv_button.c │ └─────────────────────────────────────────────────────────────┘ ↓ 调用 ┌─────────────────────────────────────────────────────────────┐ │ HAL Layer (硬件抽象层) │ │ GPIO抽象 | SysTick抽象 | Delay抽象 │ │ hal_gpio.c | hal_systick.c | hal_delay.c │ └─────────────────────────────────────────────────────────────┘ ↓ 调用 ┌─────────────────────────────────────────────────────────────┐ │ Hardware (硬件层) │ │ STM32F103ZET6 + STM32 SPL │ └─────────────────────────────────────────────────────────────┘ ``` ### 三大解耦维度 | 维度 | 方法 | 实现 | |------|------|------| | **纵向分层** | 分层架构设计 | HAL → Driver → Service → App | | **横向解耦** | 接口抽象 + 依赖注入 | 函数指针表、hal_xxx_register() | | **时序解耦** | 事件驱动架构 | event_bus 发布-订阅模式 | ## 目录结构 ``` MCU_OOP/ ├── App/ # 应用层 - 业务逻辑 │ ├── app_led.c/h # LED应用 │ └── app_button.c/h # 按键应用 │ ├── Service/ # 服务层 - 系统服务 │ ├── event_bus.c/h # 事件总线(发布-订阅) │ └── task_scheduler.c/h # 任务调度器 │ ├── Drivers/ # 驱动层 - 设备驱动 │ ├── drv_led.c/h # LED驱动(面向对象) │ └── drv_button.c/h # 按键驱动(面向对象) │ ├── HAL/ ├── hal_def.h (平台无关 - 通用定义) ├── hal_gpio.h (平台无关 - GPIO接口) ├── hal_delay.h (平台无关 - 延时接口) ├── hal_sysclock.h (平台无关 - 系统时钟接口) ├── hal_systick.h (平台无关 - SysTick接口) ├── hal_nvic.h (平台无关 - NVIC接口) │ └── platform/ ├── STM32/ (STM32F1 平台实现 - 已完成) │ ├── hal_gpio.c │ ├── hal_delay.c │ ├── hal_sysclock.c │ ├── hal_systick.c │ └── hal_nvic.c │ ├── APM32/ (APM32F1 平台实现 - 待开发) │ ├── hal_gpio.c (尚未实现) │ ├── hal_delay.c (尚未实现) │ ├── hal_sysclock.c (尚未实现) │ ├── hal_systick.c (尚未实现) │ └── hal_nvic.c (尚未实现) │ └── GD32/ (GD32F1 平台实现 - 待开发) ├── hal_gpio.c (尚未实现) ├── hal_delay.c (尚未实现) ├── hal_sysclock.c (尚未实现) ├── hal_systick.c (尚未实现) └── hal_nvic.c (尚未实现) │ ├── Common/ # 通用组件 │ └── Queue.c/h # 队列数据结构 │ ├── User/ # 用户代码 │ ├── main.c # 主程序入口 │ └── System.c/h # 系统初始化 │ ├── Libraries/ # STM32标准外设库 │ ├── CMSIS/ # ARM CMSIS │ └── STM32_SPL_Driver/ # STM32标准外设库 │ ├── MDK/ # Keil工程文件 │ └── Template.uvprojx # 工程文件 │ └── Docs/ # 文档 └── _Context.md # 项目上下文 ``` ## 快速开始 ### 1. 环境准备 - **硬件**:STM32F103ZET6开发板、ST-Link调试器 - **软件**:Keil MDK 5.x ### 2. 打开工程 ```bash # 打开Keil工程 MDK/Template.uvprojx ``` ### 3. 第一个示例:LED闪烁 ```c #include "stm32f10x.h" #include "hal_gpio.h" #include "hal_systick.h" #include "drv_led.h" #include "event_bus.h" #include "app_led.h" int main(void) { /* 1. HAL层初始化(依赖注入) */ hal_gpio_init(); // 初始化GPIO hal_systick_init(); // 初始化SysTick /* 2. Service层初始化 */ event_bus_init(); /* 3. App层初始化 */ app_led_init(); /* 4. 主循环 */ while (1) { event_bus_dispatch(); // 事件分发 } } ``` ### 4. 编译下载 1. 编译工程(F7) 2. 下载到开发板(F8) 3. 观察LED闪烁 ## 核心特性 ### 1. HAL层依赖 ```c // hal_gpio.h - 硬件无关接口(只包含stdint.h) int hal_gpio_init(const hal_gpio_config_t *config); int hal_gpio_deinit(hal_gpio_port_t port, hal_gpio_pin_t pin); void hal_gpio_write(hal_gpio_port_t port, hal_gpio_pin_t pin, hal_gpio_level_e level); hal_gpio_level_e hal_gpio_read(hal_gpio_port_t port, hal_gpio_pin_t pin); // hal_gpio_stm32f1.c - STM32F1平台实现 int hal_gpio_init(const hal_gpio_config_t *config) { if (config == NULL) { return -1; } if (config->port > HAL_GPIO_PORT_G) { return -1; } GPIO_TypeDef *port_reg = get_port_reg(config->port); if (port_reg == NULL) { return -1; } /* 使能GPIO时钟 */ RCC_APB2PeriphClockCmd(gpio_rcc_map[config->port], ENABLE); /* 配置GPIO */ GPIO_InitTypeDef gpio_init; gpio_init.GPIO_Pin = (uint16_t)config->pin; gpio_init.GPIO_Mode = convert_mode(config->mode); gpio_init.GPIO_Speed = convert_speed(config->speed); GPIO_Init(port_reg, &gpio_init); return 0; } ``` **设计特点:** - 接口层只包含标准头文件,与硬件完全无关 - 通过具体接口实现绑定具体平台 - 更换芯片只需新增 `platform/STM32/hal_xxx_.c` 文件 ### 2. 事件总线(发布-订阅模式) ```c // 订阅事件 event_bus_subscribe(EVENT_TYPE_BUTTON_PRESSED, button_handler, NULL); // 发布事件 event_t event = { .type = EVENT_TYPE_BUTTON_PRESSED, .data = btn_id }; event_bus_post(&event); // 主循环分发 while(1) { event_bus_dispatch(); } ``` **事件总线特性:** - 模块间松耦合,无直接依赖 - 支持多订阅者 - 异步事件队列 ### 3. 不透明指针封装模式 ```c // drv_led.h typedef struct drv_led drv_led_t; // 前置声明(隐藏实现) drv_led_t* drv_led_create(const drv_led_config_t *config); void drv_led_on(drv_led_t *led); void drv_led_off(drv_led_t *led); void drv_led_toggle(drv_led_t *led); ``` **设计特点:** - 结构体定义隐藏在.c文件中 - 对象池管理,静态内存分配 - 完全封装的API接口 ### 4. 四层架构设计 ``` App层(app_led.c) ← 业务逻辑 ↓ 调用 Service层(event_bus.c) ← 系统服务 ↓ 调用 Driver层(drv_led.c) ← 设备驱动 ↓ 调用 HAL层(hal_gpio.c) ← 硬件抽象 ↓ 调用 硬件(STM32 SPL) ``` **架构优势:** - HAL层实现硬件无关抽象,易于移植 - Driver层提供设备级封装 - Service层提供跨模块服务 - App层只关注业务逻辑 ## 开发指南 ### 添加新的HAL模块 1. 在 `HAL/` 目录创建 `hal_xxx.h` 定义纯接口(只包含stdint.h) 2. 在 `HAL/platform/STM32` 目录创建 `hal_xxx.c` 实现接口调度层 3. 在 `main.c` 中注册平台实现 ### 添加新的驱动 1. 在 `Drivers/` 目录创建 `drv_xxx.c/h` 2. 采用不透明指针模式设计 3. 只调用HAL层接口,不直接操作硬件 4. 使用对象池管理内存 ### 添加新的应用 1. 在 `App/` 目录创建 `app_xxx.c/h` 2. 通过事件总线与其他模块通信 3. 只调用Service层和Driver层接口 4. 禁止直接操作HAL层 ## 项目亮点 ### 1. 硬件无关抽象层 - HAL接口层只包含标准C头文件 - 通过依赖注入绑定平台实现 - 更换芯片无需修改上层代码 ### 2. 事件驱动架构 - 事件总线实现模块间松耦合 - 发布-订阅模式,支持多订阅者 - 异步事件队列,解耦时序依赖 ### 3. 不透明指针设计模式 - 完全隐藏结构体定义,实现真正的封装 - 头文件只提供前置声明和API接口 - 对象池管理,静态内存分配 ### 4. 四层分层架构 - HAL层:硬件无关抽象 - Driver层:设备级封装 - Service层:跨模块服务 - App层:业务逻辑 ## 性能指标 - **代码体积**:< 50KB(基础框架) - **RAM占用**:< 10KB(基础框架) - **SysTick精度**:1ms - **LED对象池**:8个对象 - **按键对象池**:8个对象 - **事件队列**:32个事件 ## 平台实现状态 | 平台 | 状态 | 文件位置 | GPIO | Delay | SysClock | SysTick | NVIC | |------|------|---------|------|-------|----------|---------|------| | **STM32F103ZET6** | ✅ 完全实现 | `HAL/platform/STM32/` | ✅ | ✅ | ✅ | ✅ | ✅ | | **APM32F103ZET6** | ⏳ 待实现 | `HAL/platform/APM32/` | ❌ | ❌ | ❌ | ❌ | ❌ | | **GD32F103ZET6** | ⏳ 待实现 | `HAL/platform/GD32/` | ❌ | ❌ | ❌ | ❌ | ❌ | ## 当前编译配置 **当前活跃平台**:STM32F103ZET6 **编译驱动文件**: - HAL/platform/STM32/hal_gpio.c - HAL/platform/STM32/hal_delay.c - HAL/platform/STM32/hal_sysclock.c - HAL/platform/STM32/hal_systick.c - HAL/platform/STM32/hal_nvic.c ## 切换编译平台 ### 在 Keil uVision 中操作 1. **打开工程** ``` File → Open Project → MDK/Template.uvprojx ``` 2. **禁用当前平台的实现文件** ``` Project → Manage Project Items → Source Group 1 ☐ 取消选中 HAL/platform/STM32/ 下的所有 .c 文件 ``` 3. **启用目标平台的实现文件** ``` Project → Manage Project Items → Source Group 1 ☑ 选中 HAL/platform/APM32/ 下的所有 .c 文件 ``` 4. **更新工程配置** - Project → Options for Target → Device - 改为:APM32F103ZE - Project → Options for Target → C/C++ - Include Paths 改为 APM32 库路径 - 预处理定义 改为 APM32 相关定义 5. **重新编译** ``` Project → Rebuild All (Ctrl+F7) ``` ## 添加新平台实现 ### 步骤 1:创建平台目录 ``` HAL/platform/YOUR_PLATFORM/ ``` ### 步骤 2:实现 5 个 HAL 接口 根据 `HAL/hal_*.h` 中的接口定义,在 `YOUR_PLATFORM/` 目录下创建对应的 `.c` 文件: | 接口文件 | 实现文件 | 必须实现的函数 | |---------|---------|----------------| | hal_gpio.h | hal_gpio.c | `hal_gpio_init()`, `hal_gpio_write()`, `hal_gpio_read()`, `hal_gpio_toggle()`, `hal_gpio_deinit()` | | hal_delay.h | hal_delay.c | `hal_delay_init()`, `hal_delay_us()`, `hal_delay_ms()` | | hal_sysclock.h | hal_sysclock.c | `hal_sysclock_init()`, `hal_sysclock_update()`, `hal_sysclock_get_freq()` | | hal_systick.h | hal_systick.c | `hal_systick_init()`, `hal_systick_deinit()`, `hal_systick_get_tick()`, `hal_systick_register_callback()` | | hal_nvic.h | hal_nvic.c | `hal_nvic_init()` | ### 步骤 3:包含正确的库头文件 在实现文件中包含目标 MCU 的库头文件,例如: **APM32 示例**: ```c #include "hal_gpio.h" #include "apm32f10x.h" // APM32 库头文件 // ... 实现代码 ``` **GD32 示例**: ```c #include "hal_gpio.h" #include "gd32f10x.h" // GD32 库头文件 // ... 实现代码 ``` ### 步骤 4:在 Keil 中添加文件 1. Project → Manage Project Items 2. 将新平台的 5 个 .c 文件添加到工程 3. 配置该平台的库路径和设备信息 4. 编译验证 ### 步骤 5:更新本文档 将 YOUR_PLATFORM 的状态改为 **✅ 完全实现** ## 应用代码兼容性 App 层、Driver 层、Service 层代码 **无需任何修改**,可以直接在不同平台间切换使用。 所有平台接口兼容,调用方式完全相同: ```c // 无论使用哪个平台,应用代码都保持不变 hal_gpio_config_t config = { .port = HAL_GPIO_PORT_A, .pin = HAL_GPIO_PIN_5, .mode = HAL_GPIO_MODE_OUTPUT_PP, .speed = HAL_GPIO_SPEED_MEDIUM }; hal_gpio_init(&config); hal_gpio_write(HAL_GPIO_PORT_A, HAL_GPIO_PIN_5, HAL_GPIO_LEVEL_HIGH); ``` ## 调试技巧 ### 验证当前平台 在应用代码中添加: ```c #define SYS_TARGET_MCU "STM32F103ZET6" // App/sys_config.h 中定义 #define SYS_CORE_CLOCK 72000000UL // 对应当前编译的平台 printf("Current MCU: %s\n", SYS_TARGET_MCU); printf("Core Clock: %lu Hz\n", SYS_CORE_CLOCK); ``` ### 检查编译文件列表 Project → Build → 查看 Output 窗口,确认编译了正确平台的文件 ## 常见问题 ### Q: 如何同时维护多个平台版本? A: 在 Keil 中创建多个 Target(例如 Target_STM32, Target_APM32, Target_GD32),每个 Target 配置不同的平台文件。 ### Q: 新平台实现时找不到某个库函数怎么办? A: 检查目标芯片是否支持该功能。如果不支持,考虑用替代方案或标记为"不可用"。 ### Q: 如何快速找到已实现的函数实现? A: 所有实现都在 `HAL/platform/PLATFORM_NAME/` 目录下,文件名和接口定义文件相同。 ## 快速参考 | 操作 | 文件位置 | |------|---------| | 查看 GPIO 接口定义 | `HAL/hal_gpio.h` | | 查看 STM32 GPIO 实现 | `HAL/platform/STM32/hal_gpio.c` | | 查看通用定义 | `HAL/hal_def.h` | | 修改 MCU 配置 | `App/sys_config.h` | ## 学习路径 1. **初级**:理解四层架构 → 完成LED示例 → 理解不透明指针模式 2. **中级**:学习事件总线 → 掌握依赖注入 → 添加新HAL/Driver模块 3. **高级**:设计复杂应用 → 跨平台移植 → 实现产品功能 ## 贡献指南 欢迎提交Issue和Pull Request! ### 贡献流程 1. Fork本仓库 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 提交Pull Request ### 代码规范 - 遵循现有的命名规范 - 添加必要的注释 - 更新相关文档 - 通过编译测试 ## 更新日志 ### v2.0.0 (2026-01-14) - 重构为四层架构(HAL/Driver/Service/App) - 实现HAL层GPIO/SysTick/Delay硬件无关抽象 - 采用依赖注入设计模式 - 新增事件总线(发布-订阅模式) - 新增任务调度器 - 重构LED/按键驱动为面向对象设计 ### v1.0.0 (2025-12-31) - 初始版本发布 - 完成三层架构设计 - 采用不透明指针设计模式 - 实现对象池内存管理 ## 许可证 本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件 ## 作者 **Jay.Yang** - 邮箱:695834706@qq.com - GitHub:[项目地址] ## 致谢 - STMicroelectronics - STM32标准外设库 - ARM - CMSIS核心文件 - 所有贡献者和使用者 ## 技术支持 - 邮箱:695834706@qq.com - 文档:[Docs目录](Docs/) - 问题反馈:[GitHub Issues] --- 如果这个项目对你有帮助,请给个Star支持一下! 相关链接: - [STM32官网](https://www.st.com/zh/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html) - [Keil官网](https://www.keil.com/) - [ARM CMSIS](https://developer.arm.com/tools-and-software/embedded/cmsis)