2. Harmony 3工程结构与配置机制

Harmony 3 是 Microchip 为 32 位 PIC 与 SAM 系列 MCU 提供的统一软件开发框架。它把底层外设驱动、中间件协议栈、RTOS、图形库和文件系统等模块组织成可裁剪的组件集合,并通过 MHC(MPLAB Harmony Configurator)图形化工具完成工程配置与代码生成。理解 Harmony 3 的目录组织、MHC 配置生成流程、组件依赖关系和代码生成规则,是后续所有外设开发的基础。

一、工程目录组织

一个典型的 Harmony 3 工程由三大部分构成:项目工程目录、Harmony 框架源码目录和生成代码目录。以 MPLAB X IDE 下基于 PIC32MZ 的工程为例,目录结构大致如下:

MyProject/
├── MyProject.X/                # MPLAB X 工程目录
│   ├── nbproject/              # 工程配置(编译器、器件、路径)
│   ├── config/                 # MHC 生成代码
│   │   ├── default/
│   │   │   ├── configuration.h
│   │   │   ├── initialization.c
│   │   │   ├── interrupts.c
│   │   │   ├── pin_manager.c/.h
│   │   │   ├── clock.c/.h
│   │   │   ├── peripheral/     # 各外设初始化
│   │   │   └── system/         # 系统服务初始化
│   │   └── ...
│   ├── src/                    # 用户应用代码
│   │   ├── main.c
│   │   └── app.c
│   └── MyProject.mc3           # MHC 配置文件(核心)
├── harmony3/                   # Harmony 框架源码
│   ├── framework/
│   │   ├── driver/             # 外设驱动
│   │   ├── system/             # 系统服务
│   │   ├── middleware/         # 中间件
│   │   └── ...
│   └── ...
└── ...

其中 .mc3 文件是工程的“配置真相源”,它以 XML/JSON 形式记录所有组件选择、参数设置和引脚分配。MHC 每次打开工程时读取该文件,重新生成 config/ 下的代码。用户代码应放在 src/ 中,避免直接修改 config/ 下的生成文件,否则下次生成时会被覆盖。

二、MHC 配置生成流程

MHC 的工作流程可以概括为“选择组件 → 设置参数 → 分配引脚 → 生成代码”四个阶段。下图展示了从打开工程到生成代码的完整数据流:

MHC 图形界面 组件选择器 Device Resources / Available Components 配置选项面板 Clock / UART / Timer 参数 引脚管理器 Pin Diagram / Pin Settings 时钟配置器 Clock Diagram / 树形视图 依赖关系检查 自动解析组件依赖 Generate Code .mc3 配置文件 组件树 + 参数值 引脚映射表 时钟树配置 中断优先级 配置真相源 config/ 生成代码 configuration.h 全局宏定义与配置常量 clock.c / clock.h 系统时钟初始化函数 pin_manager.c / .h 引脚方向、复用、上下拉配置 peripheral/uart1.c 外设初始化与句柄定义 interrupts.c 中断向量与优先级设置 initialization.c SYS_Initialize() 统一入口 system/ 系统服务 控制台、调试、缓存初始化 保存 生成 用户代码位于 src/,通过 SYS_Initialize() 调用生成代码完成硬件初始化

流程的关键点在于:MHC 界面上的每一次修改都会写入 .mc3 文件,点击“Generate Code”后,MHC 根据 .mc3 中的组件树和参数,调用各组件自带的代码生成模板,输出到 config/default/ 目录。因此,.mc3 文件是工程可移植、可版本管理的核心,团队协作时应将其纳入 Git 等版本控制。

三、组件依赖关系

Harmony 3 的组件不是孤立的。选择一个组件时,MHC 会自动解析其依赖并提示需要同时启用的其他组件。例如:

  • 选择 UART Driver 时,会自动依赖 UART Peripheral Library 和 Pin Manager;
  • 选择 FreeRTOS 时,会依赖 System Service 中的 Time 和 Interrupt 服务;
  • 选择 TCP/IP Stack 时,会依赖 Network Interface(如 ETHMAC 或 GMAC 驱动)以及 Heap 内存管理。

依赖关系在 MHC 中以树形结构展示,根节点通常是“Harmony Core”,子节点是各功能模块。如果依赖未满足,MHC 会在组件旁显示黄色警告图标,并在生成代码时报错。因此,配置时应遵循“自底向上”的顺序:先配置时钟和引脚,再配置外设驱动,最后配置中间件和应用层。

四、代码生成规则

Harmony 3 的代码生成遵循几条重要规则,理解它们可以避免很多“改了没生效”的问题:

  1. 生成文件不手动修改:config/ 下的所有文件由 MHC 管理,手动修改会在下次生成时丢失。用户逻辑应写在 src/ 中,通过回调或应用层调用生成代码提供的 API。
  2. 初始化入口统一:生成的 initialization.c 中提供 SYS_Initialize() 函数,它按顺序调用时钟、引脚、外设和系统服务的初始化。用户 main() 中只需调用 SYS_Initialize(),然后进入自己的应用循环。
  3. 句柄与宏命名规范:每个外设实例会生成对应的句柄变量(如 UART1_Handle)和配置宏(如 UART1_BAUD_RATE),命名与 MHC 中的实例名一致,便于在应用代码中引用。
  4. 中断向量集中管理:interrupts.c 中根据配置生成中断服务程序框架,用户只需在对应回调中填充逻辑,不需要手动编写向量表。
实践建议:每次修改 MHC 配置后,先执行“Generate Code”,再编译工程。如果编译报错提示找不到某个头文件,通常是因为组件依赖未满足或路径未正确包含,可回到 MHC 检查组件树。

五、通过 MHC 配置时钟、引脚与基础外设

以 PIC32MZ EF 系列为例,配置一个 UART1 以 115200 波特率输出调试信息,典型操作如下:

时钟配置:在 MHC 的 Clock Diagram 中,选择系统时钟源(如 POSC 24 MHz),配置 PLL 倍频使 SYSCLK 达到 200 MHz,再设置 PBCLK1~PBCLK7 的分频值。UART1 通常挂在 PBCLK2 上,需确保其频率满足波特率计算要求。MHC 会实时显示各时钟节点的频率,若超出器件规格会标红提示。

引脚配置:在 Pin Diagram 中,找到 UART1 的 TX 和 RX 引脚(如 RPA14 和 RPA15),将其功能设置为 U1TX 和 U1RX。MHC 会自动检查引脚冲突,若同一引脚被多个外设占用,会提示错误。

外设配置:在 Available Components 中添加 UART Driver,选择实例 UART1,设置波特率 115200、数据位 8、停止位 1、无校验。生成代码后,config/default/peripheral/uart1.c 中会包含 UART1_Initialize(),并在 initialization.c 的 SYS_Initialize() 中被调用。

完成上述配置后,在 src/app.c 中即可通过 UART1_Write() 发送数据。整个过程中,用户不需要直接操作寄存器,所有底层细节由 Harmony 驱动和生成代码处理。

注意:MHC 生成的代码与所选器件型号、Harmony 版本强相关。更换器件或升级 Harmony 后,应重新打开 .mc3 文件并执行 Generate Code,确认所有组件仍能正确解析依赖。