发新帖我要提问
123
返回列表
打印
[应用相关]

[stm32] STM32的通用定时器TIMx系统了解

[复制链接]
楼主: features
手机看帖
扫描二维码
随时随地手机跟帖
41
  TIMx_CCMRx中的OCxPE位选择TIMx_CCRx寄存器是否需要使用预装载寄存器。
  在输出比较模式下,更新事件UEV对OCxREF和OCx输出没有影响。
  同步的精度可以达到计数器的一个计数周期。输出比较模式(在单脉冲模式下)也能用来输出一个单脉冲。
  输出比较模式的配置步骤:

1. 选择计数器时钟(内部,外部,预分频器)
2. 将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中
3. 如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。
4. 选择输出模式,例如当计数器CNT与CCRx匹配时翻转OCx的输出引脚, CCRx预装载未用,开启 OCx输出且高电平有效,则必须设置OCxM=’011’、 OCxPE=’0’、 CCxP=’0’和CCxE=’1’。
5. 设置TIMx_CR1 寄存器的CEN位启动计数器

使用特权

评论回复
42
peripheral| | 2020-1-1 18:06 | 只看该作者
  TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形,条件是未使用预装载寄存器(OCxPE=’0’,否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。下图给出了一个例子。


                  图30 输出比较模式,翻转OC1

使用特权

评论回复
43
peripheral| | 2020-1-1 18:07 | 只看该作者
3.9 PWM 模式

  脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。

  在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1 寄存器的ARPE位, (在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。

  仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置TIMx_EGR寄存器中的UG位来初始化所有的寄存器。
  OCx的极性可以通过软件在TIMx_CCER寄存器中的CCxP位设置,它可以设置为高电平有效或低电平有效。 TIMx_CCER寄存器中的CCxE位控制OCx输出使能。

使用特权

评论回复
44
peripheral| | 2020-1-1 18:07 | 只看该作者
  在PWM模式(模式1 或模式2)下, TIMx_CNT和TIMx_CCRx始终在进行比较, (依据计数器的计数方向 ) 以确 定是否符合 TIMx_CCRx≤ TIMx_CNT 或者 TIMx_CNT ≤ TIMx_CCRx 。然而为了与OCREF_CLR的功能(在下一个PWM周期之前,ETR信号上的一个外部事件能够清除OCxREF)一致,OCxREF信号只能在下述条件下产生:

● 当比较的结果改变
● 当输出比较模式(TIMx_CCMRx寄存器中的OCxM位)从“冻结” (无比较, OCxM=’000’)切换到某个PWM模式(OCxM=’110’或’111’)

  这样在运行中可以通过软件强置PWM输出。根据TIMx_CR1 寄存器中 CMS位的状态,定时器能够产生边沿对齐的PWM信号或中央对齐的PWM信号。

>_<" PWM 边沿对齐模式 (向上计数配置当TIMx_CR1 寄存器中的DIR位为低的时候执行向上计数。)

使用特权

评论回复
45
peripheral| | 2020-1-1 18:07 | 只看该作者
  下面是一个PWM模式1 的例子。当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高,否则为低。如果TIMx_CCRx中的比较值大于自动重装载值(TIMx_ARR),则OCxREF保持为’1’。
如果比较值为0,则OCxREF保持为’0’。 下图为TIMx_ARR=8时边沿对齐的PWM波形实例。



                图31 边沿对齐的PWM波形(ARR=8)

使用特权

评论回复
46
peripheral| | 2020-1-1 18:08 | 只看该作者
>_<" 向下计数的配置(当TIMx_CR1 寄存器的DIR位为高时执行向下计数。)

  在PWM模式1,当TIMx_CNT>TIMx_CCRx时参考信号OCxREF为低,否则为高。如果TIMx_CCRx中的比较值大于TIMx_ARR中的自动重装载值,则OCxREF保持为’1’。该模式下不能产生0%的PWM波形。

使用特权

评论回复
47
peripheral| | 2020-1-1 18:08 | 只看该作者
>_<" PWM 中央对齐模式(当TIMx_CR1 寄存器中的CMS位不为’00’时,为中央对齐模式(所有其他的配置对OCxREF/OCx信号都有相同的作用)。)

  根据不同的CMS位设置,比较标志可以在计数器向上计数时被置’1’、在计数器向下计数时被置’1’、或在计数器向上和向下计数时被置’1’。 TIMx_CR1 寄存器中的计数方向位(DIR)由硬件更新,不要用软件修改它。

● TIMx_ARR=8
● PWM模式1
● TIMx_CR1 寄存器中的CMS=01 ,在中央对齐模式1 时,当计数器向下计数时设置比较标志。


              图32 中央对齐的PWM波形(APR=8)

使用特权

评论回复
48
peripheral| | 2020-1-1 18:08 | 只看该作者
使用中央对齐模式的提示:

● 进入中央对齐模式时,使用当前的向上/向下计数配置;这就意味着计数器向上还是向下计数取决于TIMx_CR1 寄存器中DIR位的当前值。此外,软件不能同时修改DIR和CMS位。
● 不推荐当运行在中央对齐模式时改写计数器,因为这会产生不可预知的结果。特别地:
  ─ 如果写入计数器的值大于自动重加载的值(TIMx_CNT>TIMx_ARR),则方向不会被更新。
  例如,如果计数器正在向上计数,它就会继续向上计数。
  ─ 如果将0或者TIMx_ARR的值写入计数器,方向被更新,但不产生更新事件UEV。
● 使用中央对齐模式最保险的方法,就是在启动计数器之前产生一个软件更新(设置TIMx_EGR 位中的UG位),不要在计数进行过程中修改计数器的值。

使用特权

评论回复
49
peripheral| | 2020-1-1 18:09 | 只看该作者
3.10 单脉冲模式

  单脉冲模式(OPM)是前述众多模式的一个特例。这种模式允许计数器响应一个激励,并在一个程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
  可以通过从模式控制器启动计数器,在输出比较模式或者PWM模式下产生波形。设置TIMx_CR1寄存器中的OPM位将选择单脉冲模式,这样可以让计数器自动地在产生下一个更新事件UEV时停止。
  仅当比较值与计数器的初始值不同时,才能产生一个脉冲。启动之前(当定时器正在等待触发),必须如下配置:

向上计数方式: CNT < CCRx ≤ ARR (特别地, 0 < CCRx)
向下计数方式: CNT > CCRx



                  图33 单脉冲模式的例子

例如,你需要在从TI2输入脚上检测到一个上升沿开始,延迟tDELAY之后,在OC1 上产生一个长度为tPULSE的正脉冲。

使用特权

评论回复
50
peripheral| | 2020-1-1 18:09 | 只看该作者
四、简单例子理解TIMx

4.1 使得PB5-TIM3通道2产生频率为12.5Hz的方波,该方波控制LED1的闪烁

>_<" 主函数为:
int main(void)
{   
  RCC_Configuration();                        //系统时钟设置及外设时钟使能                        
  NVIC_Configuration();                         //中断源配置
  time_ini();                                 //定时器3的初始化
  while(1);
}

使用特权

评论回复
51
peripheral| | 2020-1-1 18:09 | 只看该作者
>_<" 配置各外设的时钟和系统时钟:(有些是多余的)
/****************************************************************************
* 名    称:void RCC_Configuration(void)
* 功    能:系统时钟配置为72MHZ, 外设时钟配置
****************************************************************************/
void RCC_Configuration(void){

  SystemInit();
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
                          | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOE , ENABLE);
}

使用特权

评论回复
52
peripheral| | 2020-1-1 18:09 | 只看该作者
>_<" 配置中断向量:(因为这里用到了TIM3,所以要配置其中断向量)
/****************************************************************************
* 名    称:void NVIC_Configuration(void)
* 功    能:中断源配置
****************************************************************************/
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

  NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn ;               //配置定时器中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);      
}

