我是靠谱客的博主 陶醉微笑,最近开发中收集的这篇文章主要介绍STM32通用定时器(二)之PWM输出(2)——今天聊聊PWM输出的初始化配置,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

三、初始化分析(以TIM2为例)

0,前文

首先,我们使用PWM,必须要关注到如下两个指标:

(1)周期是多少(或者说这个信号的频率)

(2)占空比是多少(占空比 = 高电平时间 / 周期)

(3)输出的极性是先高后低还是先低后高

有了以上的认识,我们再进一步进行初始化分析。

1,GPIO配置

首先需要查看我们的通道对应的引脚:位于《STM32中文手册》的 ” 定时器复用功能重映射 “ 章节,如图

在这里插入图片描述

TIM2的功能引脚如图所示

在这里插入图片描述

唯一需要提醒的是因为GPIO是功能复用成PWM的通道1的,所以输出必须复用,这里需要将GPIO设置成复用推挽。

示例如下。

/*******************************************************************************
 函数名称: LED_GPIO_Configuration
 函数说明: 初始GPIOA端口 
 输入参数: 无  
 返 回 值: 无  
*******************************************************************************/
void GPIO_Configuration(void)
{ 
	GPIO_InitTypeDef  GPIO_InitStructure;	                     //定义一个结构体变量GPIO_InitStructure

  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;//PA0-PA3引脚						                          
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;		         //配置GPIO模式—复用推挽输出
  GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;			     //配置GPIO端口速率—最高输出速率50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);                     //初始化GPIOA端口
}

2,时钟

​ 使用这样的外设的时候,特别是涉及了引脚功能复用的时候就记住这样的一句话:“首先打开当前的GPIO的端口时钟,然后打开外设时钟”!

/*******************************************************************************
 函数名称: RCC_Configuration
 函数说明: 初始GPIOA端口时钟和定时器T2时钟 
 输入参数: 无  
 返 回 值: 无  
*******************************************************************************/
void RCC_Configuration(void)
{
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能APB1外设TIM2时钟 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		    //使能GPIOA端口时钟
}

3,配置时基

我们应该会非常熟悉这个函数了

(位于“stm32f10x_tim.c”的第 226~269 行)
TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)  //根据TIM_TimeBaseStructure中指定的参数初始化TIMx的时																				间基数单位

这里便不再进行过多的分析了,详细的可以参考阅读本书的基本定时器部分的初始化分析部分。

配置时基的示例如下:

  TIM_TimeBaseInitTypeDef   TIM_BaseInitStructure; 	           //定时器时基初始化结构
  
  /* 配置时间基 */
  TIM_BaseInitStructure.TIM_Period = ARR_Val;          		     //定时器计数的最大值,其计数周期为8000
  TIM_BaseInitStructure.TIM_Prescaler = 2  ;       		         //内部时钟CK_INT经3分频后,得到定时时钟CK_CNT
  TIM_BaseInitStructure.TIM_ClockDivision = 0;      		       //采样分频,分频系数为1
  TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_BaseInitStructure);			         //根据TIM_TimeBaseStructure中指定的参数初始化TIM2的时间基数单位

4,配置通道(以TIM2的通道1为例)

TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
(位于“stm32f10x_tim.c”第 279~351 行)    
TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
(位于“stm32f10x_tim.c”第 1509~1522 行)

​ 根据这两个函数的内部的assert_param函数的提示可得我们需要配置如下三块变量

—— TIM_TypeDef* TIMx
—— TIM_OCInitTypeDef* TIM_OCInitStruct
—— uint16_t TIM_OCPreload

a,TIM_TypeDef* TIMx

(节选自“stm32f10x_tim.h”第 250~265 行)

/* LIST8: TIM 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16 and 17 */                                        
#define IS_TIM_LIST8_PERIPH(PERIPH)  (((PERIPH) == TIM1) || 
                                      ((PERIPH) == TIM2) || 
                                      ((PERIPH) == TIM3) || 
                                      ((PERIPH) == TIM4) || 
                                      ((PERIPH) == TIM5) || 
                                      ((PERIPH) == TIM8) || 
                                      ((PERIPH) == TIM9) || 
                                      ((PERIPH) == TIM10)|| 
                                      ((PERIPH) == TIM11)|| 
                                      ((PERIPH) == TIM12)|| 
                                      ((PERIPH) == TIM13)|| 
                                      ((PERIPH) == TIM14)|| 
                                      ((PERIPH) == TIM15)|| 
                                      ((PERIPH) == TIM16)|| 
                                      ((PERIPH) == TIM17))

