STM32菜鸟成长记录---普通定时器应用

发布者:水云间梦最新更新时间:2016-12-28 来源: eefocus关键字:STM32  普通定时器 手机看文章 扫描二维码
随时随地手机看文章

一、STM32通用定时器原理                        

    STM32 系列的CPU,有多达8个定时器,其中TIM1和TIM8是能够产生三对PWM互补输出的高级定时器,常用于三相电机的驱动,它们的时钟由APB2的输出产生。其它6个为普通定时器,时钟由APB1的输出产生。

下图是STM32参考手册上时钟分配图中,有关定时器时钟部分的截图:

从图中可以看出,定时器的时钟不是直接来自APB1或APB2,而是来自于输入为APB1或APB2的一个倍频器,图中的蓝色部分。

下面以通用定时器2的时钟说明这个倍频器的作用:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起作用,定时器的时钟频率等于APB1的频率两倍。

可能有同学还是有点不理解,OK,我们举一个例子说明。假定AHB=36MHz,因为APB1允许的最大频率为36MHz,所以APB1的预分频系数可以取任意数值;

当预分频系数=1时,APB1=36MHz,TIM2~7的时钟频率=36MHz(倍频器不起作用);

当预分频系数=2时,APB1=18MHz,在倍频器的作用下,TIM2~7的时钟频率=36MHz。

有人会问,既然需要TIM2~7的时钟频率=36MHz,为什么不直接取APB1的预分频系数=1?答案是:APB1不但要为TIM2~7提供时钟,而且还要为其它外设提供时钟;设置这个倍频器可以在保证其它外设使用较低时钟频率时。

Stm32外设用户手册,如图:

再举个例子:当AHB=72MHz时,APB1的预分频系数必须大于2,因为APB1的最大频率只能为36MHz。如果APB1的预分频系数=2,则因为这个倍频器,TIM2~7仍然能够得到72MHz的时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频器的初衷。

              

二、STM32通用定时器编程

    定时器编程,就是中断的编程。因为使用定时器必定要使用到中断。

  

步骤一:RCC_Configuration();//设置系统时钟,包括时钟RCC的配置,倍频到72MHZ。

      

步骤二: GPIO的配置,使用函数为GPIO_cfg();,该函数的实现如下:

 


  1. void GPIO_cfg()  

  2.   

  3. {  

  4.   

  5.        GPIO_InitTypeDef GPIO_InitStructure;  

  6.   

  7.       RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD , ENABLE);  

  8.   

  9.          

  10.   

  11.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;                 //选择引脚6  

  12.   

  13.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz  

  14.   

  15.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //带上拉电阻输出  

  16.   

  17.        GPIO_Init(GPIOC,&GPIO_InitStructure);  

  18.   

  19. }  


实际上定时器的讲解,不需要配置GPIO的引脚,只是我们在定时器实验中,

使用每隔一秒点亮一次LED灯来做实验,所以需要配置对应GPIO的引脚。

 

步骤三:嵌套中断控制器的配置,我们照样使用函数NVIC_Config();只是初始化的过程略有不同。这里我们也把函数实现列出来:

     从以上函数实现来看,实际上只是改动了结构体成员NVIC_IRQChannel的值,现在需要的通道是TIM2的通道,因此初始化值为TIM2_IRQChannel。从这里也可以看出,这个函数实际上可以看做一个模型,可以拿去别的程序中改动后直接使用。

 

  1. void NVIC_cfg()  

  2.   

  3. {  

  4.   

  5.        NVIC_InitTypeDef NVIC_InitStructure;  

  6.   

  7.         //选择中断分组1  

  8.   

  9.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  

  10.   

  11.   

  12.   

  13.         //选择TIM2的中断通道  

  14.   

  15.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;       

  16.   

  17.         //抢占式中断优先级设置为0  

  18.   

  19.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  

  20.   

  21.        //响应式中断优先级设置为0  

  22.   

  23.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  

  24.   

  25.         //使能中断  

  26.   

  27.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

  28.   

  29.         NVIC_Init(&NVIC_InitStructure);  

  30.   

  31. }  


步骤四:定时器的初始化配置,使用Timer_Config();。OK,关键部分出来了。