使用特权

评论回复
53
peripheral| | 2020-1-1 18:10 | 只看该作者
>_<" TIM3的2通道配置:(下面首先配置GPIO PB5(为Tim3的2通道),PB5引脚默认是作为通用IO口使用,为了产生特定频率,利用了该引脚可以复用为TIM3_CH2,根据手册,需要用到局部复用映射,才能将TIM3_CH2映射到PB5。)

使用特权

评论回复
54
peripheral| | 2020-1-1 18:10 | 只看该作者
在定时器3的初始化中,用到了输出比较2模式的翻转设置。也就是当TIM3_CCR2=TIM3_CNT时,翻转输出的电平。以产生需要的频率,TIM3_CCR2的值决定了翻转的频率。当TIM3_CCR2=TIM3_CNT时,产生一次电平翻转,并在中断服务程序里重新完成对TIM3_CCR2的装载。依次往复,产生了所需要的12.5Hz的频率。(注意注释的第15~17行介绍如何控制输出频率,CCR2_Val=45000)
void time_ini(void){
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);            //定时器3 时钟使能
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                        //PB5复用为TIM3的通道2
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* TIM3局部复用功能开启     在TIM3的局部复用开启时,PB5会被复用为TIM3_CH2*/
  GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE);   

  /* Time Base configuration */
  /*-------------------------------------------------------------------
  TIM3CLK=72MHz  预分频系数Prescaler=63 经过分频 定时器时钟为1.125MHz
  捕获/比较寄存器2 TIM3_CCR2= CCR2_Val
  2通道产生的更新频率是=1.125MHz/CCR2_Val=25Hz
   
  -------------------------------------------------------------------*/
  TIM3_TimeBaseStructure.TIM_Prescaler = 63;                        //预分频器TIM3_PSC=63     
  TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //计数器向上计数模式 TIM3_CR1[4]=0
  TIM3_TimeBaseStructure.TIM_Period =0xffff;                        //自动重装载寄存器TIM3_APR                  
  TIM3_TimeBaseStructure.TIM_ClockDivision = 0x0;                    //时钟分频因子 TIM3_CR1[9:8]=00

  TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseStructure);                    //写TIM3各寄存器参数
  
  TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle ;                //TIM3_CCMR1[14:12]=011  翻转 当TIM3_CCR2=TIM3_CNT时,翻转OC2REF的电平
  TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //输入/捕获2输出允许  OC2信号输出到对应的输出引脚PB5
  TIM3_OCInitStructure.TIM_Pulse =CCR2_Val;                            //若CC1通道配置为输出:CCR2是装入当前捕获/比较2 TIM3_CCR2寄存器的值(预装载值)。
                                                                      //当前捕获/比较寄存器包含了与计数器TIM3_CNT比较的值,并且在OC端口上输出信号
  TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            //输出极性  低电平有效 TIM3_CCER[5]=1;

  TIM_OC2Init(TIM3, &TIM3_OCInitStructure);
  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);                //TIM3_CCMR1[1]=0  禁止TIM3_CCR2寄存器的预装载功能,可随时写入TIM3_CCR2
                                                                    //且新值马上起作用

   TIM_Cmd(TIM3,ENABLE);                                            //启动定时器3 TIM3_CR1[0]=1;  
   TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE);                             //TIM3_DIER[2]=1  允许捕获/比较2中断
}

