STM32CubeMX第五篇之PWM

前言

本文主要讲解自己实现的PWM程序。借鉴了正点原子程序的实现方法。关于正点原子的程序详细讲解,可以参考博客<STM32F429第二十一篇之PWM波实现详解>。

相对于正点原子的实验,本文程序的功能有三处不同:

  1. 通过高级时钟TIM1的通道1实现。
  2. 将单通道PWM拓展为双通道PWM。
  3. 加入刹车(断路)功能。

本文使用的HAL库的版本为:STM32Cube_FW_F4_V1.25.0
本文使用的STM32CubeMX版本为:6.1.1

该工程的下载地址为:

结构体

TIM_BreakDeadTimeConfigTypeDef

/**
  * @brief  TIM Break input(s) and Dead time configuration Structure definition
  * @note   2 break inputs can be configured (BKIN and BKIN2) with configurable
  *        filter and polarity.
  */
typedef struct
{
  uint32_t OffStateRunMode;      /*!< TIM off state in run mode
                                      This parameter can be a value of @ref TIM_OSSR_Off_State_Selection_for_Run_mode_state */
  uint32_t OffStateIDLEMode;     /*!< TIM off state in IDLE mode
                                      This parameter can be a value of @ref TIM_OSSI_Off_State_Selection_for_Idle_mode_state */
  uint32_t LockLevel;            /*!< TIM Lock level
                                      This parameter can be a value of @ref TIM_Lock_level */
  uint32_t DeadTime;             /*!< TIM dead Time
                                      This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF */
  uint32_t BreakState;           /*!< TIM Break State
                                      This parameter can be a value of @ref TIM_Break_Input_enable_disable */
  uint32_t BreakPolarity;        /*!< TIM Break input polarity
                                      This parameter can be a value of @ref TIM_Break_Polarity */
  uint32_t BreakFilter;          /*!< Specifies the break input filter.
                                      This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */
  uint32_t AutomaticOutput;      /*!< TIM Automatic Output Enable state
                                      This parameter can be a value of @ref TIM_AOE_Bit_Set_Reset */
} TIM_BreakDeadTimeConfigTypeDef;

OffStateRunMode(运行模式关闭状态)

该参数用于设置运行状态下,不使能的通道输出状态,可以选择的参数为:

/** @defgroup TIM_OSSR_Off_State_Selection_for_Run_mode_state TIM OSSR OffState Selection for Run mode state
  * @{
  */
#define TIM_OSSR_ENABLE                          TIM_BDTR_OSSR                  /*!< When inactive, OC/OCN outputs are enabled (still controlled by the timer)           */
#define TIM_OSSR_DISABLE                         0x00000000U                    /*!< When inactive, OC/OCN outputs are disabled (not controlled any longer by the timer) */
/**
  * @}
  */

在这里插入图片描述

OffStateIDLEMode(空闲状态关闭)

/** @defgroup TIM_OSSI_Off_State_Selection_for_Idle_mode_state TIM OSSI OffState Selection for Idle mode state
  * @{
  */
#define TIM_OSSI_ENABLE                          TIM_BDTR_OSSI                  /*!< When inactive, OC/OCN outputs are enabled (still controlled by the timer)           */
#define TIM_OSSI_DISABLE                         0x00000000U                    /*!< When inactive, OC/OCN outputs are disabled (not controlled any longer by the timer) */
/**
  * @}
  */

在这里插入图片描述

LockLevel(上锁等级)

/** @defgroup TIM_Lock_level  TIM Lock level
  * @{
  */
#define TIM_LOCKLEVEL_OFF                  0x00000000U                          /*!< LOCK OFF     */
#define TIM_LOCKLEVEL_1                    TIM_BDTR_LOCK_0                      /*!< LOCK Level 1 */
#define TIM_LOCKLEVEL_2                    TIM_BDTR_LOCK_1                      /*!< LOCK Level 2 */
#define TIM_LOCKLEVEL_3                    TIM_BDTR_LOCK                        /*!< LOCK Level 3 */
/**
  * @}
  */

在这里插入图片描述

DeadTime(死区时间)

该参数可以设置范围为0~255。
在这里插入图片描述

BreakState(断路状态)

/** @defgroup TIM_Break_Input_enable_disable TIM Break Input Enable
  * @{
  */
#define TIM_BREAK_ENABLE                   TIM_BDTR_BKE                         /*!< Break input BRK is enabled  */
#define TIM_BREAK_DISABLE                  0x00000000U                          /*!< Break input BRK is disabled */
/**
  * @}
  */

