Funpack5-2 - 使用Microchip PIC32的TCC外设控制RGB灯
该项目使用了Microchip PIC32,实现了TCC外设输出PWM控制RGB灯的设计,它的主要功能为:控制外部RGB灯显示固定颜色。
标签
Funpack活动
PWM
Microchip
PIC32
rgb灯
TCC
枫雪天
更新2026-06-17
5

任务介绍

本项目实现了 Funpack 活动 EV41C56A 板卡的自命题任务,基于 Microchip PIC32CM LS00 开发板,利用片上 TCC(Timer/Counter for Control)外设输出三路独立 PWM 信号,驱动外部 RGB 三色灯循环展示红、绿、蓝、紫、白五种颜色,并通过串口实时回显当前颜色状态,充分展示了 X-Macro 元编程技巧在嵌入式 C 开发中的工程实践价值。

硬件平台

本次使用 Microchip 推出的 EV41C56A 开发板,搭载 PIC32CM5164LS00048 微控制器,该芯片基于 ARM Cortex-M23 内核,内置 TrustZone 安全隔离机制,具备丰富的片上外设资源,包括多路 SERCOM 接口、TCC 定时器、ADC 等模块,非常适合面向 IoT 与低功耗嵌入式场景的开发。开发板集成了 PKOB nano 调试器,支持 SWD 在线烧录与调试,便于快速搭建原型系统。

在软件方面,本项目采用 MPLAB Harmony v3 框架作为底层驱动支撑,通过 MCC(MPLAB Code Configurator)图形化配置工具完成外设初始化代码的自动生成,并结合 XC32 编译器完成工程构建与烧录。

主控设备:Microchip EV41C56A 开发板

  • 搭载 PIC32CM5164LS00048(ARM Cortex-M23)
  • 集成 PKOB nano 调试器,支持 SWD 接口(2.000 MHz)
  • 支持 Arm TrustZone for Armv8-M 安全分区
  • 内置 XC32 v5.00 编译工具链支持

外部执行器

  • RGB 三色 LED 灯(共阳极/共阴极均可适配)
  • 通过 PA08 / PA09 / PA10 三路 GPIO 连接至 TCC0 的 WO0 / WO1 / WO2 输出

任务分析与实现

本系统实现了基于 TCC0 外设三路 PWM 输出的 RGB 彩灯循环控制,主要功能包括:

三通道 PWM 输出:

  • R 通道(TCC0_CHANNEL0)
    • 对应引脚:PA08 / TCC0_WO0
    • 占空比范围:0% ~ 100%
  • G 通道(TCC0_CHANNEL1)
    • 对应引脚:PA09 / TCC0_WO1
    • 占空比范围:0% ~ 100%
  • B 通道(TCC0_CHANNEL2)
    • 对应引脚:PA10 / TCC0_WO2
    • 占空比范围:0% ~ 100%

颜色循环控制:

  • 依次呈现 RED → GREEN → BLUE → PURPLE → WHITE 五色
  • 每色驻留时间:3000 ms(由 SYSTICK_DelayMs 实现)
  • 串口实时原地刷新显示当前颜色名称

方案框图:

TCC 外设配置过程

本项目基于 Microchip EV41C56A 开发板,借助 MPLAB Harmony v3 MCC 完成了 TCC0 外设的 PWM 模式配置,并适配了 TrustZone 安全分区,最终实现三通道 PWM 驱动 RGB 灯的完整功能。以下详细描述了配置的关键流程和核心要点。

一、配置前的准备

1. 硬件环境

  • 主控芯片:Microchip PIC32CM5164LS00048(ARM Cortex-M23 内核)
  • 开发板:EV41C56A
  • 外设资源
    • TCC0 用于输出三路独立 PWM 信号驱动 RGB LED
    • SERCOM3 用于 UART 串口调试输出
    • SYSTICK 定时器用于延时控制

2. 软件环境

  • IDE:MPLAB X IDE
  • 代码生成工具:MPLAB Harmony v3 MCC(Melody)
  • 编译工具链:XC32 v5.00
  • 底层支持库:Harmony v3 提供 HAL 及 PLIB 驱动支持


二、配置的核心步骤

1. Project Graph 外设添加

在 MCC 的 Project Graph 界面中,添加所需的外设库组件。本项目核心外设包括:

  • TCC0(Peripheral Library):提供 TMR 与 PWM 双功能节点,是驱动 RGB 灯的核心模块
  • SERCOM3(Peripheral Library):配置为 UART 模式,连接至 STDIO 组件,实现串口输出
  • NVMCTRL / PM / EVSYS:作为系统支撑外设自动加入