使用特权

评论回复
55
peripheral| | 2020-1-1 18:10 | 只看该作者
>_<" TIM3的中断服务子程序(每次TIM3_CCR2=TIM3_CNT产生一次中断,在中断子程序中取出上一次的TIM3_CCR2加上CCR2_Val作为新的TIM3_CCR2,这样等TIM3_CNT加到和TIM3_CCR2相等时又会触发一次中断)
void TIM3_IRQHandler(void)
{
        
if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)        //判断状态寄存器 TIM3_SR[2] 是否发生了捕获/比较2 中断
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);            //软件清除状态寄存器 TIM3_SR[2] 捕获/比较2 中断中断标志

    capture1 = TIM_GetCapture2(TIM3);                    //获取TIM3_CCR2的预装值
    TIM_SetCompare2(TIM3, capture1+ CCR2_Val);            //和CCR2_Val累加后装入TIM3_CCR2     这是为了配合计数器值的递增。以在下一次作出比较。
   
  }
}

使用特权

评论回复
56
peripheral| | 2020-1-1 18:11 | 只看该作者
4.2 周期控制通用定时器3的2通道,实现1KHz的不同占空比波形,控制LED实现呼吸灯

>_<" 主函数为:(不同于上面固定的频率定时方法,这里在while里不断更改CCR2_Val的值来改变占空比)
int main(void)
{     
    unsigned char a=0;
    TIM_OCInitTypeDef  TIM3_OCInitStructure;
      RCC_Configuration();  
      time_ini();              
    SysTick_Config(72000);       //配置SYSTICK时钟节拍为1ms一次
      while(1){
          Delay(1);          //延时1ms           
        TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                       //PWM模式2
          TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //输出禁止        
          TIM3_OCInitStructure.TIM_Pulse = CCR2_Val;                               //确定占空比
          TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
          TIM_OC2Init(TIM3, &TIM3_OCInitStructure);

          /*调整CCR2_Val的值来改变占空比,逐步的控制LED1的亮度, 占空比大过一定值时,
        亮度的变化就不明显了,所以CCR2_VAL最大设定到17000*/
        if(a==0) CCR2_Val=CCR2_Val+10;                                         
        else CCR2_Val=CCR2_Val-10;
        if(CCR2_Val>17000){ CCR2_Val=17000; a=1;}                              
        else if(CCR2_Val<200){ CCR2_Val=200; a=0;}
      }
}

