1、 正弦呼吸灯实现方法
本次正弦呼吸灯采用软件模拟PWM(脉冲宽度调制)方案实现,无需配置硬件定时器和引脚复用,代码更简洁、上手更快速,核心是通过正弦函数动态控制软件PWM的占空比,让LED亮度按照正弦曲线平滑变化,最终实现自然柔和的呼吸效果。
软件PWM的亮度控制逻辑。PWM的核心是“固定周期内,高、低电平的时间比例(占空比)决定LED亮度”,占空比越高(LED点亮时间越长),亮度越亮;反之则越暗。 与硬件PWM不同,软件PWM无需依赖外设定时器,而是通过
`DELAY_US()`函数精准控制LED的“点亮时长”和“熄灭时长”,两者之和为一个固定的PWM周期(本次设置为400μs,对应2.5kHz频率),该频率远超于人眼的视觉暂留阈值,不会产生明显频闪。另外,需注意本硬件的LED为低电平点亮、高电平熄灭(对应代码中`GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 0)`点亮LED)。
正弦函数的呼吸循环映射。 正弦函数
`sin(θ)`在`0~π`(弧度)区间内,输出值从0.0平滑递增至1.0,再平滑递减至0.0,这个变化过程与呼吸灯“暗→亮→暗”的循环完全匹配:- θ=0:sin(0)=0 → 占空比0% → LED完全熄灭(最暗);- θ=π/2:sin(π/2)=1 → 占空比100% → LED完全点亮(最亮); - θ=π:sin(π)=0 → 占空比0% → LED完全熄灭(回到最暗)。 通过实时更新角度`θ`并计算对应的正弦值,即可得到平滑变化的占空比,进而实现无“台阶感”的正弦呼吸效果。
2、 程序
//
// Included Files
//
#include "g32r501_project.h"
#include <math.h> // 引入数学库以使用sin函数
//
// Defines
//
#define DEVICE_GPIO_PIN_LED1 23
#define PI 3.1415926f
// --- 呼吸灯核心参数调整 ---
// PWM周期:400us (对应2.5kHz频率),人眼无法察觉频闪
#define PWM_PERIOD_US 400
// 呼吸速度步进:数值越小越慢。
// 计算:3.14 / 0.0005 = 6280次循环; 6280 * 400us ≈ 2.5秒
#define BREATH_SPEED 0.0005f
//
// Main
//
void example_main(void)
{
// 变量定义
float angle = 0.0f; // 当前角度 (弧度)
float duty_cycle = 0.0f;// 当前占空比 (0.0 - 1.0)
uint32_t time_on = 0; // 亮灯时长 (us)
uint32_t time_off = 0; // 灭灯时长 (us)
//
// Initialize device clock and peripherals
//
InitSysCtrl();
//
// Initialize GPIO and configure the GPIO pin as a push-pull output
//
InitGpio();
GPIO_SetupPinMux(DEVICE_GPIO_PIN_LED1, GPIO_MUX_CPU0, 0);
GPIO_SetupPinOptions(DEVICE_GPIO_PIN_LED1, GPIO_OUTPUT, GPIO_PUSHPULL);
//
// Initialize NVIC and clears NVIC registers. Disables CPU interrupts.
//
DINT;
Interrupt_initModule();
Interrupt_initVectorTable();
EINT;
ERTM;
//
// Loop Forever
//
for(;;)
{
// 1. 计算正弦占空比
// sin(angle) 结果为 0.0 到 1.0
duty_cycle = sinf(angle);
// 保护范围
if(duty_cycle < 0.0f) duty_cycle = 0.0f;
// 2. 根据占空比计算 亮/灭 持续时间
time_on = (uint32_t)(duty_cycle * PWM_PERIOD_US);
time_off = PWM_PERIOD_US - time_on;
// 3. 执行软件PWM周期 (低电平点亮,高电平熄灭)
// --- 亮灯阶段 ---
if(time_on > 0)
{
GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 0); // 点亮
DELAY_US(time_on);
}
// --- 灭灯阶段 ---
if(time_off > 0)
{
GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 1); // 熄灭
DELAY_US(time_off);
}
// 4. 更新角度
angle += BREATH_SPEED;
// 5. 周期结束处理
if(angle > PI)
{
angle = 0.0f; // 重置角度
// 强制熄灭LED,防止浮点误差导致微亮
GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 1);
// 添加“屏息”时间:呼吸结束后的自然停顿 (500ms)
// 这样效果更有节奏感,不像机器那样一刻不停
DELAY_US(500000);
}
}
}
3、效果

