打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

PWM 模式

脉冲宽度调制模式可以产生一个由 TIM1_ARR 寄存器确定频率、由 TIM1_CCRx 寄存器确定占空比的信号。
在 TIM1_CCMRx 寄存器中的 OCxM 位写入’110’(PWM 模式 1)或’111’(PWM 模式 2),能够独立地设置每个 OCx 输出通道产生一路 PWM。 必须通过设置 TIM1_CCMRx 寄存器的 OCxPE 位使能相应的预装载寄存器,最后还要设置 TIM1_CR1 寄存器的 ARPE 位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。

仅当发生一个更新事件的时候, 预装载寄存器才能被传送到影子寄存器, 因此在计数器开始计数之前,必须通过设置 TIM1_EGR 寄存器中的 UG 位来初始化所有的寄存器。
OCx 的极性可以通过软件在 TIM1_CCER 寄存器中的 CCxP 位设置,它可以设置为高电平有效或低电平有效。OCx 的输出使能通过(TIM1_CCER 和 TIM1_BDTR 寄存器中)CCxE、CCxNE、MOE、OSSI 和 OSSR 位的组合控制。详见 TIM1_CCER 寄存器的描述。

在 PWM 模式(模式 1 或模式 2)下,TIM1_CNT 和 TIM1_CCRx 始终在进行比较,(依据计数器的计数方向)以确定是否符合 TIM1_CCRx≤TIM1_CNT 或TIM1_CNT≤TIM1_CCRx。 根据TIM1_CR1寄存器中CMS位的状态, 定时器能够产生边沿对齐的PWM信号或中央对齐的PWM信号。

在这里插入图片描述

PWM 中央对齐模式
当 TIM1_CR1 寄存器中的 CMS 位不为’00’时为中央对齐模式(所有其他的配置对 OCxREF/OCx 信号都有相同的作用)。根据不同的 CMS 位设置,比较标志可以在计数器向上计数时被置 1、在计数器向下计数时被置 1、 或在计数器向上和向下计数时被置 1。 TIM1_CR1 寄存器中的计数方向位(DIR)由硬件更新,不要用软件修改它。
下图给出了一些中央对齐的 PWM 波形的例子
⚫ TIM1_ARR=8
⚫ PWM 模式 1
⚫ TIM1_CR1 寄存器的 CMS=01,在中央对齐模式 1 下,当计数器向下计数时设置比较标志。
在这里插入图片描述
使用中央对齐模式的提示:
⚫ 进入中央对齐模式时, 使用当前的向上/向下计数配置。 这就意味着计数器向上还是向下计数取决于 TIM1_CR1 寄存器中 DIR 位的当前值。此外,软件不能同时修改 DIR 和 CMS 位。
⚫ 不推荐当运行在中央对齐模式时改写计数器,因为这会产生不可预知的结果。特别地:

  • 如果写入计数器的值大于自动重加载的值(TIM1_CNT>TIM1_ARR),则方向不会被更新。
    例如,如果计数器正在向上计数,它就会继续向上计数。
  • 如果将 0 或者 TIM1_ARR 的值写入计数器,方向被更新,但不产生更新事件 UEV。

⚫ 使用中央对齐模式最保险的方法,就是在启动计数器之前产生一个软件更新(设置 TIM1_EGR位中的 UG 位),并且不要在计数进行过程中修改计数器的值。

/********************************************************************************
* @file    bsp_pwm.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-18
* @brief   NULL
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_gpio.h"
#include "bsp_tim.h"
#include "bsp_pwm.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Variables ---------------------------------------------------------*/
static bool g_pwm_init = false;

#if BS_TIM1_EN
extern TIM_HandleTypeDef tim1_handle_t;
extern TIM_OC_InitTypeDef tim1_oc_init_handle_t;
#endif

/* Public function prototypes -----------------------------------------------*/
/**
 * @brief  PWN功能初始化,使用定时器和ppi来模拟PWM功能
 * @note   NULL
 * @retval None
 */