如图所示,TCC0 组件已被选中(蓝色高亮边框):

2. TCC0 PWM 参数配置

双击 TCC0 组件进入详细配置界面,按照 RGB 灯驱动需求完成以下关键参数设置:

  • Operating Mode:选择 PWM
  • Select PWM Type:选择 DSTOP(双斜坡单触发模式)
  • Period Value:设置为 240,对应 PWM 频率 100000 Hz(100 kHz)
  • Channel Configurations:启用 Channel 0 / Channel 1 / Channel 2,初始 Duty Value 均设为 0
  • Output Polarity:每通道设置为 Output is DIR when counter matches CCx value
  • Invert Output 0 / 1 / 2:均保持不勾选,确保输出极性与 LED 硬件匹配

如图所示,绿色高亮项目为本次配置的关键参数:

3. TrustZone 外设安全属性配置

由于 PIC32CM LS00 集成了 Arm TrustZone for Armv8-M,所有外设在使用前须在 MCC 的 Arm TrustZone 配置界面中明确其安全属性。

本项目将 TCC0 及 SERCOM3 设置为 Non-Secure(橙色),以便在 Non-Secure 应用代码中直接访问:

  • TCC0 → Non-Secure(橙色)
  • SERCOM3 → Non-Secure(橙色)
  • 其余外设保持 Secure 默认状态(绿色)

如图所示,TCC0 与 SERCOM3 均以橙色标注,表示已配置为 Non-Secure 区域:

4. 引脚映射配置(Pin Configuration)

在 MCC 的 Pin Configuration Table View 中,将 TCC0 的三路 PWM 输出映射至对应 GPIO 引脚:

引脚编号

Pin ID

功能

安全属性

13

PA08

TCC0_WO0

NON-SECURE

14

PA09

TCC0_WO1

NON-SECURE

15

PA10

TCC0_WO2

NON-SECURE

7

PB08

SERCOM3_PAD0

NON-SECURE

三路 PWM 输出引脚(PA08 / PA09 / PA10)均设置为 NON-SECURE,与 TrustZone 分区保持一致,如下图红框标注所示:


代码详解

整体软件流程


一、X-Macro 颜色数据表设计

本项目的核心亮点在于采用 X-Macro 元编程技巧,将颜色数据集中定义在一张"大表"中,通过宏展开自动生成枚举、switch-case 分支及主循环体,彻底消除重复代码,保证颜色新增或修改时只需改动一处。

#define FOREACH_COLOR(X)            \
X(RED, 100, 0, 0, "RED") \
X(GREEN, 0, 100, 0, "GREEN") \
X(BLUE, 0, 0, 100, "BLUE") \
X(PURPLE, 60, 0, 60, "PURPLE") \
X(WHITE, 100, 100, 100, "WHITE")

展开用途一:自动生成颜色枚举

#define GENERATE_ENUM(enum_name, r, g, b, str) COLOR_##enum_name,
typedef enum {
FOREACH_COLOR(GENERATE_ENUM)
COLOR_MAX
} RGB_Color_T;
// 展开结果:COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_PURPLE, COLOR_WHITE, COLOR_MAX

展开用途二:switch-case 自动生成

#define GENERATE_CASE(enum_name, r, g, b, str) \
case COLOR_##enum_name: RGB_Set_Duty(r, g, b); break;

void Set_Static_Color(RGB_Color_T color) {
switch (color) {
FOREACH_COLOR(GENERATE_CASE)
default: RGB_Set_Duty(0, 0, 0); break;
}
}


二、PWM 占空比计算与设置

RGB_Set_Duty 函数负责将百分比形式的 RGB 亮度值转换为 TCC0 比较寄存器的实际计数值,并写入三个通道:

void RGB_Set_Duty(uint8_t r_pct, uint8_t g_pct, uint8_t b_pct) {
uint32_t period = TCC0_PWM24bitPeriodGet(); // 读取当前周期值(=240)

uint32_t r_cc = (r_pct * period) / 100; // 红色通道比较值
uint32_t g_cc = (g_pct * period) / 100; // 绿色通道比较值
uint32_t b_cc = (b_pct * period) / 100; // 蓝色通道比较值

TCC0_PWM24bitDutySet(TCC0_CHANNEL0, r_cc); // 写入 R 通道
TCC0_PWM24bitDutySet(TCC0_CHANNEL1, g_cc); // 写入 G 通道
TCC0_PWM24bitDutySet(TCC0_CHANNEL2, b_cc); // 写入 B 通道
}

