Funpack4-3 - 基于MAX32655FTHR 实现按钮切换不同rgb灯效
该项目使用了MAX32655FTHR,实现了led的灯效的设计,它的主要功能为:使用按钮实现各个灯效的切换。
标签
定时器
MAX32655FTHR
pt
悠悠兹有
更新2026-02-25
13

硬件介绍

资料

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支持。

image.png

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

image.png

通过ssh连接的情况下,最后把updatesh脚本改个名字,不然ssh会断开。

简单测试一个流程:helloworld。

image.png

make 编译成功后,使用make flash.openocd烧录程序到板卡里。

执行minicom -c on -D /dev/ttyACM0,打开串口,显示如下

image.png

项目框图

led引脚接线如下

image.png

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

image.png

流程图如下

image.png

开发代码

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

image.png

生成的代码如下

/**
* @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 的硬件结构与功能特色,还通过实操环节帮助大家快速上手开发和调试。讲师讲解清晰、案例贴近实际,使复杂的概念变得易于理解。

在活动中,我学到了如何配置开发环境、调试外设等实用技巧,这些对后续项目开发非常有帮助。同时,活动也为开发者提供了交流平台,大家分享经验、互相切磋,收获颇丰。

感谢电子森林团队的精心组织与辛勤付出,也感谢所有参与者的积极互动和支持。

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