阿源玩电子 发表于 2025-6-24 21:26

【灵动微电子MM32F0121测评】3.PWM呼吸灯

本帖最后由 阿源玩电子 于 2025-6-24 21:44 编辑

PWM呼吸灯

[*]原理图部分

2.引脚复用,使用TIM1的1,2通道用于调光,PB14和PB15复用为AF7功能。

3.定时器配置频率计算:
[*]预分频值计算为(TIM_ClockFrequency / 1000000) - 1,使计数器时钟为1MHz
[*]设置ARR值为999(1000-1),得到精确的1kHz PWM频率
占空比范围:

[*]通过设置ARR=999,CCR值范围0-999对应0%-100%占空比
[*]使用TIM_SetCompare1(TIM1, value),TIM_SetCompare2(TIM1, value)设置占空比,value范围0-999


[*]pwm_dsp.c
#include "pwm_dsp.h"
void TIM1_PWM_Configure(void)
{
    RCC_ClocksTypeDef       RCC_Clocks;
    GPIO_InitTypeDef      GPIO_InitStruct;
    TIM_OCInitTypeDef       TIM_OCInitStruct;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    uint32_t                TIM_ClockFrequency = 0;
    uint32_t                HPRE = 0, PPRE2 = 0;

    // PWM参数配置
    uint32_t PWM_Frequency = 1000;    // 1kHz PWM频率
    uint16_t PWM_Period = 1000;       // 周期值(ARR),占空比范围0-1000
    uint16_t PrescalerValue = 0;      // 预分频值

    // 1. 获取时钟频率
    HPRE= READ_BIT(RCC->CFGR, RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_Pos;
    PPRE2 = READ_BIT(RCC->CFGR, RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos;
    RCC_GetClocksFreq(&RCC_Clocks);

    // 计算TIM1时钟频率
    if (HPRE < 8) {
      TIM_ClockFrequency = (PPRE2 < 4) ? RCC_Clocks.PCLK2_Frequency : RCC_Clocks.PCLK2_Frequency * 2;
    } else {
      TIM_ClockFrequency = (PPRE2 < 4) ? RCC_Clocks.PCLK2_Frequency * 2 : RCC_Clocks.PCLK2_Frequency * 4;
    }

    // 2. 计算预分频值 (目标计数器时钟 = 1MHz)
    PrescalerValue = (uint16_t)(TIM_ClockFrequency / 1000000) - 1;

    // 3. 初始化TIM1定时器
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
    TIM_TimeBaseInitStruct.TIM_Prescaler = PrescalerValue;// 设置预分频
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period = PWM_Period - 1;   // ARR值 (1000-1)
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_Div1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);

    // 4. 配置PWM模式 (初始占空比0%)
    TIM_OCStructInit(&TIM_OCInitStruct);
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_Pulse = 0;               // 初始CCR值(占空比)
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;

    TIM_OC1Init(TIM1, &TIM_OCInitStruct);// 配置通道1
    TIM_OC2Init(TIM1, &TIM_OCInitStruct);// 配置通道2

    // 启用预装载寄存器
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM1, ENABLE);

    // 5. 配置GPIO为PWM输出
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_7);// TIM1_CH1
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_7);// TIM1_CH2

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 6. 使能TIM1和PWM输出
    TIM_Cmd(TIM1, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

[*]pwm_dsp.h#include "hal_conf.h"
void TIM1_PWM_Configure(void);
4.试验现象PB14(TIM1_CH1) 和 PB15(TIM1_CH2)将输出1kHz 的 PWM 信号,并可动态调整占空比(0%~100%),将占空比由0变化到1000,再由1000变换到0,由此作为呼吸效果







loutin 发表于 2025-7-2 12:43

从硬件配置到软件编程,每个步骤都有详细的说明,这对于初学者来说非常有帮助。

ccook11 发表于 2025-7-2 13:34

可以学习如何配置MCU的定时器和GPIO

sanfuzi 发表于 2025-7-3 21:50

灵动微电子MM32F0121是一款基于ARM Cortex-M0内核的32位微控制器(MCU),具有高集成度和便捷开发体验的特点。

pentruman 发表于 2025-7-4 21:46

PWM呼吸灯实验是一个实用的项目

sanfuzi 发表于 2025-7-5 22:27

频率和占空比的调节方法。            
页: [1]
查看完整版本: 【灵动微电子MM32F0121测评】3.PWM呼吸灯