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 界面上的每一次修改都会写入 .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 的代码生成遵循几条重要规则,理解它们可以避免很多“改了没生效”的问题:
- 生成文件不手动修改:
config/下的所有文件由 MHC 管理,手动修改会在下次生成时丢失。用户逻辑应写在src/中,通过回调或应用层调用生成代码提供的 API。 - 初始化入口统一:生成的
initialization.c中提供SYS_Initialize()函数,它按顺序调用时钟、引脚、外设和系统服务的初始化。用户main()中只需调用SYS_Initialize(),然后进入自己的应用循环。 - 句柄与宏命名规范:每个外设实例会生成对应的句柄变量(如
UART1_Handle)和配置宏(如UART1_BAUD_RATE),命名与 MHC 中的实例名一致,便于在应用代码中引用。 - 中断向量集中管理:
interrupts.c中根据配置生成中断服务程序框架,用户只需在对应回调中填充逻辑,不需要手动编写向量表。
五、通过 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 驱动和生成代码处理。