STM32定时器详解!BASE与PWM模式!一文看懂

一、基本定时器

定时器的本质

        定时器本质是一个计数器,所以牵扯到的问题就是多久产生一次计数,计数到到多少会发生什么世事件,因此引出相应的寄存器来设置。

相关寄存器

        PSC预分频器:对输入时钟TIMxCLK进行分频--->决定计数的时间
        自动重装载寄存器(ARR):当计数器=ARR时,触发相应事件 ,他有自己对应的影子寄存器,预装载寄存器用于设置定时器的参数,比如设置自动重装载值等。而这些设置的参数需要从预装载寄存器加载到对应的影子寄存器,影子寄存器中的值才会真正对定时器的运行产生作用
        ARPE使能有缓冲功能,预装载寄存器的值不会立即更新到影子寄存器,要等到发生更新事件(如计数器溢出)时,预装载寄存器的值才会被传送到影子寄存器中。当ARPE位未使能时,预装载寄存器中的值会立即传送到影子寄存器,也就是对预装载寄存器的修改会马上生效,直接影响定时器的运行参数

定时器溢出时间

        简而言之就是多少次计数乘以一次计数的时间。

HAL库实现基本定时器

TIM_HandleTypeDef g_timx_handle;

void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handle.Instance = TIM6;
    g_timx_handle.Init.Prescaler = psc;
    g_timx_handle.Init.Period = arr;
    HAL_TIM_Base_Init(&g_timx_handle);

    HAL_TIM_Base_Start_IT(&g_timx_handle);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM6)
    {
        __HAL_RCC_TIM6_CLK_ENABLE();
        HAL_NVIC_SetPriority(TIM6_IRQn, 1, 3);
        HAL_NVIC_EnableIRQ(TIM6_IRQn);
    }
}

void TIM6_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handle);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM6)
    {
        LED0_TOGGLE();
    }
}

二、通用定时器+PWM模式

        通用定时器的模式和功能更多,但计数的本质不变

实验:通过定时器PWM模式实现呼吸灯
 

核心思想:当配置为复用推挽输出+PWM模式后,GPIO的电平变化完全由定时器硬件自动控制,脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空
比的信号。

过程

1.配置定时器 --HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle)--与HAL_TIM_Base_Init对应;
2.配置pwm通道
3.启用PWM
4.初始化GPIO为推挽复用模式

核心理解:定时器的时钟源经过预分频之后的信号决定了计数器多久自加一次,而arr的值决定了加到多少置零重新加,而ccr决定了占空比得多少,小于ccr的值为有效电平,大于为无效电平,如果是固定的占空比则亮度是一样,所以需要周期变化ccr来变化占空比达到呼吸灯的效果,所以需要修改CCR

思路一:在主循环改变CCR

思路二:通过定时器中断触发改变CCR

void Pwm_Timer_Init(void)

{

    // 初始化定时器2
    g_pwm_timer1.Instance = TIM2;
    g_pwm_timer1.Init.Prescaler = 72 - 1; // 72M分频系数
    g_pwm_timer1.Init.Period = 500 - 1; // ARR
    g_pwm_timer1.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&g_pwm_timer1);

    // 配置pwm通道
    TIM_OC_InitTypeDef sConfigOC;
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = (500 - 1) / 2; // 初始化占空比为50% ---CCR
    sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
    HAL_TIM_PWM_ConfigChannel(&g_pwm_timer1, &sConfigOC, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&g_pwm_timer1, TIM_CHANNEL_2);
    HAL_TIM_Base_Start_IT(&g_pwm_timer1);
}

  

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        // Enable the TIM6 clock
        __HAL_RCC_TIM2_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();

        // 初始化GPIOA1
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.Pin = GPIO_PIN_1;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
        // Configure the NVIC for TIM6
        HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
        HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
    }
}

  
void TIM2_IRQHandler(void)
{
    // Handle the timer interrupt here
    HAL_TIM_IRQHandler(&g_pwm_timer1);
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    // Handle the timer period elapsed callback here
    if(htim->Instance == TIM2)
    {
        static uint16_t ledrpwmval = 0;
        static uint8_t dir = 1;
        if (dir)ledrpwmval++;              
        else ledrpwmval--;                  
        if (ledrpwmval > 300)dir = 0;      
        if (ledrpwmval == 0)dir = 1;
        __HAL_TIM_SET_COMPARE(Pwm_Timer_Get_Handle(), TIM_CHANNEL_2, ledrpwmval);
    }
}

  
TIM_HandleTypeDef* Pwm_Timer_Get_Handle(void)
{
    return &g_pwm_timer1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值