使用特权

评论回复
57
peripheral| | 2020-1-1 18:11 | 只看该作者
>_<" 配置各外设的时钟和系统时钟:(同4.1有些是多余的)
/****************************************************************************
* 名    称:void RCC_Configuration(void)
* 功    能:系统时钟配置为72MHZ, 外设时钟配置
****************************************************************************/
void RCC_Configuration(void){

  SystemInit();
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
                          | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOE , ENABLE);
}

使用特权

评论回复
58
peripheral| | 2020-1-1 18:11 | 只看该作者
>_<" TIM3的2通道配置:(注意,这里没有用到中断向量和中断子程序!!!下面首先配置GPIO PB5(为Tim3的2通道),PB5引脚默认是作为通用IO口使用,为了产生特定频率,利用了该引脚可以复用为TIM3_CH2,根据手册,需要用到局部复用映射,才能将TIM3_CH2映射到PB5。)

使用特权

评论回复
59
peripheral| | 2020-1-1 18:12 | 只看该作者
由于TIM3计数器的时钟频率是72MHz,希望各通道输出频率为1KHZ,根据3倍预分频后,时钟频率为24MHz,根据公式ftim3=TIM3CLK/(TIM3_Period+1),可得到TIM3预分频的值为24000, 根据公式根据公式 通道输出占空比=TIM3_CCR2/(TIM_Period+1),可以得到TIM_Pulse的计数值,逐步改变这个值,可以控制占空比, 从而获得LED1 亮度明暗渐变的效果。(所以在main函数的while中不断重置CCR2_Val值来控制不同占空比)
/****************************************************************************
* 名    称:void time_ini(void)
* 功    能:TIM3初始化
****************************************************************************/
void time_ini(void){
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                        //PB5复用为TIM3的通道2
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  /*TIM3局部复用功能开启     在TIM3的局部复用开启时,PB5会被复用为TIM3_CH2*/
  GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE);            
                  
   /*-------------------------------------------------------------------
  TIM3CLK=72MHz  预分频系数Prescaler=2 经过分频 定时器时钟为24MHz
  根据公式 通道输出占空比=TIM3_CCR2/(TIM_Period+1),可以得到TIM_Pulse的计数值     
  捕获/比较寄存器2 TIM3_CCR2= CCR2_Val         
  -------------------------------------------------------------------*/
  TIM3_TimeBaseStructure.TIM_Prescaler = 2;                            //预分频器TIM3_PSC=3     
  TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //计数器向上计数模式 TIM3_CR1[4]=0
  TIM3_TimeBaseStructure.TIM_Period =24000;                            //自动重装载寄存器TIM3_APR  确定频率为1KHz              
  TIM3_TimeBaseStructure.TIM_ClockDivision = 0x0;                    //时钟分频因子 TIM3_CR1[9:8]=00
  TIM3_TimeBaseStructure.TIM_RepetitionCounter = 0x0;

  TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseStructure);                    //写TIM3各寄存器参数
  
  TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                 //PWM模式2 TIM3_CCMR1[14:12]=111 在向上计数时,
                                                                      //一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平
  TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //输入/捕获2输出允许  OC2信号输出到对应的输出引脚PB5
  TIM3_OCInitStructure.TIM_Pulse = CCR2_Val;                         //确定占空比,这个值决定了有效电平的时间。
  TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;         //输出极性  低电平有效 TIM3_CCER[5]=1;
         
  TIM_OC2Init(TIM3, &TIM3_OCInitStructure);
  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
  TIM_Cmd(TIM3,ENABLE);                                            //启动定时器3 TIM3_CR1[0]=1;
}

使用特权

评论回复
60
peripheral| | 2020-1-1 18:12 | 只看该作者
链接

本文正版链接:http://www.cnblogs.com/zjutlitao/p/4652695.html

工程4.1 TIM3-CH2链接:http://pan.baidu.com/s/1c0dLgAW

工程4.2 TIM3-PWM链接: http://pan.baidu.com/s/1dDjiMnn

上述两个工程的说明(建议直接看我博客):http://pan.baidu.com/s/1ntkoym9

stm32几个重要的文件:http://pan.baidu.com/s/1qW41bw4

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则