​ 而本次由于我们使用的是定时器2,故而选择“ TIM2 ”

b,TIM_OCInitTypeDef* TIM_OCInitStruct

(节选自“stm32f10x_tim.h”第 80~109 行)
typedef struct
{
  uint16_t TIM_OCMode;        /*!< Specifies the TIM mode.
                                   This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */

  uint16_t TIM_OutputState;   /*!< Specifies the TIM Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_state */

  uint16_t TIM_OutputNState;  /*!< Specifies the TIM complementary Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_state
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_Pulse;         /*!< Specifies the pulse value to be loaded into the Capture Compare Register. 
                                   This parameter can be a number between 0x0000 and 0xFFFF */

  uint16_t TIM_OCPolarity;    /*!< Specifies the output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_Polarity */

  uint16_t TIM_OCNPolarity;   /*!< Specifies the complementary output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Polarity
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCIdleState;   /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCNIdleState;  /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */
} TIM_OCInitTypeDef;

​ 具体的参数解释参考比较输出的初始化部分。

​ 首先按惯例来说,碰到这样的结构体类的,我们需要建一个TIM_OCInitTypeDef结构体类型的TIM_OCInitStruct(你仔细观察函数 TIM_OC1Init 后的参数提醒会发现一些命名依据是ST帮你想好的)。

​ 然后对于本次的TIM2的通道1的PWM输出,我们仅仅需要配置的是如下的变量

—— TIM_OCMode
—— TIM_Pulse
—— TIM_OutputState
—— TIM_OCPolarity

​ 示例如下

  TIM_OCInitTypeDef  TIM_OCInitStructure;                      //输出通道初始化函数

  /* 配置通道1:PWM1模式 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;            //TIM2为PWM1输出模式
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;  					         //待装入输出比较寄存器中的脉冲值
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//通道1输出状态使能
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		 //TIM2输出有效电平为高电平
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);						         //根据TIM_OCInitStructure中指定的参数初始化TIM2

c,uint16_t TIM_OCPreload

(节选自“stm32f10x_tim.h”第 870~877 行)

/** @defgroup TIM_Output_Compare_Preload_State 
  * @{
  */

#define TIM_OCPreload_Enable               ((uint16_t)0x0008)
#define TIM_OCPreload_Disable              ((uint16_t)0x0000)
#define IS_TIM_OCPRELOAD_STATE(STATE) (((STATE) == TIM_OCPreload_Enable) || 
                                       ((STATE) == TIM_OCPreload_Disable))

很明显,只有使能和失能的选项。对于我们来说,我们是需要使能这个通道的,故而是“ TIM_OCPreload_Enable ”。

示例如下

TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);

d,通道配置示例

通道配置代码示例如下

  /* 配置通道1:PWM1模式 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;            //TIM2为PWM1输出模式
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;  					         //待装入输出比较寄存器中的脉冲值
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//通道1输出状态使能
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		 //TIM2输出有效电平为高电平
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);						         //根据TIM_OCInitStructure中指定的参数初始化TIM2
  TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);             //使能TIM2在CCR1上的预装载寄存器。以便在下一次更新事件
                                                               //发生时可以更新输出波形

5,关于NVIC的问题

因为PWM是直接自动翻转,暂时没有用上中断,所以我们不需要为其配置中断分组。

6,开启定时器

千万记得打开定时器

TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

第一个参数已经介绍过了,第二个的如下,仅有使能或不使能。

(节选自“stm32f10x.h”的第 521 ~522 行)
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))

示例如下

TIM_Cmd(TIM2, ENABLE);										                   //开启TIM2

7,定时器部分的初始化函数 TIM2_Configuration (配置4通道不同占空比的PWM输出)如下

/*******************************************************************************
 函数名称: RCC_Configuration
 函数说明: 初始GPIOA端口时钟和定时器T2时钟 
 输入参数: 无  
 返 回 值: 无  
*******************************************************************************/
void RCC_Configuration(void)
{
  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能APB1外设TIM2时钟 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		    //使能GPIOA端口时钟
}

/*******************************************************************************
 函数名称: LED_GPIO_Configuration
 函数说明: 初始GPIOA端口 
 输入参数: 无  
 返 回 值: 无  
*******************************************************************************/
void GPIO_Configuration(void)
{ 
	GPIO_InitTypeDef  GPIO_InitStructure;	                     //定义一个结构体变量GPIO_InitStructure

  	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;//PA0-PA3引脚						                          
 	GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;		         //配置GPIO模式—复用推挽输出
  	GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;			     //配置GPIO端口速率—最高输出速率50MHz
  	GPIO_Init(GPIOA, &GPIO_InitStructure);                     //初始化GPIOA端口
}

/*******************************************************************************
 函数名称: TIM2_Configuration
 函数说明: 定时器初始化函数
 输入参数: 无
 返 回 值: 无
*******************************************************************************/
void TIM2_Configuration(void)				                          
{
    TIM_TimeBaseInitTypeDef   TIM_BaseInitStructure; 	           //定时器时基初始化结构
  	TIM_OCInitTypeDef  TIM_OCInitStructure;                      //输出通道初始化函数
 	 /* 配置时间基 */
 	TIM_BaseInitStructure.TIM_Period = ARR_Val;          		     //定时器计数的最大值,其计数周期为8000
 	TIM_BaseInitStructure.TIM_Prescaler = 2  ;       		         //内部时钟CK_INT经3分频后,得到定时时钟CK_CNT
  	TIM_BaseInitStructure.TIM_ClockDivision = 0;      		       //采样分频,分频系数为1
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_BaseInitStructure);			         //根据TIM_TimeBaseStructure中指定的参数初始化TIM2的时间基数单位

    /* 配置通道1:PWM1模式 */
  	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;            //TIM2为PWM1输出模式
  	TIM_OCInitStructure.TIM_Pulse = CCR1_Val;  					         //待装入输出比较寄存器中的脉冲值
  	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//通道1输出状态使能
  	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		 //TIM2输出有效电平为高电平
  	TIM_OC1Init(TIM2, &TIM_OCInitStructure);						         //根据TIM_OCInitStructure中指定的参数初始化TIM2
  	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);             //使能TIM2在CCR1上的预装载寄存器。以便在下一次更新事件
                                                               //发生时可以更新输出波形
  	/* 配置通道2:PWM1模式 */
  	TIM_OCInitStructure.TIM_Pulse = CCR2_Val;  					         //待装入输出比较寄存器中的比较值
  	TIM_OC2Init(TIM2, &TIM_OCInitStructure); 						         //根据TIM_OCInitStructure中指定的参数初始TIM2
  	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);		         //使能TIM2在CCR2上的预装载寄存器

 	 /* 配置通道3:PWM1模式 */
 	TIM_OCInitStructure.TIM_Pulse = CCR3_Val;  					         //待装入输出比较寄存器中的比较值
 	TIM_OC3Init(TIM2, &TIM_OCInitStructure);						         //根据TIM_OCInitStructure中指定的参数初始TIM2
  	TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);			       //使能TIM2在CCR3上的预装载寄存器

  	/* 配置通道4:PWM1模式 */
  	TIM_OCInitStructure.TIM_Pulse = CCR4_Val;  					         //待装入输出比较寄存器中的比较值
  	TIM_OC4Init(TIM2, &TIM_OCInitStructure);						         //根据TIM_OCInitStructure中指定的参数初始TIM2
  	TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);			       //使能TIM2在CCR3上的预装载寄存器
  
 	TIM_Cmd(TIM2, ENABLE);										                   //开启TIM2  														
}

最后

以上就是陶醉微笑为你收集整理的STM32通用定时器(二)之PWM输出(2)——今天聊聊PWM输出的初始化配置的全部内容,希望文章能够帮你解决STM32通用定时器(二)之PWM输出(2)——今天聊聊PWM输出的初始化配置所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部