在这里插入图片描述

BreakPolarity(断路极性)

/** @defgroup TIM_Break_Polarity TIM Break Input Polarity
  * @{
  */
#define TIM_BREAKPOLARITY_LOW              0x00000000U                          /*!< Break input BRK is active low  */
#define TIM_BREAKPOLARITY_HIGH             TIM_BDTR_BKP                         /*!< Break input BRK is active high */
/**
  * @}
  */

在这里插入图片描述

BreakFilter(断路滤波器)

该参数的取值范围为:0~15.此参数在目前版本的HAL库中,并没有什么作用。

AutomaticOutput(自动输出使能)

/** @defgroup TIM_AOE_Bit_Set_Reset TIM Automatic Output Enable
  * @{
  */
#define TIM_AUTOMATICOUTPUT_DISABLE        0x00000000U                          /*!< MOE can be set only by software */
#define TIM_AUTOMATICOUTPUT_ENABLE         TIM_BDTR_AOE                         /*!< MOE can be set by software or automatically at the next update event 
                                                                                    (if none of the break inputs BRK and BRK2 is active) */
/**
  * @}
  */

在这里插入图片描述

HAL解析

和正点原子配置相比,本程序只是多用了一个HAL库函数,其定义如下:

/**
  * @brief  Configures the Break feature, dead time, Lock level, OSSI/OSSR State
  *         and the AOE(automatic output enable).
  * @param  htim TIM handle
  * @param  sBreakDeadTimeConfig pointer to a TIM_ConfigBreakDeadConfigTypeDef structure that
  *         contains the BDTR Register configuration  information for the TIM peripheral.
  * @note   Interrupts can be generated when an active level is detected on the
  *         break input, the break 2 input or the system break input. Break
  *         interrupt can be enabled by calling the @ref __HAL_TIM_ENABLE_IT macro.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef *htim,
                                                TIM_BreakDeadTimeConfigTypeDef *sBreakDeadTimeConfig)
{
  /* Keep this variable initialized to 0 as it is used to configure BDTR register */
  uint32_t tmpbdtr = 0U;

  /* Check the parameters */
  assert_param(IS_TIM_BREAK_INSTANCE(htim->Instance));
  assert_param(IS_TIM_OSSR_STATE(sBreakDeadTimeConfig->OffStateRunMode));
  assert_param(IS_TIM_OSSI_STATE(sBreakDeadTimeConfig->OffStateIDLEMode));
  assert_param(IS_TIM_LOCK_LEVEL(sBreakDeadTimeConfig->LockLevel));
  assert_param(IS_TIM_DEADTIME(sBreakDeadTimeConfig->DeadTime));
  assert_param(IS_TIM_BREAK_STATE(sBreakDeadTimeConfig->BreakState));
  assert_param(IS_TIM_BREAK_POLARITY(sBreakDeadTimeConfig->BreakPolarity));
  assert_param(IS_TIM_AUTOMATIC_OUTPUT_STATE(sBreakDeadTimeConfig->AutomaticOutput));

  /* Check input state */
  __HAL_LOCK(htim);

  /* Set the Lock level, the Break enable Bit and the Polarity, the OSSR State,
     the OSSI State, the dead time value and the Automatic Output Enable Bit */

  /* Set the BDTR bits */
  MODIFY_REG(tmpbdtr, TIM_BDTR_DTG, sBreakDeadTimeConfig->DeadTime);
  MODIFY_REG(tmpbdtr, TIM_BDTR_LOCK, sBreakDeadTimeConfig->LockLevel);
  MODIFY_REG(tmpbdtr, TIM_BDTR_OSSI, sBreakDeadTimeConfig->OffStateIDLEMode);
  MODIFY_REG(tmpbdtr, TIM_BDTR_OSSR, sBreakDeadTimeConfig->OffStateRunMode);
  MODIFY_REG(tmpbdtr, TIM_BDTR_BKE, sBreakDeadTimeConfig->BreakState);
  MODIFY_REG(tmpbdtr, TIM_BDTR_BKP, sBreakDeadTimeConfig->BreakPolarity);
  MODIFY_REG(tmpbdtr, TIM_BDTR_AOE, sBreakDeadTimeConfig->AutomaticOutput);


  /* Set TIMx_BDTR */
  htim->Instance->BDTR = tmpbdtr;

  __HAL_UNLOCK(htim);

  return HAL_OK;
}

该函数十分简单,将结构体中的成员直接写入到寄存器中即可。不再详细分析。

keil版本