我们来看下实现过程:


  1. TIMER_cfg(); //定时器的配置  

  2.   

  3.        //开启定时器2  

  4.   

  5.  TIM_Cmd(TIM2,ENABLE);  

  6.   

  7. voidTimer_Config(void)  

  8. {   

  9.   

  10.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);   

  11.   

  12.     TIM_DeInit(TIM2);  

  13.   

  14.     TIM_TimeBaseStructure.TIM_Period=2000-1;  //自动重装载寄存器的值  

  15.   

  16.     TIM_TimeBaseStructure.TIM_Prescaler=(36000-1);         //时钟预分频数  

  17.   

  18.     TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;  //采样分频  

  19.   

  20.      TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式  

  21.     TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);  

  22.   

  23.     TIM_ClearFlag(TIM2,TIM_FLAG_Update);               //清除溢出中断标志  

  24.   

  25.     TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);  

  26.   

  27.      TIM_Cmd(TIM2,ENABLE);                              /开启时钟  

  28.   

  29. }   

    我们每个语句都来解释一下。首先我们想使用定时器,就必须使能定时器的时钟,这就是函数RCC_APB1PeriphClockCmd();,通过它开启 RCC_APB1Periph_TIM2。

TIM_DeInit(TIM2);该函数主要用于复位TIM2定时器,使之进入初始状态。

然后我们对自动重装载寄存器赋值,TIM_Period的大小实际上表示的是需要经过TIM_Period次计数后才会发生一次更新或中断。接下来需要设置时钟预分频数TIM_Prescaler,这里有一个公式,我们举例来说明:例如时钟频率=72MHZ/(时钟预分频+1)。说明当前设置的这个TIM_Prescaler,直接决定定时器的时钟频率。通俗点说,就是一秒钟能计数多少次。比如算出来的时钟频率是2000,也就是

一秒钟会计数2000次,而此时如果TIM_Period设置为4000,即4000次计数后就会中断一次。由于时钟频率是一秒钟计数2000次,因此只要2秒钟,就会中断一次。

再往后的代码,还有一个需要注意的,TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;就是我们一般采用向上计数模式,即每次计数就会加1,直到寄存器溢出发生中断为止。最后别忘了,需要使能定时器!!

发生中断时间=(TIM_Prescaler+1)* (TIM_Period+1)/FLK

 用上述公式可算出:发生中断时间 (2000-1+1)*(36000-1+1)/72000000=1 秒

步骤五:编写中断服务程序。同样需要注意的,一进入中断服务程序,第一步要做的,就是清除掉中断标志位。由于我们使用的是向上溢出模式,因此使用

的函数应该是:TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);。

STM32开发板实现的中断服务程序如下:

每隔一秒,发生中断时,进入此中断函数执行程序,让LED闪一下,此中断程序所在文件stm32f10x_it.c


  1. /*******************************************************************************  

  2.   

  3. * Function Name  : TIM2_IRQHandler  

  4.   

  5. * Description    : This function handles TIM2 global interrupt request.  

  6.   

  7. * Input          : None  

  8.   

  9. * Output         : None  

  10.   

  11. * Return         : None  

  12.   

  13. ******************************************************************************/  

  14.   

  15.    

  16.   

  17. void TIM2_IRQHandler(void)  

  18.   

  19. {  

  20.   

  21.    u8 ReadValue;  

  22.   

  23.    

  24.   

  25.    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)    //检测是否发生溢出更新事件  

  26.   

  27.      {  

  28.   

  29.         TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);//清除TIM2的中断待处理位  

  30.   

  31.               //UART2_TX485_Puts("123450");  

  32.   

  33.    

  34.   

  35.               /*调试定时器测试*/  

  36.   

  37.               ReadValue = GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_6);  

  38.   

  39.         if(ReadValue == 0)                   //若该端口当前为低电平,  

  40.   

  41.          {  

  42.   

  43.             GPIO_SetBits(GPIOC,GPIO_Pin_6);//将其改为高电平输出 ;  

  44.   

  45.          }      

  46.   

  47.    

  48.   

  49.          else                            //若该端口当前为高电平,  

  50.   

  51.          {  

  52.   

  53.             GPIO_ResetBits(GPIOC,GPIO_Pin_6);   //将其改为低电平输出;  

  54.   

  55.          }  

  56.   

  57.           

  58.   

  59.      }          

  60.   

  61. }  

 

普通定时器工作原理图


编译完成的代码下载在我的资源:http://download.csdn.net/detail/yx_l128125/4508425


关键字:STM32  普通定时器 引用地址:STM32菜鸟成长记录---普通定时器应用

上一篇:STM32菜鸟成长记录---系统滴答定时器(systick)应用
下一篇:STM32菜鸟成长记录---GPIO的使用

推荐阅读最新更新时间:2024-03-16 15:27