以 Period Value = 240、PWM 频率 100 kHz 为基准,各颜色对应的占空比与比较值如下:

颜色

R(%)

G(%)

B(%)

R_CC

G_CC

B_CC

RED

100

0

0

240

0

0

GREEN

0

100

0

0

240

0

BLUE

0

0

100

0

0

240

PURPLE

60

0

60

144

0

144

WHITE

100

100

100

240

240

240


三、串口原地刷新显示

为避免串口输出逐行滚动,代码采用退格符(\b)覆盖上一行内容,实现原地刷新效果:

#define GENERATE_LOOP(enum_name, r, g, b, str)       \
Set_Static_Color(COLOR_##enum_name); \
for (int i = 0; i < last_len; i++) { \
printf("\b \b"); /* 逐字符退格清除 */ \
} \
printf("Current Color: %s", str); \
fflush(stdout); \
last_len = strlen("Current Color: ") + strlen(str); \
SYSTICK_DelayMs(3000);

last_len 是静态全局变量,记录上一次输出字符串的总长度,保证下一次能精准退格覆盖,不产生残留字符。


四、主函数

int main(void) {
SYS_Initialize(NULL); // Harmony v3 统一初始化入口
SYSTICK_TimerStart(); // 启动 SysTick
TCC0_PWMStart(); // 启动 PWM 输出

printf("\r\n");
printf("================================\r\n");
printf(" PIC32CM LS00 Task2\r\n");
printf("================================\r\n\r\n");

while (true) {
FOREACH_COLOR(GENERATE_LOOP) // X-Macro 自动展开五色循环
SYS_Tasks();
}
return (EXIT_FAILURE);
}

效果展示

程序运行后,RGB 灯依次点亮红、绿、蓝、紫、白五种颜色,每色持续 3 秒后自动切换;串口终端同步显示当前颜色名称,并在同一行原地刷新,无滚动干扰。

红色

绿色

蓝色

如图所示,串口终端(COM20,115200 波特率)显示当前颜色为 GREEN,输出格式为 Current Color: 当前颜色

遇到的难题与解决办法

问题一:TCC0 PWM 输出无信号,RGB 灯不亮

解法:检查 TrustZone 配置后发现 TCC0 默认属于 Secure 区域,而应用代码运行在 Non-Secure 区域,导致外设访问被拦截。在 MCC 的 Arm TrustZone Peripheral Configuration 界面中将 TCC0 切换为 Non-Secure,同时将对应 GPIO 引脚(PA08 / PA09 / PA10)的 Security Mode 也设为 NON-SECURE,问题解决。

问题二:串口输出乱码或无输出

解法:SERCOM3 同样需要设置为 Non-Secure 并在 Pin Configuration 中正确映射 PAD0(PB08),确保 STDIO 组件能正常调用 UART 发送接口。同时确认波特率配置与上位机终端(115200)一致。

问题三:PWM 占空比调节无效,颜色无变化

解法:排查发现 TCC0_PWM24bitDutySet 需在 PWM 已启动(TCC0_PWMStart() 调用之后)才能生效;另需确认 Period Value 与实际系统时钟匹配,避免因分频配置错误导致计算出的 CC 值溢出或为零。

活动感想

通过本项目实践,深入掌握了 Microchip MPLAB Harmony v3 框架下 TCC 外设的 PWM 配置方法,以及 Arm TrustZone 安全分区机制在实际工程中的配置要点。EV41C56A 开发板集成的 PKOB nano 调试器极大简化了烧录与调试流程,MCC 图形化配置工具使外设初始化代码的生成变得直观高效。

在代码设计层面,X-Macro 元编程技巧的引入让颜色表的维护成本降至最低——新增一种颜色只需在 FOREACH_COLOR 宏中追加一行,枚举、switch-case 及主循环均自动同步更新,体现了嵌入式 C 开发中"数据驱动代码生成"的工程哲学。整个项目过程中,深刻体会到硬件安全配置、外设时钟正确性与应用层逻辑三者缺一不可,每个环节的细致配置都直接决定了最终功能能否正常运行。

感谢硬禾学堂和得捷电子联合举办的 Funpack 活动,祝硬禾的活动越办越好!

附件下载
funpack_task_2.rar
工程源码
团队介绍
个人
团队成员
枫雪天
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号