主函数

/**
  ******************************************************************************
  * @file    main.c
  * @author  zhy
  * @version 1.0
  * @date    2021-02-22
  * @brief   用于生成pwm波
  ******************************************************************************
  */

#include "stm32f4xx_hal.h"
#include "sys.h"
#include "pwm.h"

uint16_t compare = 9000;
int main()
{
    /* 1.系统初始化 */
    HAL_Init();
    SystemClock_Config();
    PwmInit();

    /* 2.设置占空比 */
    while (1)
    {
        PwmSetCompare(compare);
    }
}

与正点原子不同,本文通过调试时,修改变量compare值来修改PWM波的占空比。

PWM配置相关

/**
  ******************************************************************************
  * @file    pwm.c
  * @author  zhy
  * @version 1.0
  * @date    2021-02-22
  * @brief   通过高级定时器配置双通道PWM
  ******************************************************************************
  */

#include "stm32f4xx_hal.h"
#include "pwm.h"

/** 
 * @brief PWM配置
 * @note 高级寄存器TIM1的通道1
 * @param {*}无
 * @retval 无
 */
void PwmInit(void)
{
    /* 1.使能TIM1的时钟 */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* 2.PWM时钟初始化 */
    TIM_HandleTypeDef htim1;                                   //定时器1句柄
    htim1.Instance = TIM1;                                     //定时器1
    htim1.Channel = HAL_TIM_ACTIVE_CHANNEL_1;                  //活跃通道:通道1.
    htim1.State = HAL_TIM_STATE_RESET;                         //初始化状态
    htim1.Lock = HAL_UNLOCKED;                                 //无锁
    htim1.Init.Prescaler = 1 - 1;                              //此处不分频,提高PWM的精度
    htim1.Init.Period = 18000 - 1;                             //PWM的频率为10K
    htim1.Init.AutoReloadPreload = TIM_AUTOMATICOUTPUT_ENABLE; //启用ARR影子寄存器
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;         //死区发生器与采样频率的分频数
    htim1.Init.RepetitionCounter = 0;                          //重复次数1
    HAL_TIM_PWM_Init(&htim1);                                  //初始化定时器1的通道1

    /* 3.PWM输出通道初始化 */
    TIM_OC_InitTypeDef ocInit;
    ocInit.OCMode = TIM_OCMODE_PWM1;              //pwm1模式
    ocInit.OCPolarity = TIM_OCPOLARITY_HIGH;      //高电平有效
    ocInit.OCNPolarity = TIM_OCPOLARITY_HIGH;     //高电平有效
    ocInit.OCIdleState = TIM_OCIDLESTATE_RESET;   //闲置状态:低
    ocInit.OCNIdleState = TIM_OCNIDLESTATE_RESET; //闲置状态:低
    ocInit.Pulse = 9000;                          //占空比50%
    ocInit.OCFastMode = TIM_OCFAST_DISABLE;       //不启动快速响应
    HAL_TIM_PWM_ConfigChannel(&htim1, &ocInit, TIM_CHANNEL_1);

    /* 4.配置死区与断路 */
    TIM_BreakDeadTimeConfigTypeDef timBreakDead;
    timBreakDead.OffStateRunMode = TIM_OSSR_DISABLE;           //禁止OSSR
    timBreakDead.OffStateIDLEMode = TIM_OSSI_ENABLE;           //使能OSSI
    timBreakDead.LockLevel = TIM_LOCKLEVEL_OFF;                //关闭上锁等级
    timBreakDead.DeadTime = 0;                                 //死区时间为0
    timBreakDead.BreakState = TIM_BREAK_ENABLE;                //使能断路
    timBreakDead.BreakPolarity = TIM_BREAKPOLARITY_HIGH;       //高电平有效
    timBreakDead.BreakFilter = 0;                              //不使用滤波器
    timBreakDead.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; //自动断路使能
    HAL_TIMEx_ConfigBreakDeadTime(&htim1, &timBreakDead);

    /* 5.启动PWM */
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
}

/** 
 * @brief PWM底层驱动配置
 * @note    1.此函数在HAL_TIM_PWM_Init中调用
 *          2.使用PA7与PA8管脚
 * @param {*} 定时器句柄
 * @retval 无
 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    /* 1.启动时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* 2.GPIOA初始化 */
    GPIO_InitTypeDef gpioInit;
    gpioInit.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8; //pin6,7,8
    gpioInit.Pull = GPIO_PULLDOWN;                       //上拉
    gpioInit.Speed = GPIO_SPEED_HIGH;                    //快速
    gpioInit.Mode = GPIO_MODE_AF_PP;                     //复用推挽
    gpioInit.Alternate = GPIO_AF1_TIM1;                  //复用为TIM1通道接口
    HAL_GPIO_Init(GPIOA, &gpioInit);                     //PA6,PA7,PA8
}

