电力电子代码(一):架构解析,从功能需求到三层架构设计

本文仅包括代码架构文件树设计和功能需求分析,不包括具体的如芯片选型、各功能实现等。本文仅属于电力电子代码系列文章的一小章,后面会详细讲如芯片选择、底层配置、命名风格推荐、各种功能细节…

电力电子代码特点

  1. 代码简洁:项目代码量少,易于阅读和复用,逻辑清晰。例如,最近本人在做的项目总代码量(含测试不含库)为5685行,实际功能代码仅约3000行(可用 cloc 工具统计)。
  2. 团队小:通常只有1到2人参与开发。
  3. 资源有限:项目可用的计算资源和存储空间较少。
  4. 实时性要求高:系统需要严格按照设定的频率运行,确保及时响应。
  5. 多重保护机制:系统设计了多级保护措施,确保安全运行。
  6. 用户通讯实时性要求低:与用户的交互不需要高实时性,允许一定的延迟。

电力电子代码需要实现哪些功能?

  1. 底层:初始化、运行时变模态、启动与关闭等功能。Timer、PWM、ADC、DAC(DAC是必要的,尤其是在调控制环路时)、GPIO、CMP、CAN、UART…等。(这里的CAN等通讯主要指可以正常收发,收发的数据代表的逻辑设定由通讯部分完成)
  2. 调度:根据数控原理,对非变频电力电子变换器来说,开关频率是控制频率的整数倍,一般尽量为一倍,并令控制器带宽为控制频率的1/5~1/10。因此,关键控制代码必然运行某定时器的中断中。低实时性功能(主要指通讯)可以放在 main() 的主循环中,也可使用 FreeRTOS 等操作系统进行管理,但本人更推荐放在 main() 的主循环中,因为功能较少,没必要使用操作系统进行调度管理。总之,使用 TimerX_ISR()while 进行功能逻辑调度。
  3. 控制:如PID、PR、MPPT、DQ变换、PLL…等各种控制算法和其组合使用。
  4. 状态机:主要分为两类,一类是状态机逻辑,一类是状态逻辑。状态机逻辑包括状态机的状态机初始化逻辑和状态之间的切换逻辑;状态逻辑包括空闲、运行、错误、调试、更新、配置等状态的初始化、进入、退出、执行函数。
  5. 保护:此处只是简要的说明一下,会在介绍保护的章节专门介绍保护逻辑。
    电力电子系统的保护通常需要多级设计,以确保在不同时间尺度上应对各种故障。根据响应速度的不同,保护机制可以分为最快响应、次快响应和较慢响应三类。最快响应的保护通常通过硬件实现,如使用比较器(COMP)和数模转换器(DAC)进行比较,或通过外部电路结合PWM模块的FAULT功能,直接硬件关断PWM输出,实现微秒级的快速保护。随后触发中断,处理相关业务逻辑,如记录故障信息和切换状态。这种保护适用于过流、短路等需要极快响应的故障。
    次快响应的保护在每个控制周期内通过ADC采集关键参数(如电压、电流),并与保护阈值进行比较。如果超出阈值,则触发保护动作。这种保护适用于欠压、过压等需要较快响应的故障。较慢响应的保护则在主循环中周期性检查系统状态(如温度、功率),如果检测到异常,则执行相应的保护动作。这种保护适用于过温、通信异常等允许稍慢响应的故障。
    在实现保护机制时,最快响应的保护需要在系统初始化阶段配置相关硬件,如PWM FAULT功能和比较器。触发保护时,通过中断设置对应的fault_flag,以便后续处理。最慢响应的保护则在主循环中检测到故障后,修改对应的fault_flag,以便统一处理。保护逻辑可以分为保护总体逻辑和各保护逻辑两类。保护总体逻辑负责判断是否触发保护、处理触发的保护、记录保护历史和配置保护参数。各保护逻辑则定义具体的保护行为,包括保护类型和相关函数。
    保护总体逻辑的功能包括判断是否触发保护、处理触发的保护、记录保护历史和配置保护参数。各保护逻辑的功能则包括保护类型设定和相关函数。保护类型设定可以包括立即停止驱动、停止后延时重启、停止后条件重启和其他自定义动作。相关函数包括check函数、recover函数和user defined action函数,分别用于检测是否满足保护触发条件、定义重启或恢复逻辑以及实现用户自定义的保护动作。
  6. 通讯:与DMA配合,设计编码和对应功能。
  7. 测试:含单元测试、模块测试、整体测试,分别在电脑用gcc或板上完成各项测试。

