stm32 TIM定时器[操作寄存器+库函数]

stm32配备了2个高级定时器TIM1和TIM8,4个通用定时器 TIM2,TIM3,TIM4和TIM5,还有两个基本定时器TIM6和TIM7。 高级定时器常用于电机控制,因为其加入了死区控制,紧急制动,定时器同步等高级特性。基本定时器可以为数模转化器提供准确的时间基准。
 
stm32的通用定时器由一个通过可编程预分频器驱动的16位自动装载计数器构成。通用定时器可以用于测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。
 
通用计时器的使用,需要先配置一个时基单元,就是设定一个基准时间,确定计数一次耗去的时间,可以设定在几个微妙到几个毫秒之间。
 
通用定时器的都有4个独立通道(TIMx_CH1~4),这些通道可以用来作为:
  • 输入捕获
  • 输出比较
  • PWM生成
  • 单脉冲模式输出
时基单元核心部件是一个16位分频器,通过对定时器时钟的分频实现确定时间基准的功能。
 
根据手册可以知道 基准时钟的计算公式:     
 
T = (分频寄存器+1)/TIM时钟 
 
需要注意的是TIM时钟的大小,以TIM2为例,虽然其挂载在APB1总线上,PCLK时钟为36Mhz,但TIM2得到的却是72Mhz。所有挂载在APB1总线上的通用定时器时钟频率都为72Mhz;
 
通用寄存器的四个通道,每一个通道相当于一个中断触发源,可以设置一个计数值,当TIM计数值和此计数值相等时,触发中断。 
 
本例实现以TIM2为例产生一组不同频率的时钟,使4个LED不同频率闪烁

 
直接操作寄存器
 
首先是控制寄存器(TIMx_CR1),该寄存器各位描述如下:
timx_cr1.png
 
需要注意的是
ARPE位 :要开启自动重装必须将此为置1;
DIR位:  0:计数器向上计数;    1:计数器向下计数。 注:当计数器配置为中央对齐模式或编码器模式时,该位为只读。
CEN位:计数器使能位
 
计数器中断使能寄存器:
 
timx_dier.png
 
TIE:触发中断使能位;
UIE:允许更新中断位,允许由更新事件来产生中断;
  • 更新事件包括: 计数器向上/向下溢出,计数器初始化
  • 触发时间包括:计数器启动,停止,初始化
CC1IE~CC4IE:允许捕获/比较1~4中断
 
TDE,UDE,CC1DE~CC4DE为DMA相关中断设置,这里不讨论。
 
预分频寄存器(TIMx_PSC),低16位有效,该寄存器用于设置时钟进行分频,然后提供给计数器作为时钟。
 
自动重装载寄存器(TIMx_ARR),低16位有效。
 
状态寄存器(TIMx_SR),该寄存器用于标识当前与定时器相关的各种事件和中断是否发生。
描述如下:
timx_sr.png
 
UIF:更新中断标记 (Update interrupt flag)  当产生更新事件时该位由硬件置’1’。它由软件清’0’。
  • 若TIMx_CR1寄存器的UDIS=0、URS=0,当TIMx_EGR寄存器的UG=1时产生更新事件(软件对计数器CNT重新初始化);
  •  若TIMx_CR1寄存器的UDIS=0、URS=0,当计数器CNT被触发事件重初始化时产生更新事件。
 
CC1IF~CC4IF:捕获/比较1~4 中断标记 (Capture/Compare 1 interrupt flag)
 
TIF:触发器中断标记 (Trigger interrupt flag)  
当发生触发事件(当从模式控制器处于除门控模式外的其它模式时,在TRGI输入端检测到有效边沿,或门控模式下的任一边沿)时由硬件对该位置’1’。它由软件清’0’。
 
