STM32学习之路——通用定时器库函数分析(为产生PWM)

产生PWM的必要流程

一、使能GPIOA和TIM2外设。
两个外设别挂接在APB1和APB2总线上,所以需要分别调用下面两条库函数指令。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,DISABLE);

分析:该指令的作用是APB总线上的外设的使能

二、对GPIOA进行配置。
我使用的是TIM2,TIM2有四个输出通道(TIM2_CH1,TIM2CH2,TIM2_CH3,TIM2_CH4)分别于PA.0,PA.1,PA.2,PA.3引脚复用,所以对GPIOA进行配置如下:

	GPIO_Structure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_Structure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Structure.GPIO_Pin=GPIO_Pin_0;
	GPIO_Init(GPIOA,&GPIO_Structure);

这里只对TIM2_CH1通道进行输出,所以把PA.0配置成为复用输出

三、讲TIM2进行初始化。

	TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV4;
	TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TimeBaseStructure.TIM_Period=899;
	TimeBaseStructure.TIM_Prescaler=0;
	TIM_TimeBaseInit(TIM2,&TimeBaseStructure);

分析:下面是TIM_TimeBaseInit函数定义

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); //
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));
//检验以上三个变量是否符合规定,符合就往下执行,不符合就报错
  tmpcr1 = TIMx->CR1;//控制寄存器1,主要控制着计数器的工作方式

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));//控制寄存器1上的DIR于CMS位,分别控制计数器的计数方向和对齐方式
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;//把我们定义的TIM_CounterMode_Up实际上就是0x0000,与其相或,进而使DIR和CMS位达到我们的想要的设定。此时的设定为位边缘对齐模式和向上计数
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));//控制寄存器1上的CKD位,是选择时钟分频因子
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;//对CKD位进行赋值,
  }

  TIMx->CR1 = tmpcr1;//将设定的值赋值到控制寄存器1中

  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;//ARR为自动重装载寄存器,将值赋予其中,在这里的值为899,功能:计数器从零开始计数,在达到899是归零,在重新计数,以此往复
 
  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;//PSC为预分频器,功能:控制计数器计数的频率,计数频率=fCK_PSC/(PSC存储的数值+1)
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }//我们的定时器选择的是TIM2,所以这段语句直接跳过

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;//EGR为时间产生寄存器,这里使用的是默认值,也就是0x0000,没有使用    。   
}

四、设置 TIM2_CH1 的 PWM 模式及通道方向, 使能 TIM1 的 CH1 输出。

	Tim_OCInitypeStructure.TIM_OCMode=TIM_OCMode_PWM2;
	Tim_OCInitypeStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	Tim_OCInitypeStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM2,&Tim_OCInitypeStructure);

分析:下面是TIM_OC1Init函数定义。

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
{
  uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
   
  /* Check the parameters */
  assert_param(IS_TIM_LIST8_PERIPH(TIMx));
  assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
  assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
  assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));   
 /* Disable the Channel 1: Reset the CC1E Bit */
  TIMx->CCER &= (uint16_t)(~(uint16_t)TIM_CCER_CC1E);//将CCER(捕获/比较使能寄存器)上的CC1E位置1,开启- OC1信号输出到对应的输出引脚。
  /* Get the TIMx CCER register value */
  tmpccer = TIMx->CCER;
  /* Get the TIMx CR2 register value */
  tmpcr2 =  TIMx->CR2;//CR2为控制寄存器2
  
  /* Get the TIMx CCMR1 register value */
  tmpccmrx = TIMx->CCMR1;//CCMR1为捕获/比较模式寄存器1
    
  /* Reset the Output Compare Mode Bits */
  tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_OC1M));
  tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_CC1S));
  //CCMR1上的OC1M三位控制的是输出比较模式,CC1S两位控制的是通道的方向(输入/输出),及输入脚的选择

  /* Select the Output Compare Mode */
  tmpccmrx |= TIM_OCInitStruct->TIM_OCMode;
  
  /* Reset the Output Polarity level */
  tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1P));
  /* Set the Output Compare Polarity */
  tmpccer |= TIM_OCInitStruct->TIM_OCPolarity;
  
  /* Set the Output State */
  tmpccer |= TIM_OCInitStruct->TIM_OutputState;
  //将我们的设定值分别赋值给这几个变量  
  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)||
     (TIMx == TIM16)|| (TIMx == TIM17))
  {
    assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState));
    assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity));
    assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState));
    assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
    
    /* Reset the Output N Polarity level */
    tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NP));
    /* Set the Output N Polarity */
    tmpccer |= TIM_OCInitStruct->TIM_OCNPolarity;
    
    /* Reset the Output N State */
    tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NE));    
    /* Set the Output N State */
    tmpccer |= TIM_OCInitStruct->TIM_OutputNState;
    
    /* Reset the Output Compare and Output Compare N IDLE State */
    tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1));
    tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1N));
    
    /* Set the Output Idle state */
    tmpcr2 |= TIM_OCInitStruct->TIM_OCIdleState;
    /* Set the Output N Idle state */
    tmpcr2 |= TIM_OCInitStruct->TIM_OCNIdleState;
  }//我们选择的是TIM2,所以该条件跳过
  /* Write to TIMx CR2 */
  TIMx->CR2 = tmpcr2;
  
  /* Write to TIMx CCMR1 */
  TIMx->CCMR1 = tmpccmrx;

  /* Set the Capture Compare Register value */
  TIMx->CCR1 = TIM_OCInitStruct->TIM_Pulse; 
 
  /* Write to TIMx CCER */
  TIMx->CCER = tmpccer;
  //分别将变量里的值赋值给这几寄存器,完成设定
}

五、前面只是完成了计数器的计数模式的配置,输出通道的输出模式配置,此时需要对计数器进行使能操作,开始进行计数。

	TIM_Cmd(TIM2,ENABLE);

分析:下面是TIM_Cmd函数定义

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if (NewState != DISABLE)
  {
    /* Enable the TIM Counter */
    TIMx->CR1 |= TIM_CR1_CEN;//将控制寄存器1上的CEN为置1,功能:使能计数器。
  }
  else
  {
    /* Disable the TIM Counter */
    TIMx->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
  }
}

六、需要了解的PWM输出原理。
在这里,我们设定的TIM2_CH1输出模式为PWM模式2-,在该模式下就有,当计数器内的值<CCR1(捕获/比较寄存器1)内的值是,输出为低电平,当计数器内的值>=CCR1(捕获/比较寄存器1)内的值是,输出为高电平。
所以此时我们想要得到脉冲输出的话,就需要对CCR1进行赋值,此时我选择的是计数器设定值得一半,也就是450,调用的函数如下:

TIM_SetCompare1(TIM2,450);

七、得到的PWM输出
在这里插入图片描述

发布了2 篇原创文章 · 获赞 1 · 访问量 50
展开阅读全文
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览