/** 
 * @brief 设置比较值
 * @note 用于Tim1的通道1
 * @param {uint16_t} c 比较寄存器的值
 * @retval 
 */
void PwmSetCompare(uint16_t c)
{
    TIM1->CCR1 = c;
}

与正点原子相比,程序中多了刹车功能,通过PA6实现。而且配置互补通道。

CUBE版本

此部分主要介绍与PWM配置相关内容,这部分内容是通过Cube自动生成的,时钟配置的源代码如下:

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

    /* USER CODE BEGIN TIM1_Init 0 */

    /* USER CODE END TIM1_Init 0 */

    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_OC_InitTypeDef sConfigOC = {0};
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

    /* USER CODE BEGIN TIM1_Init 1 */

    /* USER CODE END TIM1_Init 1 */
    /* 1.PWM时钟初始化 */
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 0;
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 17999;
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
    {
        Error_Handler();
    }
    /* 2.同步设置 */
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }
    /* 3.PAM通道初始化 */
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 9000;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
    {
        Error_Handler();
    }
    /* 4.PWM死区与断路设置 */
    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
    sBreakDeadTimeConfig.DeadTime = 0;
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
    if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN TIM1_Init 2 */

    /* USER CODE END TIM1_Init 2 */
    /* 5.PWM输出管脚配置 */
    HAL_TIM_MspPostInit(&htim1);
}

通过对比可以发现:

  1. 该代码多了同步设置的而配置,在注释的第二部分。由于此部分是禁用状态,所以,在keil写代码没有明确配置。
  2. 定时器句柄部分,只设置了初始化相关的参数。
  3. 没有启动PWM,该部分需要自己在main函数调用。
  4. 将PWM输出管脚底层配置通过HAL_TIM_MspPostInit实现。底层配置分成两个函数,定义如下:
/**
* @brief TIM_PWM MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_pwm: TIM_PWM handle pointer
* @retval None
*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim_pwm->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */

  /* USER CODE END TIM1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration
    PA6     ------> TIM1_BKIN
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM1_MspInit 1 */

  /* USER CODE END TIM1_MspInit 1 */
  }

}

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspPostInit 0 */

  /* USER CODE END TIM1_MspPostInit 0 */

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration
    PA7     ------> TIM1_CH1N
    PA8     ------> TIM1_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM1_MspPostInit 1 */

  /* USER CODE END TIM1_MspPostInit 1 */
  }

}

该部分程序与手写部分大同小异,不再详细介绍。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32CubeMX中配置灰度可以通过以下步骤完成: 1. 打开STM32CubeMX软件并创建一个新的工程。 2. 在"Pinout & Configuration"选项卡中,选择你的目标STM32芯片型号。 3. 在"Pinout & Configuration"选项卡中,选择你想要配置的引脚。 4. 在"Configuration"选项卡中,找到"TIMx"(x代表定时器的编号)并启用它。 5. 在"Configuration"选项卡中,找到"TIMx Channel y"(y代表定时器通道的编号)并启用它。 6. 在"Configuration"选项卡中,找到"TIMx Channel y Configuration"并选择"PWM Generation CHy"。 7. 在"Configuration"选项卡中,找到"TIMx Channel y Configuration"下的"Output Compare Mode"并选择"PWM Mode 1"。 8. 在"Configuration"选项卡中,找到"TIMx Channel y Configuration"下的"Output Compare Polarity"并选择"Active High"。 9. 在"Configuration"选项卡中,找到"TIMx Channel y Configuration"下的"Output Compare Pulse"并设置一个合适的占空比,以实现所需的灰度效果。 10. 在"Project"菜单中,选择"Generate Code"以生成HAL库代码。 11. 导入生成的代码到你的开发环境中,并编译、下载到STM32芯片中。 通过以上步骤,你可以在STM32CubeMX中配置灰度,并生成相应的HAL库代码来实现灰度控制。\[1\]\[2\] #### 引用[.reference_title] - *1* [第一章:STM32MxCube 基本使用方法](https://blog.csdn.net/xuquanlin_1680/article/details/80499977)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [STM32CUBEMX配置教程(一)基础配置](https://blog.csdn.net/weixin_44584198/article/details/118959294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值