stm32 rcc 时钟
STM32中在使用任何一个外设都必须打开相应的时钟,所以我从STM32的时钟学起。 RCC时钟 iframe id="iframe_0.2786969253793359" src="data:text/html;charset=utf8,%3Cimg%20id=%22img%22%20src=%22http://hiphotos.baidu.com/%25B4%25D3%25D0%25A1%25BE%25CD%25BA%25DC%25CB%25A5/pic/item/481cde3e541abeaad5622588.jpg?_=2634063%22%20style=%22border:none;max-width:1397px%
[单片机]
<font color='red'>stm32</font> rcc 时钟
如何利用STM32单片机发送字符串
一、STM32有自己的字符发送函数。 void PC_SendChar(uint8_t DataToSend) { USART_SendData (USART1 ,DataToSend); while(USART_GetFlagStatus (USART1 ,USART_FLAG_TC )!=SET ); } 二、发送字符串函数是在字符发送函数的基础上编写的 void PC_SendString(uint8_t *str) { while(*str) { PC_SendChar (*str); str++; } } 三、发送字符串示例 PC_SendString((u8*) Welcome to the NDIR wo
[单片机]
STM32 禁用swd-jtag下载口后,重新下载程序的方法
由于工作需要,复用了PA15的时候,程序禁用swd-jtag功能,网上多方查找解决方法。 在重新上电的时候,保证BOOT0为高电平,BOOT1为低电平,即可禁止程序从烧写过的代码启动,这时,重新烧写程序即可。 STM32三种启动模式对应的存储介质均是芯片内置的,它们是: 1)用户闪存=芯片内置的Flash。 2)SRAM=芯片内置的RAM区,就是内存啦。 3)系统存储器=芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROROMM区。 在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位
[单片机]
STM32启动文件的选择及宏定义
startup_stm32f10x_cl.s 互联型的器件,STM32F105xx,STM32F107xx startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx startup_stm32f10x_hd_vl.s 大容量的STM32F100xx startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx startup_stm32f10x_ld_vl.s 小容量的STM32F100xx startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM32
[单片机]
stm32电机控制之控制两路直流电机
  小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下:   由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动,通过改变PWM占空比的大小可以改变电机的转速,由于我们的控制目标是实现电机运行在速度范围内任意给定的速度,这里就需要采用闭环控制的思想,通过编码器获取电机的实时转速,通过与给定速度做差,将偏差作为PID控制器的输入,通过PID控制改变PWM占空比的大小,从而使电机的速度运行在给定的速度上。   这里使用的电机驱动芯片为TB6612,该芯片可以十分方便的驱动两个直流电机的运行,其驱动逻辑表如下:   AIN1,A
[单片机]
<font color='red'>stm32</font>电机控制之控制两路直流电机
STM32 BOOT位理解及设置
STM32F10x 片上存储区有3个部分:内置Flash,内置SRAM ,内置ROM(system memory),这就定义了系统的启动方式有3种:从内置Flash启动,从内置SRAM启动,从system memory 启动,这三种启动方式是通过BOOT 这两个引脚来决定的。 SRAM:即芯片内置的RAM区,通俗意义上的内存。 系统存储区(system memory):芯片内部一块特定的区域,芯片出厂时ST在这个区域烧写了一段Bootloader ,由于这个区域为ROM,因此芯片出厂后是无法修改的。这个Bootloader的主要任务就是通过UART1下载程序到内置Flash中去。BOOT选择System memory 模
[单片机]
<font color='red'>STM32</font> BOOT位理解及设置
STM32学习笔记一一PWM 输出
1.PWM 简介 脉冲宽度调制(PWM),是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。即对脉冲宽度的控制。 STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出! 2.相关寄存器 除了定时器章节介绍的几个寄存器( ARR、PSC、 CR1 等) 外,还会用到 4 个寄存器(通用定时器则只需要 3 个),来控制 PWM 的输出。这四个寄存器分别是:捕获/比较模式寄存器( TIMx_CCMR
[单片机]
快速理解STM32位带操作原理和用途
说到位带操作,可能很多人比较陌生,但说到控制IO,你肯定不会陌生。有的项目为了最大效率控制IO,使用位带操作。下面就来简单说说未带操作的内容。 一、初识位带操作 Bit-banding简称位带,有人也叫位段。支持位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。 很多朋友是从学习51单片机过来的,都知道P1.1这个引脚可以单独控制,我们操作的这个引脚就是一个Bit位。 我们都知道在STM32中不能直接操作寄存器的某一个Bit位,比如单独控制PA端口输出数据寄存器中的ODR1,如下图: STM32F1内核Cortex-M3早就考虑到了这个问题,为了能达到直接操作ODR1这类Bit位,就在内核中开辟了一块
[单片机]
快速理解<font color='red'>STM32</font>位带操作原理和用途
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved