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
05 #define  TIM_3  0x03
06 #define  TIM_4  0x04
07 #define  TIM_5  0x05
08 #define  TIM_6  0x06
09 #define  TIM_7  0x07
10 #define  TIM_8  0x08
11  
12  
13 #define  CCR_1  0x01
14 #define  CCR_2  0x02
15 #define  CCR_3  0x03
16 #define  CCR_4  0x04
17  
18 void Tim_Init(u8 TIM_x,u16 arr,u16 psc);
19 void Tim_CCR_Set(u8 TIM_x,u8 CCR_x,u32 val);
 
 
库函数操作
 
通用定时器有4个通道,每个通道都有6种工作模式:
TIM_OCMODE定义
TIM_OCMode描述
    TIM_OCMODE_TimgingTIM输出比较时间模式,中断时管脚无变化
    TIM_OCMODE_ActiveTIM输出比较时间模式,中断时管脚强制为有效电平
    TIM_OCMODE_InactiveTIM输出比较时间模式,中断时管脚强制为无效电平
    TIM_OCMODE_ToggleTIM输出比较时间模式,中断时管脚状态翻转,高变低,低变高
    TIM_OCMODE_PWM1TIM脉冲宽度调制模式1
    TIM_OCMODE_PWM2TIM脉冲宽度调制模式2
 
PS:至于有效电平是高还是低,要看CCER寄存器的CCxP位设置。两种PWM模式,区别在于通道的电平极性是相反的。
 
 
main.c
001 #include "stm32f10x.h"
002  
003 vu16 CCR1_Val = 40000;
004 vu16 CCR2_Val = 20000;
005 vu16 CCR3_Val = 10000;
006 vu16 CCR4_Val = 5000;             
007  
008 void RCC_Configuration(void);
009 void GPIO_Configuration(void);
010 void NVIC_Configuration(void);
011 void TIM_Configuration(void);
012  
013 int main(void)
014 {
015     
016     RCC_Configuration();
017     GPIO_Configuration();
018     NVIC_Configuration();
019     TIM_Configuration();
020     while(1);
021 }
022  
023 void TIM_Configuration(void)
024 {
025     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
026     TIM_OCInitTypeDef TIM_OCInitStructure;
027     TIM_TimeBaseStructure.TIM_Period = 65535;
028     TIM_TimeBaseStructure.TIM_Prescaler = 7199;
029     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
030     TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
031  
032     //TIM_PrescalerConfig(TIM2,7199,TIM_PSCReloadMode_Immediate);
033  
034     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
035     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
036     TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
037     TIM_OC1Init(TIM2,&TIM_OCInitStructure);
038     TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
039     TIM_OC2Init(TIM2,&TIM_OCInitStructure);
040     TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
041     TIM_OC3Init(TIM2,&TIM_OCInitStructure);
042     TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
043     TIM_OC4Init(TIM2,&TIM_OCInitStructure);
044      
045     TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Disable);
046     TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Disable);
047     TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Disable);
048     TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Disable);
049  
050     TIM_ITConfig(TIM2,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);
051      
052     TIM_Cmd(TIM2,ENABLE);
053  
054 }
055  
056 void NVIC_Configuration(void)
057 {
058     NVIC_InitTypeDef NVIC_InitStructure;
059  
060     #ifdef  VECT_TAB_RAM
061         NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
062     #else
063         NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
064     #endif
065  
066     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
067     NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
068     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
069     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
070     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
071     NVIC_Init(&NVIC_InitStructure);
072  
073 }
074  
075    
076 void GPIO_Configuration(void)
077 {
078     GPIO_InitTypeDef GPIO_InitStructure;
079  
080     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
081     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
082     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
083     GPIO_Init(GPIOA , &GPIO_InitStructure);
084 }
085  
086  
087 void RCC_Configuration(void)
088 {
089     /* 定义枚举类型变量 HSEStartUpStatus */
090     ErrorStatus HSEStartUpStatus;
091  
092     /* 复位系统时钟设置*/
093     RCC_DeInit();
094     /* 开启HSE*/
095     RCC_HSEConfig(RCC_HSE_ON);
096     /* 等待HSE起振并稳定*/
097     HSEStartUpStatus = RCC_WaitForHSEStartUp();
098     /* 判断HSE起是否振成功,是则进入if()内部 */
099     if(HSEStartUpStatus == SUCCESS)
100     {
101         /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
102         RCC_HCLKConfig(RCC_SYSCLK_Div1);
103         /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
104         RCC_PCLK2Config(RCC_HCLK_Div1);
105         /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
106         RCC_PCLK1Config(RCC_HCLK_Div2);
107         /* 设置FLASH延时周期数为2 */
108         FLASH_SetLatency(FLASH_Latency_2);
109         /* 使能FLASH预取缓存 */
110         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
111         /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
112         RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
113         /* 使能PLL */
114         RCC_PLLCmd(ENABLE);
115         /* 等待PLL输出稳定 */
116         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
117         /* 选择SYSCLK时钟源为PLL */
118         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
119         /* 等待PLL成为SYSCLK时钟源 */
120         while(RCC_GetSYSCLKSource() != 0x08);
121     }
122     /* 打开APB2总线上的GPIOA时钟*/
123     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
124  
125     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
126      
127 }
stm32f10x_it.c

01 #include "stm32f10x_it.h"
02  
03 extern vu16 CCR1_Val;
04 extern vu16 CCR2_Val;
05 extern vu16 CCR3_Val;
06 extern vu16 CCR4_Val;
07  
08  
09  
10 void TIM2_IRQHandler(void)
11 {
12     vu16 capture=0;
13     if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET)
14     {
15         GPIO_WriteBit(GPIOA , GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));     
16         capture = TIM_GetCapture1(TIM2);
17         TIM_SetCompare1(TIM2,capture + CCR1_Val);
18         TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
19     }
20     else if(TIM_GetITStatus(TIM2,TIM_IT_CC2) != RESET)
21     {
22         GPIO_WriteBit(GPIOA , GPIO_Pin_5,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)));     
23         capture = TIM_GetCapture2(TIM2);
24         TIM_SetCompare2(TIM2,capture + CCR2_Val);
25         TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
26     }
27     else if(TIM_GetITStatus(TIM2,TIM_IT_CC3) != RESET)
28     {
29         GPIO_WriteBit(GPIOA , GPIO_Pin_6,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_6)));     
30         capture = TIM_GetCapture3(TIM2);
31         TIM_SetCompare3(TIM2,capture + CCR3_Val);
32         TIM_ClearITPendingBit(TIM2,TIM_IT_CC3);
33     }
34     else
35     {
36         GPIO_WriteBit(GPIOA , GPIO_Pin_7,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_7)));     
37         capture = TIM_GetCapture4(TIM2);
38         TIM_SetCompare4(TIM2,capture + CCR4_Val);
39         TIM_ClearITPendingBit(TIM2,TIM_IT_CC4);
40     }
41 }
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值