电力电子代码的三层架构

传统嵌入式代码的四层架构

一般来说,电力电子代码和一般的嵌入式代码一样,往往分为三层, app bsp hal 三层,分别是应用层、中间层、硬件层。

嵌入式论坛有这样一段话:https://www.embeddedrelated.com/thread/17476/concepts-around-hal-bsp-os-composition

In summary:

  • OS: can be used by any module, it may need HAL functions
  • BSP: uses HAL and OS
  • HAL: uses OS and vendor files
  • Application : this is your business logic, and should not call HAL functions anymore, but rather use the BSP layer (and OS of course).

分层架构核心要点

  1. 层次划分
    • Application Layer:业务逻辑,调用BSP和OS。
    • BSP Layer:硬件抽象,调用HAL和OS。
    • HAL Layer:硬件驱动,调用OS和供应商库。
    • OS Layer:系统服务,被所有层调用。
  2. 依赖关系
    • Application → BSP + OS
    • BSP → HAL + OS
    • HAL → OS + Vendor Libs
    • OS → 无依赖
  3. 设计原则
    • Top-Bottom:基于应用需求设计API,避免过度实
    • 解耦:分离业务逻辑与底层实现,提升可维护性和可移植性。
  4. 优点
    • 可维护性:层次清晰,修改底层不影响上层。
    • 可移植性:更换硬件或OS只需修改底层。
    • 简化开发:按需实现,避免冗余。
  5. 适用场景
    • 嵌入式系统,多硬件平台支持。
    • 长期维护和扩展的项目。

示例:UART驱动

  • HAL:实现uart_send_bytes,使用OS消息队列。
  • BSP:提供debug_print,调用HAL发送数据。
  • Application:调用debug_print,不直接操作硬件。

电力电子代码的三层架构(没有OS)

电力电子代码常写在如 STM32C2000 相关MCU或DSP上,往往官方的 HAL库或 device 库基本完成了大部分底层有关内容,且 CubeMxsysconfig 完成了大部分 setup 等初始化代码。(这里必须指出的是,本人强烈推荐把 sysconfig 生成的代码单独复制并保存在其它位置,因为 sysconfig 不支持生成多对文件,且不利于自己加修改。这也是TI官方论坛建议的使用方式)

  • App Layer:业务逻辑,调用BSP。
  • BSP Layer:硬件抽象,调用HAL。
  • HAL Layer:硬件驱动,调用供应商库。
src
│
├─ main.c
│  
├─app
│  ├─ project_app.c
│  ├─ project_app.h
│  ├─ project_app_global.c
│  ├─ project_app_global.h
│  │  
│  ├─control
│  │  │  project_control.c
│  │  │  project_control.h
│  │  │
│  │  └─pid
│  │          pid.c
│  │          pid.h
│  │
│  ├─fsm
│  │  │  fsm_core.c
│  │  │  fsm_core.h
│  │  │
│  │  └─stateSuite
│  │          fsm_state_config.c
│  │          fsm_state_debug.c
│  │          fsm_state_fault.c
│  │          fsm_state_idle.c
│  │          fsm_state_run.c
│  │          fsm_state_upgrade.c
│  │          fsm_transition.c
│  │          state_suite.c
│  │          state_suite.h
│  │          state_suite_api.h
│  │
│  └─safety
│      │  ReadMe.md
│      │  safety_core.c
│      │  safety_core.h
│      │
│      ├─configManager
│      │      safety_config_manager.c
│      │      safety_config_manager.h
│      │
│      ├─logManager
│      │      safety_log_manager.c
│      │      safety_log_manager.h
│      │
│      └─safetySuite
│              safety_suite.c
│              safety_suite.h
│              safety_suite_none.c
│              safety_suite_none.h
│
├─bsp
│  │  project_bsp.c
│  └─ project_bsp.h
│
└─hal
        project_hal.c
        project_hal.h
        project_hal_adc.c
        project_hal_asysctl.c
        project_hal_board.h
        project_hal_can.c
        project_hal_dac.c
        project_hal_dma.c
        project_hal_epwm.c
        project_hal_epwm.h
        project_hal_gpio.c
        project_hal_i2c.c
        project_hal_interrupt.c
        project_hal_sci.c
        project_hal_sync.c
        project_hal_timer.c

如上文件树所示,hal层包括所有底层内容,bsp层包括对hal的调用封装,app层包括定时器中断函数、全局变量、控制、状态机、保护逻辑,main.c包括程序入口main()。