void bsp_pwm_init(void)
{
    if (g_pwm_init)
    {
        return;
    }
#if BS_TIM1_EN
    bsp_tim_pwm_init();
	g_pwm_init = true;
#endif
}

/**
 * @brief  PWN功能关闭
 * @note   NULL
 * @retval None
 */
void bsp_pwm_deinit(void)
{
    if (!g_pwm_init)
    {
        return;
    }
#if BS_TIM1_EN
	bsp_tim_pwm_deinit();
    g_pwm_init = false;
#endif
}

/**
 * @brief  设置PWM占空比
 * @note   NULL
 * @param  pwmx: PWM组号
 * @param  val: 0-100 PWM值
 * @retval None
 */
void bsp_pwm_set_pulse(bsp_pwm_t pwmx, uint16_t val)
{
    if (!g_pwm_init)
    {
        return;
    }
    if (pwmx == BSP_PWM_0)
    {
#if BS_TIM1_EN && BS_PWM0_EN
        HAL_TIM_PWM_Stop(&tim1_handle_t, TIM_CHANNEL_1);
        tim1_oc_init_handle_t.Pulse = val;
        HAL_TIM_PWM_ConfigChannel(&tim1_handle_t, &tim1_oc_init_handle_t, TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&tim1_handle_t, TIM_CHANNEL_1);
#endif
    }
    else if (pwmx == BSP_PWM_1)
    {
#if BS_TIM1_EN && BS_PWM1_EN
        HAL_TIM_PWM_Stop(&tim1_handle_t, TIM_CHANNEL_2);
        tim1_oc_init_handle_t.Pulse = val;
        HAL_TIM_PWM_ConfigChannel(&tim1_handle_t, &tim1_oc_init_handle_t, TIM_CHANNEL_2);
        HAL_TIM_PWM_Start(&tim1_handle_t, TIM_CHANNEL_2);
#endif
    }
    else if (pwmx == BSP_PWM_2)
    {
#if BS_TIM1_EN && BS_PWM2_EN
        HAL_TIM_PWM_Stop(&tim1_handle_t, TIM_CHANNEL_3);
        tim1_oc_init_handle_t.Pulse = val;
        HAL_TIM_PWM_ConfigChannel(&tim1_handle_t, &tim1_oc_init_handle_t, TIM_CHANNEL_3);
        HAL_TIM_PWM_Start(&tim1_handle_t, TIM_CHANNEL_3);
#endif
    }
    else if (pwmx == BSP_PWM_3)
    {
#if BS_TIM1_EN && BS_PWM3_EN
        HAL_TIM_PWM_Stop(&tim1_handle_t, TIM_CHANNEL_4);
        tim1_oc_init_handle_t.Pulse = val;
        HAL_TIM_PWM_ConfigChannel(&tim1_handle_t, &tim1_oc_init_handle_t, TIM_CHANNEL_4);
        HAL_TIM_PWM_Start(&tim1_handle_t, TIM_CHANNEL_4);
#endif
    }
}

/********************************************************************************
* @file    bsp_pwm.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-18
* @brief   NULL
********************************************************************************/

#ifndef __BSP_PWM_H
#define __BSP_PWM_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>

/* Public enum ---------------------------------------------------------------*/
typedef enum
{
    BSP_PWM_0 = 0,
    BSP_PWM_1,
    BSP_PWM_2,
    BSP_PWM_3,
    BSP_PWM_4,
    BSP_PWM_5,
    BSP_PWM_6,
    BSP_PWM_7,
    BSP_PWM_8,
    BSP_PWM_9,
    BSP_PWM_10,
    BSP_PWM_11
} bsp_pwm_t;

/* Public Function Prototypes ------------------------------------------------*/

void bsp_pwm_init(void);
void bsp_pwm_deinit(void);

void bsp_pwm_set_pulse(bsp_pwm_t pwmx, uint16_t val);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(119)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033