硬件介绍
资料
MAX32655FTHR是美国亚德诺半导体公司(ADI)推出的一款高性能、超低功耗微控制器开发板。它以其极致的能效比和强大的无线连接能力为核心特色,专为下一代电池供电的物联网(IoT)和可穿戴设备而设计。并非通用型入门开发板,而是一款高度集成、目标明确的专业评估平台。其核心使命是解决物联网边缘设备在高性能计算、持续无线连接与超长电池续航之间的核心矛盾。它主要面向需要复杂数据处理(如生物信号分析、音频处理)并保持数月甚至数年续航的先进应用。
本站地址:https://www.eetree.cn/project/detail/4230
主控芯片(MAX32655):一颗主频高达96MHz的ARM Cortex-M4F内核(支持浮点运算单元),用于运行主应用程序和复杂算法;同时集成一颗低功耗RISC-V协处理器,专门处理蓝牙协议栈和传感器轮询等任务
无线连接:集成蓝牙5.2 低功耗(BLE)射频前端,支持长距离、高数据传输率模式,为设备提供稳定、高效的无线连接。
介绍
本次活动使用使用按钮实现不同led等效的切换。
目前设计的led灯效有蓝灯呼吸,红灯呼吸,绿灯呼吸,rgb乱闪。
开发环境搭建
msdk地址地址:离线地址
使用命令行,MaximMicrosSDK_2024_10.run,安装max36552支持。

安装完毕后,在安装sdk路径下,执行一下环境创建脚本:setenv.sh,如下图

通过ssh连接的情况下,最后把updatesh脚本改个名字,不然ssh会断开。
简单测试一个流程:helloworld。

make 编译成功后,使用make flash.openocd烧录程序到板卡里。
执行minicom -c on -D /dev/ttyACM0,打开串口,显示如下

项目框图
led引脚接线如下

查看手册,分析引脚的功能如下,下面看一下pt和基于定时器的呼吸灯实现方法。

流程图如下

开发代码
如下,使用claude 自动生成一份基于pt外设的呼吸灯代码。