由于电力电子领域的供应商(如ST、TI)已经对HAL层进行了高度封装,且关键外设(如PWM)的差异较大,BSP层实际上很难与HAL层完全分离。因此,通常会将硬件初始化、外设配置、硬件事件处理等函数放在 src/hal中,而不直接使用供应商提供的库。这也导致在电力电子代码中,BSP层的原始定义(Board Support Package)常常被忽视,转而将其视为一个中间层。在这种架构下,BSP层通常包含大量应用代码,而App层则仅保留定时器中断等核心逻辑。这也是我个人习惯的实现方式。

在这种习惯下,文件树为:

src
│  ReadMe.md                # 项目总说明文档
│  main.c                   # 程序入口,初始化系统并启动主循环
│
├─app                       # 应用层,存放业务逻辑代码
│      project_app.c        # 应用层主逻辑实现
│      project_app.h        # 应用层头文件,定义接口和数据结构
│
├─bsp                       # 中间层
│  │  project_bsp.c         # BSP层核心实现
│  │  project_bsp.h         # BSP层头文件
│  │  project_bsp_global.c  # BSP层全局变量
│  │  project_bsp_global.h  # BSP层全局变量
│  │
│  ├─control                # 控制算法相关代码
│  │  │  project_control.c  # 控制逻辑实现
│  │  │  project_control.h  # 控制逻辑头文件
│  │  │
│  │  └─pid                # PID控制算法实现
│  │          pid.c         # PID算法核心实现
│  │          pid.h         # PID算法头文件
│  │          ReadMe.md     # PID算法说明文档
│  │
│  ├─fsm                    # 有限状态机(FSM)相关代码
│  │  │  fsm_core.c         # 状态机核心逻辑实现
│  │  │  fsm_core.h         # 状态机核心逻辑头文件
│  │  │  ReadMe.md          # 状态机说明文档
│  │  │
│  │  └─stateSuite         # 状态机具体状态实现
│  │          fsm_state_config.c   # 配置状态实现
│  │          fsm_state_debug.c    # 调试状态实现
│  │          fsm_state_fault.c    # 故障状态实现
│  │          fsm_state_idle.c     # 空闲状态实现
│  │          fsm_state_run.c      # 运行状态实现
│  │          fsm_state_upgrade.c  # 升级状态实现
│  │          fsm_transition.c     # 状态转换逻辑实现
│  │          state_suite.c        # 状态机套件核心实现
│  │          state_suite.h        # 状态机套件头文件
│  │          state_suite_api.h    # 状态机套件对外接口
│  │
│  └─safety                # 安全相关代码
│      │  ReadMe.md        # 安全模块说明文档
│      │  safety_core.c    # 安全核心逻辑实现
│      │  safety_core.h    # 安全核心逻辑头文件
│      │
│      ├─configManager     # 安全配置管理
│      │      safety_config_manager.c  # 安全配置管理实现
│      │      safety_config_manager.h  # 安全配置管理头文件
│      │
│      ├─logManager        # 安全日志管理
│      │      safety_log_manager.c     # 安全日志管理实现
│      │      safety_log_manager.h     # 安全日志管理头文件
│      │
│      └─safetySuite      # 安全套件
│              safety_suite.c         # 安全套件核心实现
│              safety_suite.h         # 安全套件头文件
│              safety_suite_none.c    # 空安全套件实现(占位)
│              safety_suite_none.h    # 空安全套件头文件
│
└─hal                      # 硬件抽象层,与硬件直接交互的代码
        project_hal.c      # HAL层核心实现
        project_hal.h      # HAL层头文件
        project_hal_adc.c  # ADC外设驱动实现
        project_hal_asysctl.c  # 系统控制外设驱动实现
        project_hal_board.h    # 硬件板级配置头文件
        project_hal_can.c  # CAN外设驱动实现
        project_hal_dac.c  # DAC外设驱动实现
        project_hal_dma.c  # DMA外设驱动实现
        project_hal_epwm.c # EPWM外设驱动实现
        project_hal_epwm.h # EPWM外设驱动头文件
        project_hal_gpio.c # GPIO外设驱动实现
        project_hal_i2c.c  # I2C外设驱动实现
        project_hal_interrupt.c  # 中断处理实现
        project_hal_sci.c  # SCI外设驱动实现
        project_hal_sync.c # 同步外设驱动实现
        project_hal_timer.c  # 定时器外设驱动实现
        ReadMe.md          # HAL层说明文档

Eva2026年6月硕士毕业,正在找工作^^有兴趣招我的可以通过评论与我联系^^

发表回复