代码如下:(system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置
 
User/main.c
01 #include <stm32f10x_lib.h>    
02 #include "system.h"
03 #include "tim.h"   
04  
05 void Gpio_Init(void);
06  
07 int main(void)
08 {                
09  
10     Rcc_Init(9);             //系统时钟设置
11     //Usart1_Init(72,9600); //设置系统时钟和波特率
12  
13     // 相关TIM_x,CCR_x参数定义tim.h文件
14  
15     Tim_Init(TIM_2,65535,7199);  //初始化TIM2定时器,设定重装值和分频值
16  
17     Tim_CCR_Set(TIM_2,CCR_1,40000);
18     Tim_CCR_Set(TIM_2,CCR_2,20000);
19     Tim_CCR_Set(TIM_2,CCR_3,10000);
20     Tim_CCR_Set(TIM_2,CCR_4,5000);
21       
22     Nvic_Init(0,0,TIM2_IRQChannel,0);     //设置抢占优先级为0,响应优先级为0,中断分组为0
23  
24     Gpio_Init();
25  
26     while(1);
27  
28 }
29  
30 void Gpio_Init(void)
31 {
32     RCC->APB2ENR|=1<<2;    //使能PORTA时钟     
33  
34     GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
35     GPIOA->CRL|=0x33334444;
36     //GPIOA->ODR &=0xFFFFFFF0;
37      
38     //USART1 串口I/O设置
39  
40     //GPIOA -> CRH&=0xFFFFF00F;   //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入
41     //GPIOA -> CRH|=0x000008B0;   
42 }
 
User/stm32f10x_it.c
01 #include "stm32f10x_it.h"
02 #include "system.h"
03  
04 #define LED0 PAout(4)
05 #define LED1 PAout(5)
06 #define LED2 PAout(6)
07 #define LED3 PAout(7)
08   
09 void TIM2_IRQHandler(void)
10 {
11     if(TIM2->SR&0x02)   //捕获比较中断1触发
12     {
13         LED0 = !LED0;  
14              
15         TIM2 ->CCR1 = TIM2 -> CNT + 40000;     //更新捕获/比较1的值
16  
17         TIM2->SR &= 0xFD;  //清除捕获比较中断
18     }
19  
20     if(TIM2->SR&0x04)   //捕获比较中断2触发
21     {
22         LED1 = !LED1;      
23         TIM2 ->CCR2 = TIM2 -> CNT + 20000;
24  
25         TIM2->SR &= 0xFB;  //清除捕获比较中断
26     }
27  
28     if(TIM2->SR&0x08)   //捕获比较中断3触发
29     {
30         LED2 = !LED2;  
31  
32         TIM2 ->CCR3 = TIM2 -> CNT + 10000;
33         TIM2->SR &= 0xF7;  //清除捕获比较中断
34      
35     }
36  
37     if(TIM2->SR&0x10)   //捕获比较中断4触发
38     {
39         LED3 = !LED3;
40  
41         TIM2 ->CCR4 = TIM2 -> CNT + 5000;
42         TIM2->SR &= 0x0F;  //清除捕获比较中断
43      
44     }
45      
46     TIM2->SR &= ~(1<<0);    //清除中断
47  
48 }
Library/src/tim.c
001 #include <stm32f10x_lib.h>    
002 #include "tim.h"
003  
004 //通用定时器初始化
005 //参数说明:TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h), arr为自动重装值 ;psc 为时钟预分频数
006 //待完善 目前只支持TIM2
007 void Tim_Init(u8 TIM_x,u16 arr,u16 psc)
008 {
009     switch(TIM_x)
010     {
011         case 1 :{
012  
013             RCC->APB2ENR |=1<<11;
014  
015             break;
016         }
017  
018         case 2 :{
019             RCC->APB1ENR |=1<<0;
020  
021             TIM2->ARR = arr;         //设定自动重装值
022             TIM2->PSC = psc;         //设定预分频值
023             TIM2->DIER |= 1<<0;            //允许更新中断
024             TIM2->DIER |= 1<<6;            //允许触发中断
025  
026             TIM2->CR1 |= 0x81;           //使能定时器,自动重装允许                     
027  
028             break;
029         }
030  
031         case 3 :{
032             RCC->APB1ENR |=1<<1;
033  
034             break;
035         }
036         case 4 :{
037             RCC->APB1ENR |=1<<2;              
038  
039             break;
040         }
041  
042         case 5 :{
043             RCC->APB1ENR |=1<<3;      
044  
045             break;
046         }
047         case 6 :{
048  
049             RCC->APB1ENR |=1<<4;
050  
051             break;
052         }  
053         case 7 :{
054  
055             RCC->APB1ENR |=1<<5;  
056  
057             break;
058         }
059  
060         case 8 :{
061  
062             RCC->APB2ENR |=1<<13;
063  
064             break;
065         }
066  
067     }
068 }
069  
070 //捕获比较值设定函数
071 //参数说明:
072 //          TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h)
073 //          CCR_x 为选择捕获/比较寄存器(1~4)(定义于tim.h)
074 //          val   为要设定的捕获/比较寄存器的值
075 // 待完善,目前只支持TIM2
076  
077 void Tim_CCR_Set(u8 TIM_x,u8 CCR_x,u32 val)
078 {
079     switch(TIM_x)
080     {
081         case 1 :{
082             break;
083         }
084  
085         case 2 :{
086  
087             TIM2->DIER |= 1 << CCR_x;          //开启相应允许捕获/比较中断
088  
089             switch(CCR_x){
090  
091                 case 1: {
092                     TIM2 ->CCR1 = val;        //设置捕获/比较1的值
093                     break;
094                 }
095  
096                 case 2: {
097                     TIM2 ->CCR2 = val;        //设置捕获/比较2的值
098                     break;
099                 }
100  
101                 case 3: {
102                     TIM2 ->CCR3 = val;        //设置捕获/比较3的值
103                     break;
104                 }
105  
106                 case 4: {
107                     TIM2 ->CCR4 = val;        //设置捕获/比较4的值
108                     break;
109                 }
110             }
111                      
112             break;
113         }
114  
115         case 3 :{
116             break;
117         }
118         case 4 :{
119             break;
120         }
121  
122         case 5 :{
123             break;
124         }
125         case 6 :{
126             break;
127         }  
128         case 7 :{
129             break;
130         }
131  
132         case 8 :{
133             break;
134         }
135  
136     }
137  
138 }
Library/inc/tim.h
01 #include <stm32f10x_lib.h>
02  
03 #define  TIM_1  0x01
04 #define  TIM_2  0x02