生成的代码如下
/**
* @file main.c
* @brief MAX32655 Pulse Train 呼吸灯示例
* @details 使用PT模块产生PWM信号,实现LED呼吸灯效果
*/
#include <stdio.h>
#include <stdint.h>
#include "mxc_device.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "pt.h"
#include "gpio.h"
#include "board.h"
/*******************************************************************************
* 宏定义
******************************************************************************/
#define PT_CHANNEL 0 // 使用PT通道0
#define PT_FREQ 1000 // PWM频率: 1kHz
#define PT_RATE_HZ 1000000 // PT时钟频率: 1MHz
#define BREATH_STEPS 100 // 呼吸步数
#define BREATH_DELAY_MS 15 // 每步延时(ms)
/*******************************************************************************
* 全局变量
******************************************************************************/
static uint32_t pt_rate; // 实际PT时钟频率
/*******************************************************************************
* 函数声明
******************************************************************************/
static int PT_PWM_Init(void);
static void PT_SetDutyCycle(uint8_t duty_percent);
static void Breath_LED(void);
static void Breath_LED_Smooth(void);
/*******************************************************************************
* 函数实现
******************************************************************************/
/**
* @brief 初始化Pulse Train为PWM模式
* @return 0:成功, 其他:失败
*/
static int PT_PWM_Init(void)
{
int ret;
mxc_pt_cfg_t pt_cfg;
// 初始化PT模块,设置时钟频率
MXC_PT_Init(PT_RATE_HZ);
// 获取实际的PT时钟频率
// pt_rate = MXC_PT_GetRateHz();
// printf("PT时钟频率: %u Hz\n", pt_rate);
// 配置PT通道
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ; // 位速率 = PWM频率
pt_cfg.ptLength = 2; // 2位模式 (用于PWM)
pt_cfg.pattern = 0x01; // 初始模式: 50%占空比 (01)
pt_cfg.loop = 0; // 连续循环
pt_cfg.loopDelay = 0; // 无延迟
ret = MXC_PT_Config(&pt_cfg);
if (ret != E_NO_ERROR) {
printf("PT配置失败: %d\n", ret);
return ret;
}
// 启动PT通道
MXC_PT_Start(1 << PT_CHANNEL);
printf("Pulse Train 初始化成功\n");
printf("PWM频率: %d Hz\n", PT_FREQ);
return E_NO_ERROR;
}
/**
* @brief 使用32位模式设置更精确的占空比
* @param duty_percent: 占空比(0-100)
*/
static void PT_SetDutyCycle(uint8_t duty_percent)
{
uint32_t pattern;
uint32_t high_bits;
// 限制范围
if (duty_percent > 100) {
duty_percent = 100;
}
// 停止当前PT
MXC_PT_Stop(1 << PT_CHANNEL);
// 使用32位模式,计算高电平位数
// 32位中有多少位为1决定占空比
high_bits = (32 * duty_percent) / 100;
if (high_bits == 0) {
pattern = 0x00000000; // 0%
} else if (high_bits >= 32) {
pattern = 0xFFFFFFFF; // 100%
} else {
// 生成pattern: 高位为1,低位为0
pattern = (1UL << high_bits) - 1;
}
// 重新配置PT
mxc_pt_cfg_t pt_cfg;
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ * 32; // 32位 * PWM频率
pt_cfg.ptLength = 32; // 32位模式
pt_cfg.pattern = pattern;
pt_cfg.loop = 0;
pt_cfg.loopDelay = 0;
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << PT_CHANNEL);
}
/**
* @brief 简化版占空比设置 (使用8位模式)
* @param duty: 占空比值(0-255映射到0-100%)
*/
static void PT_SetDutyCycle_8bit(uint8_t duty)
{
uint8_t pattern;
uint8_t high_bits;
MXC_PT_Stop(1 << PT_CHANNEL);
// 8位模式下计算高电平位数
high_bits = duty / 32; // 0-7位
if (high_bits == 0) {
pattern = 0x00;
} else if (high_bits >= 8) {
pattern = 0xFF;
} else {
pattern = (1 << high_bits) - 1;
}
mxc_pt_cfg_t pt_cfg;
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ * 8;
pt_cfg.ptLength = 8;
pt_cfg.pattern = pattern;
pt_cfg.loop = 0;
pt_cfg.loopDelay = 0;
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << PT_CHANNEL);
}
/**
* @brief 线性呼吸灯效果
*/
static void Breath_LED(void)
{
int i;
printf("渐亮...\n");
// 渐亮
for (i = 0; i <= BREATH_STEPS; i++) {
PT_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
printf("渐暗...\n");
// 渐暗
for (i = BREATH_STEPS; i >= 0; i--) {
PT_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 平滑呼吸灯效果 (指数曲线)
*/
static void Breath_LED_Smooth(void)
{
int i;
uint8_t duty;
// Gamma 2.2 校正表 - 更自然的视觉效果
static const uint8_t gamma_table[64] = {
0, 0, 0, 0, 0, 1, 1, 1,
1, 2, 2, 2, 3, 3, 4, 4,
5, 5, 6, 7, 7, 8, 9, 10,
11, 12, 13, 14, 15, 17, 18, 19,
21, 22, 24, 26, 27, 29, 31, 33,
35, 37, 40, 42, 44, 47, 50, 52,
55, 58, 61, 64, 68, 71, 75, 78,
82, 86, 90, 94, 98, 103, 107, 100
};
// 渐亮
for (i = 0; i < 64; i++) {
duty = gamma_table[i];
PT_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = 63; i >= 0; i--) {
duty = gamma_table[i];
PT_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 正弦波呼吸效果
*/
static void Breath_LED_Sine(void)
{
int i;
// 正弦波查找表 (0-100范围,半周期)
static const uint8_t sine_table[64] = {
0, 2, 5, 7, 10, 12, 15, 17,
20, 22, 25, 27, 30, 32, 35, 37,
40, 42, 44, 47, 49, 51, 54, 56,
58, 60, 62, 64, 66, 68, 70, 72,
74, 76, 77, 79, 81, 82, 84, 85,
87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 97, 98, 98, 99, 99,
99, 100, 100, 100, 100, 100, 100, 100
};
// 渐亮 (0 -> 100)
for (i = 0; i < 64; i++) {
PT_SetDutyCycle(sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗 (100 -> 0)
for (i = 63; i >= 0; i--) {
PT_SetDutyCycle(sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 主函数
*/
int main(void)
{
int ret;
int mode = 0;
printf("\n\n========================================\n");
printf(" MAX32655 Pulse Train 呼吸灯示例\n");
printf("========================================\n\n");
// 打印PT通道对应的引脚信息
printf("PT%d 输出引脚: 请参考数据手册\n", PT_CHANNEL);
printf("呼吸周期: 约 %d ms\n", BREATH_STEPS * BREATH_DELAY_MS * 2);
// 初始化Pulse Train
ret = PT_PWM_Init();
if (ret != E_NO_ERROR) {
printf("初始化失败! 错误码: %d\n", ret);
while (1);
}
printf("\n开始呼吸灯效果...\n\n");
// 主循环 - 轮换不同的呼吸效果
while (1) {
switch (mode) {
case 0:
printf("模式0: 线性呼吸\n");
Breath_LED();
break;
case 1:
printf("模式1: 平滑呼吸(Gamma校正)\n");
Breath_LED_Smooth();
break;
case 2:
printf("模式2: 正弦波呼吸\n");
Breath_LED_Sine();
break;
}
// 切换模式
mode = (mode + 1) % 3;
// 模式切换间隔
MXC_Delay(MXC_DELAY_MSEC(500));
}
return 0;
}
对于b灯,使用定时器tmr2,功能码2,使用claude生成呼吸灯,代码如下
#if 0
/**
* @file main.c
* @brief MAX32655 Pulse Train 呼吸灯示例
* @details 使用PT模块产生PWM信号,实现LED呼吸灯效果
*/
#include <stdio.h>
#include <stdint.h>
#include "mxc_device.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "pt.h"
#include "gpio.h"
#include "board.h"
/*******************************************************************************
* 宏定义
******************************************************************************/
#define PT_CHANNEL 0 // 使用PT通道0
#define PT_FREQ 1000 // PWM频率: 1kHz
#define PT_RATE_HZ 1000000 // PT时钟频率: 1MHz
#define BREATH_STEPS 100 // 呼吸步数
#define BREATH_DELAY_MS 15 // 每步延时(ms)
/*******************************************************************************
* 全局变量
******************************************************************************/
static uint32_t pt_rate; // 实际PT时钟频率
/*******************************************************************************
* 函数声明
******************************************************************************/
static int PT_PWM_Init(void);
static void PT_SetDutyCycle(uint8_t duty_percent);
static void Breath_LED(void);
static void Breath_LED_Smooth(void);
/*******************************************************************************
* 函数实现
******************************************************************************/
/**
* @brief 初始化Pulse Train为PWM模式
* @return 0:成功, 其他:失败
*/
static int PT_PWM_Init(void)
{
int ret;
mxc_pt_cfg_t pt_cfg;
// 初始化PT模块,设置时钟频率
MXC_PT_Init(PT_RATE_HZ);
// 获取实际的PT时钟频率
//pt_rate = MXC_PT_GetRateHz();
// printf("PT时钟频率: %u Hz\n", pt_rate);
// 配置PT通道
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ; // 位速率 = PWM频率
pt_cfg.ptLength = 2; // 2位模式 (用于PWM)
pt_cfg.pattern = 0x01; // 初始模式: 50%占空比 (01)
pt_cfg.loop = 0; // 连续循环
pt_cfg.loopDelay = 0; // 无延迟
ret = MXC_PT_Config(&pt_cfg);
if (ret != E_NO_ERROR) {
printf("PT配置失败: %d\n", ret);
return ret;
}
// 启动PT通道
MXC_PT_Start(1 << PT_CHANNEL);
printf("Pulse Train 初始化成功\n");
printf("PWM频率: %d Hz\n", PT_FREQ);
return E_NO_ERROR;
}
/**
* @brief 使用32位模式设置更精确的占空比
* @param duty_percent: 占空比(0-100)
*/
static void PT_SetDutyCycle(uint8_t duty_percent)
{
uint32_t pattern;
uint32_t high_bits;
// 限制范围
if (duty_percent > 100) {
duty_percent = 100;
}
// 停止当前PT
MXC_PT_Stop(1 << PT_CHANNEL);
// 使用32位模式,计算高电平位数
// 32位中有多少位为1决定占空比
high_bits = (32 * duty_percent) / 100;
if (high_bits == 0) {
pattern = 0x00000000; // 0%
} else if (high_bits >= 32) {
pattern = 0xFFFFFFFF; // 100%
} else {
// 生成pattern: 高位为1,低位为0
pattern = (1UL << high_bits) - 1;
}
// 重新配置PT
mxc_pt_cfg_t pt_cfg;
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ * 32; // 32位 * PWM频率
pt_cfg.ptLength = 32; // 32位模式
pt_cfg.pattern = pattern;
pt_cfg.loop = 0;
pt_cfg.loopDelay = 0;
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << PT_CHANNEL);
}
/**
* @brief 简化版占空比设置 (使用8位模式)
* @param duty: 占空比值(0-255映射到0-100%)
*/
static void PT_SetDutyCycle_8bit(uint8_t duty)
{
uint8_t pattern;
uint8_t high_bits;
MXC_PT_Stop(1 << PT_CHANNEL);
// 8位模式下计算高电平位数
high_bits = duty / 32; // 0-7位
if (high_bits == 0) {
pattern = 0x00;
} else if (high_bits >= 8) {
pattern = 0xFF;
} else {
pattern = (1 << high_bits) - 1;
}
mxc_pt_cfg_t pt_cfg;
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ * 8;
pt_cfg.ptLength = 8;
pt_cfg.pattern = pattern;
pt_cfg.loop = 0;
pt_cfg.loopDelay = 0;
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << PT_CHANNEL);
}
/**
* @brief 线性呼吸灯效果
*/
static void Breath_LED(void)
{
int i;
printf("渐亮...\n");
// 渐亮
for (i = 0; i <= BREATH_STEPS; i++) {
PT_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
printf("渐暗...\n");
// 渐暗
for (i = BREATH_STEPS; i >= 0; i--) {
PT_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 平滑呼吸灯效果 (指数曲线)
*/
static void Breath_LED_Smooth(void)
{
int i;
uint8_t duty;
// Gamma 2.2 校正表 - 更自然的视觉效果
static const uint8_t gamma_table[64] = {
0, 0, 0, 0, 0, 1, 1, 1,
1, 2, 2, 2, 3, 3, 4, 4,
5, 5, 6, 7, 7, 8, 9, 10,
11, 12, 13, 14, 15, 17, 18, 19,
21, 22, 24, 26, 27, 29, 31, 33,
35, 37, 40, 42, 44, 47, 50, 52,
55, 58, 61, 64, 68, 71, 75, 78,
82, 86, 90, 94, 98, 103, 107, 100
};
// 渐亮
for (i = 0; i < 64; i++) {
duty = gamma_table[i];
PT_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = 63; i >= 0; i--) {
duty = gamma_table[i];
PT_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 正弦波呼吸效果
*/
static void Breath_LED_Sine(void)
{
int i;
// 正弦波查找表 (0-100范围,半周期)
static const uint8_t sine_table[64] = {
0, 2, 5, 7, 10, 12, 15, 17,
20, 22, 25, 27, 30, 32, 35, 37,
40, 42, 44, 47, 49, 51, 54, 56,
58, 60, 62, 64, 66, 68, 70, 72,
74, 76, 77, 79, 81, 82, 84, 85,
87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 97, 98, 98, 99, 99,
99, 100, 100, 100, 100, 100, 100, 100
};
// 渐亮 (0 -> 100)
for (i = 0; i < 64; i++) {
PT_SetDutyCycle(sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗 (100 -> 0)
for (i = 63; i >= 0; i--) {
PT_SetDutyCycle(sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 主函数
*/
int main(void)
{
int ret;
int mode = 0;
printf("\n\n========================================\n");
printf(" MAX32655 Pulse Train 呼吸灯示例\n");
printf("========================================\n\n");
// 打印PT通道对应的引脚信息
printf("PT%d 输出引脚: 请参考数据手册\n", PT_CHANNEL);
printf("呼吸周期: 约 %d ms\n", BREATH_STEPS * BREATH_DELAY_MS * 2);
// 初始化Pulse Train
ret = PT_PWM_Init();
if (ret != E_NO_ERROR) {
printf("初始化失败! 错误码: %d\n", ret);
while (1);
}
printf("\n开始呼吸灯效果...\n\n");
// 主循环 - 轮换不同的呼吸效果
while (1) {
switch (mode) {
case 0:
printf("模式0: 线性呼吸\n");
Breath_LED();
break;
case 1:
printf("模式1: 平滑呼吸(Gamma校正)\n");
Breath_LED_Smooth();
break;
case 2:
printf("模式2: 正弦波呼吸\n");
Breath_LED_Sine();
break;
}
// 切换模式
mode = (mode + 1) % 3;
// 模式切换间隔
MXC_Delay(MXC_DELAY_MSEC(500));
}
return 0;
}
#endif
/**
* @file main.c
* @brief MAX32655 PWM呼吸灯示例
* @details 使用TMR模块产生PWM信号,实现LED呼吸灯效果
*/
#include <stdio.h>
#include <stdint.h>
#include "mxc_device.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "tmr.h"
#include "gpio.h"
#include "board.h"
#include "led.h"
/*******************************************************************************
* 宏定义
******************************************************************************/
#define PWM_TIMER MXC_TMR2 // 使用TMR0
#define PWM_PORT MXC_GPIO0 // GPIO端口
#define PWM_PIN MXC_GPIO_PIN_26 // PWM输出引脚 (P0.3)
#define PWM_FREQ 1000 // PWM频率: 1kHz
#define BREATH_STEPS 100 // 呼吸步数
#define BREATH_DELAY_MS 10 // 每步延时(ms)
/*******************************************************************************
* 全局变量
******************************************************************************/
static mxc_tmr_cfg_t tmr_cfg;
/*******************************************************************************
* 函数声明
******************************************************************************/
static int PWM_Init(void);
static void PWM_SetDutyCycle(uint8_t duty_percent);
static void Breath_LED(void);
/*******************************************************************************
* 函数实现
******************************************************************************/
/**
* @brief 初始化PWM
* @return 0:成功, 其他:失败
*/
static int PWM_Init(void)
{
int ret;
// 配置GPIO为TMR0输出功能
mxc_gpio_cfg_t gpio_cfg;
gpio_cfg.port = PWM_PORT;
gpio_cfg.mask = PWM_PIN;
gpio_cfg.func = MXC_GPIO_FUNC_ALT1; // TMR0_OUT功能
gpio_cfg.pad = MXC_GPIO_PAD_NONE;
gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIOH;
ret = MXC_GPIO_Config(&gpio_cfg);
if (ret != E_NO_ERROR) {
printf("GPIO配置失败: %d\n", ret);
return ret;
}
// 初始化定时器时钟
MXC_TMR_Shutdown(PWM_TIMER);
// 配置PWM模式
tmr_cfg.pres = TMR_PRES_1; // 预分频: 1
tmr_cfg.mode = TMR_MODE_PWM; // PWM模式
tmr_cfg.bitMode = TMR_BIT_MODE_32; // 32位模式
tmr_cfg.clock = MXC_TMR_APB_CLK; // 使用APB时钟
tmr_cfg.cmp_cnt = PeripheralClock / PWM_FREQ; // 设置周期
tmr_cfg.pol = 1; // 极性
ret = MXC_TMR_Init(PWM_TIMER, &tmr_cfg, false);
if (ret != E_NO_ERROR) {
printf("TMR初始化失败: %d\n", ret);
return ret;
}
// 设置初始占空比为0
PWM_SetDutyCycle(0);
// 启动定时器
MXC_TMR_Start(PWM_TIMER);
printf("PWM初始化成功, 频率: %d Hz\n", PWM_FREQ);
return E_NO_ERROR;
}
/**
* @brief 设置PWM占空比
* @param duty_percent: 占空比(0-100)
*/
static void PWM_SetDutyCycle(uint8_t duty_percent)
{
uint32_t period;
uint32_t duty_count;
// 限制范围
if (duty_percent > 100) {
duty_percent = 100;
}
// 获取周期计数值
period = tmr_cfg.cmp_cnt;
// 计算占空比计数值
duty_count = (period * duty_percent) / 100;
// 设置PWM占空比
MXC_TMR_SetPWM(PWM_TIMER, duty_count);
}
/**
* @brief 呼吸灯效果 - 使用线性渐变
*/
static void Breath_LED(void)
{
int i;
// 渐亮
for (i = 0; i <= BREATH_STEPS; i++) {
PWM_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = BREATH_STEPS; i >= 0; i--) {
PWM_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 呼吸灯效果 - 使用指数渐变 (更自然的视觉效果)
*/
static void Breath_LED_Exponential(void)
{
int i;
uint8_t duty;
// 指数查找表 (模拟人眼对亮度的非线性感知)
static const uint8_t gamma_table[101] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 4, 4, 4, 5,
5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
10, 10, 11, 12, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 24, 25, 26, 28, 29,
31, 33, 34, 36, 38, 40, 42, 44, 47, 49,
51, 54, 57, 59, 62, 65, 68, 71, 75, 78,
82, 85, 89, 93, 97, 101, 105, 110, 114, 119,
124, 129, 134, 139, 145, 150, 156, 162, 168, 175,
181
};
// 渐亮
for (i = 0; i <= 100; i++) {
duty = gamma_table[i] * 100 / 181; // 映射到0-100
PWM_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = 100; i >= 0; i--) {
duty = gamma_table[i] * 100 / 181;
PWM_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 主函数
*/
int main(void)
{
int ret;
printf("\n\n****** MAX32655 PWM呼吸灯示例 ******\n");
printf("PWM引脚: P0.3\n");
printf("PWM频率: %d Hz\n", PWM_FREQ);
printf("呼吸周期: %d ms\n", BREATH_STEPS * BREATH_DELAY_MS * 2);
// 初始化PWM
ret = PWM_Init();
if (ret != E_NO_ERROR) {
printf("PWM初始化失败!\n");
while (1);
}
printf("开始呼吸灯效果...\n");
// 主循环
while (1) {
// 选择一种呼吸效果
// Breath_LED(); // 线性渐变
Breath_LED_Exponential(); // 指数渐变 (更自然)
}
return 0;
}
效果如下
第四种灯效需要随机数,用于乱闪led,所以开启trng 外设。开了个定时器,好像没用。
实际代码如下
/**
* @file main.c
* @brief MAX32655 PWM呼吸灯示例
* @details 使用TMR模块产生PWM信号,实现LED呼吸灯效果
*/
#include <stdio.h>
#include <stdint.h>
#include "mxc_device.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "tmr.h"
#include "gpio.h"
#include "board.h"
#include "led.h"
#include "nvic_table.h"
#include "pt.h"
#include "trng.h"
/*******************************************************************************
* 宏定义
******************************************************************************/
#define PWM_TIMER MXC_TMR2 // 使用TMR0
#define PWM_PORT MXC_GPIO0 // GPIO端口
#define PWM_PIN MXC_GPIO_PIN_26 // PWM输出引脚 (P0.3)
#define PWM_FREQ 1000 // PWM频率: 1kHz
#define BREATH_STEPS 100 // 呼吸步数
#define BREATH_DELAY_MS 10 // 每步延时(ms)
#define CONT_FREQ 1 // (Hz)
#define PT_CHANNEL 0 // 使用PT通道0
#define PT_CHANNEL_G 1 // 使用PT通道0
#define PT_FREQ 1000 // PWM频率: 1kHz
#define PT_RATE_HZ 1000000 // PT时钟频率: 1MHz
#define BREATH_STEPS 100 // 呼吸步数
#define BREATH_DELAY_MS 15 // 每步延时(ms)
/*******************************************************************************
* 全局变量
******************************************************************************/
static mxc_tmr_cfg_t tmr_cfg;
static uint32_t pt_rate; // 实际PT时钟频率
static uint8_t bthmopde = 0;
/*******************************************************************************
* 函数声明
******************************************************************************/
static int PWM_Init(void);
static void PWM_SetDutyCycle(uint8_t duty_percent);
static void Breath_LED(void);
void PB1Handler(void);
/*******************************************************************************
* 函数实现
******************************************************************************/
/**
* @brief 初始化PWM
* @return 0:成功, 其他:失败
*/
static int PWM_Init(void)
{
int ret;
// 配置GPIO为TMR0输出功能
mxc_gpio_cfg_t gpio_cfg;
gpio_cfg.port = PWM_PORT;
gpio_cfg.mask = PWM_PIN;
gpio_cfg.func = MXC_GPIO_FUNC_ALT1; // TMR0_OUT功能
gpio_cfg.pad = MXC_GPIO_PAD_NONE;
gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
ret = MXC_GPIO_Config(&gpio_cfg);
if (ret != E_NO_ERROR) {
printf("GPIO配置失败: %d\n", ret);
return ret;
}
// 初始化定时器时钟
MXC_TMR_Shutdown(PWM_TIMER);
// 配置PWM模式
tmr_cfg.pres = TMR_PRES_1; // 预分频: 1
tmr_cfg.mode = TMR_MODE_PWM; // PWM模式
tmr_cfg.bitMode = TMR_BIT_MODE_32; // 32位模式
tmr_cfg.clock = MXC_TMR_APB_CLK; // 使用APB时钟
tmr_cfg.cmp_cnt = PeripheralClock / PWM_FREQ; // 设置周期
tmr_cfg.pol = 1; // 极性
ret = MXC_TMR_Init(PWM_TIMER, &tmr_cfg, false);
if (ret != E_NO_ERROR) {
printf("TMR初始化失败: %d\n", ret);
return ret;
}
// 设置初始占空比为0
PWM_SetDutyCycle(0);
// 启动定时器
MXC_TMR_Start(PWM_TIMER);
printf("PWM初始化成功, 频率: %d Hz\n", PWM_FREQ);
return E_NO_ERROR;
}
/**
* @brief 设置PWM占空比
* @param duty_percent: 占空比(0-100)
*/
static void PWM_SetDutyCycle(uint8_t duty_percent)
{
uint32_t period;
uint32_t duty_count;
// 限制范围
if (duty_percent > 100) {
duty_percent = 100;
}
// 获取周期计数值
period = tmr_cfg.cmp_cnt;
// 计算占空比计数值
duty_count = (period * duty_percent) / 100;
// 设置PWM占空比
MXC_TMR_SetPWM(PWM_TIMER, duty_count);
}
/**
* @brief 呼吸灯效果 - 使用线性渐变
*/
static void Breath_LED(void)
{
int i;
// 渐亮
for (i = 0; i <= BREATH_STEPS; i++) {
PWM_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = BREATH_STEPS; i >= 0; i--) {
PWM_SetDutyCycle(i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 呼吸灯效果 - 使用指数渐变 (更自然的视觉效果)
*/
static void Breath_LED_Exponential(void)
{
int i;
uint8_t duty;
// 指数查找表 (模拟人眼对亮度的非线性感知)
static const uint8_t gamma_table[101] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 4, 4, 4, 5,
5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
10, 10, 11, 12, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 24, 25, 26, 28, 29,
31, 33, 34, 36, 38, 40, 42, 44, 47, 49,
51, 54, 57, 59, 62, 65, 68, 71, 75, 78,
82, 85, 89, 93, 97, 101, 105, 110, 114, 119,
124, 129, 134, 139, 145, 150, 156, 162, 168, 175,
181
};
// 渐暗
for (i = 100; i >= 0; i--) {
duty = gamma_table[i] * 100 / 181;
PWM_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐亮
for (i = 0; i <= 100; i++) {
duty = gamma_table[i] * 100 / 181; // 映射到0-100
PWM_SetDutyCycle(duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
void PB2Handler(void)
{
printf(" ---------------------------%s----------------------.\n\n", __func__);
return;
}
void Timer1Handler(void)
{
// Clear interrupt
MXC_TMR_ClearFlags(MXC_TMR1);
//printf("-------------------%s---------------------.\n\n",__func__);
}
void Timer2Handler(void)
{
// Clear interrupt
MXC_TMR_ClearFlags(MXC_TMR2);
printf("-------------------%s---------------------\n",__func__);
}
void Timer3Handler(void)
{
MXC_TMR_ClearFlags(MXC_TMR3);
printf("-------------------%s---------------------.\n\n",__func__);
}
void Timer4Handler(void)
{
MXC_TMR_ClearFlags(MXC_TMR4);
printf("-------------------%s------------------\n",__func__);
}
int initTmr(void)
{
printf("---------------[%s]--start----------------\n",__func__);
MXC_NVIC_SetVector(TMR1_IRQn, Timer1Handler);
NVIC_EnableIRQ(TMR1_IRQn);
// Declare variables
mxc_tmr_cfg_t tmr;
uint32_t periodTicks = MXC_TMR_GetPeriod(MXC_TMR1, MXC_TMR_ISO_CLK, 128, CONT_FREQ);
MXC_TMR_Shutdown(MXC_TMR1);
tmr.pres = TMR_PRES_128;
tmr.mode = TMR_MODE_CONTINUOUS;
tmr.bitMode = TMR_BIT_MODE_32;
tmr.clock = MXC_TMR_ISO_CLK;
tmr.cmp_cnt = periodTicks; //SystemCoreClock*(1/interval_time);
tmr.pol = 0;
MXC_TMR_Init(MXC_TMR1, &tmr, true);
MXC_TMR_EnableInt(MXC_TMR1);
MXC_TMR_SetPWM(MXC_TMR1, periodTicks*4);
MXC_TMR_Start(MXC_TMR1);
printf("---------------[%s]--end----------------\n",__func__);
return 0;
}
/**
* @brief 初始化Pulse Train为PWM模式
* @return 0:成功, 其他:失败
*/
static int PT_PWM_Init(void)
{
int ret;
mxc_pt_cfg_t pt_cfg;
// 初始化PT模块,设置时钟频率
MXC_PT_Init(PT_RATE_HZ);
// 获取实际的PT时钟频率
//pt_rate = MXC_PT_GetRateHz();
// printf("PT时钟频率: %u Hz\n", pt_rate);
// 配置PT通道
pt_cfg.channel = PT_CHANNEL;
pt_cfg.bps = PT_FREQ; // 位速率 = PWM频率
pt_cfg.ptLength = 2; // 2位模式 (用于PWM)
pt_cfg.pattern = 0x3; // 初始模式: 50%占空比 (01)
pt_cfg.loop = 0; // 连续循环
pt_cfg.loopDelay = 0; // 无延迟
ret = MXC_PT_Config(&pt_cfg);
if (ret != E_NO_ERROR) {
printf("PT配置失败: %d\n", ret);
return ret;
}
// 启动PT通道
MXC_PT_Start(1 << PT_CHANNEL);
//--------------------------------------------------
pt_cfg.channel = PT_CHANNEL_G;\
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << PT_CHANNEL_G);
printf("Pulse Train 初始化成功\n");
printf("PWM频率: %d Hz\n", PT_FREQ);
return E_NO_ERROR;
}
/**
* @brief 使用32位模式设置更精确的占空比
* @param duty_percent: 占空比(0-100)
*/
static void PT_SetDutyCycle(uint8_t channel, uint8_t duty_percent)
{
uint32_t pattern;
uint32_t high_bits;
// 限制范围
if (duty_percent > 100) {
duty_percent = 100;
}
// 停止当前PT
MXC_PT_Stop(1 << channel);
// 使用32位模式,计算高电平位数
// 32位中有多少位为1决定占空比
high_bits = (32 * duty_percent) / 100;
if (high_bits == 0) {
pattern = 0x00000000; // 0%
} else if (high_bits >= 32) {
pattern = 0xFFFFFFFF; // 100%
} else {
// 生成pattern: 高位为1,低位为0
pattern = (1UL << high_bits) - 1;
}
// 重新配置PT
mxc_pt_cfg_t pt_cfg;
pt_cfg.channel = channel;
pt_cfg.bps = PT_FREQ * 32; // 32位 * PWM频率
pt_cfg.ptLength = 32; // 32位模式
pt_cfg.pattern = pattern;
pt_cfg.loop = 0;
pt_cfg.loopDelay = 0;
MXC_PT_Config(&pt_cfg);
MXC_PT_Start(1 << channel);
}
/**
* @brief 线性呼吸灯效果
*/
static void Breath_LED_pt(uint8_t channel)
{
int i;
printf("渐暗...\n");
// 渐暗
for (i = BREATH_STEPS; i >= 0; i--) {
PT_SetDutyCycle(channel,i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
printf("渐亮...\n");
// 渐亮
for (i = 0; i <= BREATH_STEPS; i++) {
PT_SetDutyCycle(channel,i);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 平滑呼吸灯效果 (指数曲线)
*/
static void Breath_LED_Smooth_pt(uint8_t channel)
{
int i;
uint8_t duty;
// Gamma 2.2 校正表 - 更自然的视觉效果
static const uint8_t gamma_table[64] = {
0, 0, 0, 0, 0, 1, 1, 1,
1, 2, 2, 2, 3, 3, 4, 4,
5, 5, 6, 7, 7, 8, 9, 10,
11, 12, 13, 14, 15, 17, 18, 19,
21, 22, 24, 26, 27, 29, 31, 33,
35, 37, 40, 42, 44, 47, 50, 52,
55, 58, 61, 64, 68, 71, 75, 78,
82, 86, 90, 94, 98, 103, 107, 100
};
// 渐亮
for (i = 0; i < 64; i++) {
duty = gamma_table[i];
PT_SetDutyCycle(channel,duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐暗
for (i = 63; i >= 0; i--) {
duty = gamma_table[i];
PT_SetDutyCycle(channel,duty);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
/**
* @brief 正弦波呼吸效果
*/
static void Breath_LED_Sine_pt(uint8_t channel)
{
int i;
// 正弦波查找表 (0-100范围,半周期)
static const uint8_t sine_table[64] = {
0, 2, 5, 7, 10, 12, 15, 17,
20, 22, 25, 27, 30, 32, 35, 37,
40, 42, 44, 47, 49, 51, 54, 56,
58, 60, 62, 64, 66, 68, 70, 72,
74, 76, 77, 79, 81, 82, 84, 85,
87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 97, 98, 98, 99, 99,
99, 100, 100, 100, 100, 100, 100, 100
};
// 渐暗 (100 -> 0)
for (i = 63; i >= 0; i--) {
PT_SetDutyCycle(channel,sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
// 渐亮 (0 -> 100)
for (i = 0; i < 64; i++) {
PT_SetDutyCycle(channel,sine_table[i]);
MXC_Delay(MXC_DELAY_MSEC(BREATH_DELAY_MS));
}
}
#define LIGHTT_ON 0
#define LIGHTT_OFF 100
void PB1Handler(void)
{
bthmopde++;
bthmopde = bthmopde& 0x0003 ;
printf(" --------------------------%s---------bthmopde[%d]-------------.\n\n", __func__,bthmopde);
PT_SetDutyCycle(PT_CHANNEL,LIGHTT_OFF);
PT_SetDutyCycle(PT_CHANNEL_G,LIGHTT_OFF);
PWM_SetDutyCycle(LIGHTT_OFF);
return;
}
uint8_t var_rnd_no[128] = { 0 };
void Test_TRNG(int asynchronous)
{
printf(asynchronous ? "\nTest TRNG Async\n" : "\nTest TRNG Sync\n");
MXC_TRNG_Init();
}
void get_data()
{
MXC_TRNG_Random(var_rnd_no, 128);
}
/**
* @brief 主函数
*/
int main(void)
{
int ret;
printf("\n\n****** MAX32655 PWM呼吸灯示例 ******\n");
printf("PWM引脚: P0.3\n");
printf("PWM频率: %d Hz\n", PWM_FREQ);
printf("呼吸周期: %d ms\n", BREATH_STEPS * BREATH_DELAY_MS * 2);
PB_RegisterCallback(0, (pb_callback)PB1Handler);
PB_RegisterCallback(1, (pb_callback)PB2Handler);
initTmr();
PT_PWM_Init();
Test_TRNG(0);
// 初始化PWM
ret = PWM_Init();
if (ret != E_NO_ERROR) {
printf("PWM初始化失败!\n");
while (1);
}
printf("开始呼吸灯效果...\n");
// 主循环
bthmopde = 0;
// Breath_LED_Exponential();
while (1) {
printf("开始呼吸灯效果..bthmopde[%d]--------------.\n",bthmopde);
//PT_SetDutyCycle(PT_CHANNEL,LIGHTT_ON); //red on
// PT_SetDutyCycle(PT_CHANNEL_G,LIGHTT_ON); //green on
// PWM_SetDutyCycle(LIGHTT_ON); //blue on
if(bthmopde==0){
Breath_LED_pt(PT_CHANNEL);
}else if(bthmopde==1){
Breath_LED_Sine_pt(PT_CHANNEL_G);
}else if(bthmopde==2){
Breath_LED_Exponential();
}else if(bthmopde==3){
get_data();
for(int i=0;i<128;i++){
PT_SetDutyCycle(PT_CHANNEL,var_rnd_no[i]%100);
printf("var_rnd_no[%d][%d]--------------.\n",i,var_rnd_no[i]);
i++;
PT_SetDutyCycle(PT_CHANNEL_G,var_rnd_no[i]%100);
printf("var_rnd_no[%d][%d]--------------.\n",i,var_rnd_no[i]);
i++;
PWM_SetDutyCycle(var_rnd_no[i]%100);
printf("var_rnd_no[%d][%d]--------------.\n",i,var_rnd_no[i]);
MXC_Delay(MXC_DELAY_MSEC(200));
}
// Breath_LED_pt(PT_CHANNEL);
// Breath_LED_Sine_pt(PT_CHANNEL_G);
// Breath_LED_Exponential();
}
}
return 0;
}
疑难杂症
暂无,对pt和定时期的使用比较顺利,ai写代码的准确率超乎我的期待,一键生成直接能用。
心得体会
衷心感谢电子森林举办这次关于 MAX32655 板卡的活动。活动内容丰富、安排紧凑,不仅让我们深入了解了 MAX32655 的硬件结构与功能特色,还通过实操环节帮助大家快速上手开发和调试。讲师讲解清晰、案例贴近实际,使复杂的概念变得易于理解。
在活动中,我学到了如何配置开发环境、调试外设等实用技巧,这些对后续项目开发非常有帮助。同时,活动也为开发者提供了交流平台,大家分享经验、互相切磋,收获颇丰。
感谢电子森林团队的精心组织与辛勤付出,也感谢所有参与者的积极互动和支持。