概述
三、初始化分析(以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输出的初始化配置所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复