STM32学习笔记6-定时器中断

STM32 的定时器功能十分强大。

有TIME1 和 TIME8 等高级定时器,TIME2~TIME5 等通用定时器,TIME6 和TIME7 等基本定时器。

STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。   

使用时需要写两个函数

1.初始化函数(包括定时器的模式设置、初值,时钟,分频等)

2.中断函数


一、初始化函数

typedef struct            //定时器的结构体组成
{
uint16_t TIM_Prescaler;   //分频数
uint16_t TIM_CounterMode;      //模式(向上、向下计数,中央对齐模式1,2,3)
uint16_t TIM_Period;     //周期数(初值)
uint16_t TIM_ClockDivision;    //时钟分割(为0就行)
uint8_t TIM_RepetitionCounter;  //周期计数值(高级定时器才用)
} TIM_TimeBaseInitTypeDef;  

分频数为7199 计数值为4999时为500ms


1.定义结构体

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

NVIC_InitTypeDef NVIC_InitStructure;


2.开时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能


3.定时器TIM3初始化

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位


4.开中断

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断


5.管理中断NVIC
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器


6.使能

TIM_Cmd(TIM3, ENABLE);  //使能TIMx


二、中断函数

void TIM3_IRQHandler(void)   //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
.......................................//process
}
}


转自:http://blog.sina.com.cn/s/blog_49cb42490100s6ud.html

1.     STM32Timer简介

STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick,看门狗定时器以后再详细研究。今天主要是研究剩下的8个定时器。

定时器

计数器分辨率

计数器类型

预分频系数

产生DMA请求

捕获/比较通道

互补输出

TIM1

TIM8

16

向上,向下,向上/向下

1-65536之间的任意数

可以

4

TIM2

TIM3

TIM4

TIM5

16

向上,向下,向上/向下

1-65536之间的任意数

可以

4

没有

TIM6

TIM7

16

向上

1-65536之间的任意数

可以

0

没有

其中TIM1TIM8是能够产生3PWM互补输出的高级登时其,常用于三相电机的驱动,时钟由APB2的输出产生。TIM2-TIM5是普通定时器,TIM6TIM7是基本定时器,其时钟由APB1输出产生。由于STM32TIMER功能太复杂了,所以只能一点一点的学习。因此今天就从最简单的开始学习起,也就是TIM2-TIM5普通定时器的定时功能。

 

2.     普通定时器TIM2-TIM5

2.1    时钟来源

计数器时钟可以由下列时钟源提供:

·内部时钟(CK_INT)

·外部时钟模式1:外部输入脚(TIx)

·外部时钟模式2:外部触发输入(ETR)

       ·内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

    由于今天的学习是最基本的定时功能,所以采用内部时钟。TIM2-TIM5的时钟不是直接来自于APB1,而是来自于输入为APB1的一个倍频器。这个倍频器的作用是:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其他数值时(即预分频系数为24816),这个倍频器起作用,定时器的时钟频率等于APB1的频率的2倍。APB1的分频在STM32_SYSTICK的学习笔记中有详细描述。通过倍频器给定时器时钟的好处是:APB1不但要给TIM2-TIM5提供时钟,还要为其他的外设提供时钟;设置这个倍频器可以保证在其他外设使用较低时钟频率时,TIM2-TIM5仍然可以得到较高的时钟频率。

2.2    计数器模式

TIM2-TIM5可以由向上计数、向下计数、向上向下双向计数。向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。在向下模式中,计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。而中央对齐模式(向上/向下计数)是计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

2.3    编程步骤

1.       配置系统时钟;

2.       配置NVIC

3.       配置GPIO

4.       配置TIMER

其中,前3项在前面的笔记中已经给出,在此就不再赘述了。第4项配置TIMER有如下配置:

(1)       利用TIM_DeInit()函数将Timer设置为默认缺省值;

(2)       TIM_InternalClockConfig()选择TIMx来设置内部时钟源;

(3)       TIM_Perscaler来设置预分频系数;

(4)       TIM_ClockDivision来设置时钟分割;

(5)       TIM_CounterMode来设置计数器模式;

(6)       TIM_Period来设置自动装入的值

(7)       TIM_ARRPerloadConfig()来设置是否使用预装载缓冲器

(8)       TIM_ITConfig()来开启TIMx的中断

其中(3-6)步骤中的参数由TIM_TimerBaseInitTypeDef结构体给出。步骤(3)中的预分频系数用来确定TIMx所使用的时钟频率,具体计算方法为:CK_INT/(TIM_Perscaler+1)CK_INT是内部时钟源的频率,是根据2.1中所描述的APB1的倍频器送出的时钟,TIM_Perscaler是用户设定的预分频系数,其值范围是从0  – 65535

步骤(4)中的时钟分割定义的是在定时器时钟频率(CK_INT)与数字滤波器(ETR,TIx)使用的采样频率之间的分频比例。TIM_ClockDivision的参数如下表:

TIM_ClockDivision

描述

二进制值

TIM_CKD_DIV1

tDTS = Tck_tim

0x00

TIM_CKD_DIV2

tDTS = 2 * Tck_tim

0x01

TIM_CKD_DIV4

tDTS = 4 * Tck_tim

0x10

数字滤波器(ETR,TIx)是为了将ETR进来的分频后的信号滤波,保证通过信号频率不超过某个限定。

步骤(7)中需要禁止使用预装载缓冲器。当预装载缓冲器被禁止时,写入自动装入的值(TIMx_ARR)的数值会直接传送到对应的影子寄存器;如果使能预加载寄存器,则写入ARR的数值会在更新事件时,才会从预加载寄存器传送到对应的影子寄存器。

ARM中,有的逻辑寄存器在物理上对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器);设计preload registershadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload registershadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。

 

3.     程序源代码

本例实现的是通过TIM2的定时功能,使得LED灯按照1s的时间间隔来闪烁

[cpp] view plain copy print ?
  1. #include "stm32f10x_lib.h"  
  2.   
  3. void RCC_cfg();  
  4.   
  5. void TIMER_cfg();  
  6.   
  7. void NVIC_cfg();  
  8.   
  9. void GPIO_cfg();  
  10.   
  11.    
  12.   
  13. int main()  
  14.   
  15. {  
  16.   
  17.        RCC_cfg();  
  18.   
  19.        NVIC_cfg();  
  20.   
  21.        GPIO_cfg();  
  22.   
  23.        TIMER_cfg();  
  24.   
  25.    
  26.   
  27.        //开启定时器2  
  28.   
  29.        TIM_Cmd(TIM2,ENABLE);  
  30.   
  31.    
  32.   
  33.        while(1);  
  34.   
  35. }  
  36.   
  37.    
  38.   
  39. void RCC_cfg()  
  40.   
  41. {  
  42.   
  43.         
  44.   
  45.        //定义错误状态变量  
  46.   
  47.        ErrorStatus HSEStartUpStatus;  
  48.   
  49.         
  50.   
  51.        //将RCC寄存器重新设置为默认值  
  52.   
  53.        RCC_DeInit();  
  54.   
  55.    
  56.   
  57.        //打开外部高速时钟晶振  
  58.   
  59.        RCC_HSEConfig(RCC_HSE_ON);  
  60.   
  61.    
  62.   
  63.        //等待外部高速时钟晶振工作  
  64.   
  65.        HSEStartUpStatus = RCC_WaitForHSEStartUp();  
  66.   
  67.        if(HSEStartUpStatus == SUCCESS)  
  68.   
  69.        {  
  70.   
  71.               //设置AHB时钟(HCLK)为系统时钟  
  72.   
  73.               RCC_HCLKConfig(RCC_SYSCLK_Div1);  
  74.   
  75.    
  76.   
  77.               //设置高速AHB时钟(APB2)为HCLK时钟  
  78.   
  79.               RCC_PCLK2Config(RCC_HCLK_Div1);  
  80.   
  81.    
  82.   
  83.               //设置低速AHB时钟(APB1)为HCLK的2分频  
  84.   
  85.               RCC_PCLK1Config(RCC_HCLK_Div2);  
  86.   
  87.                
  88.   
  89.               //设置FLASH代码延时  
  90.   
  91.               FLASH_SetLatency(FLASH_Latency_2);  
  92.   
  93.    
  94.   
  95.               //使能预取指缓存  
  96.   
  97.               FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  
  98.   
  99.    
  100.   
  101.               //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz  
  102.   
  103.               RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  
  104.   
  105.    
  106.   
  107.               //使能PLL  
  108.   
  109.               RCC_PLLCmd(ENABLE);  
  110.   
  111.    
  112.   
  113.               //等待PLL准备就绪  
  114.   
  115.               while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  
  116.   
  117.    
  118.   
  119.               //设置PLL为系统时钟源  
  120.   
  121.               RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  
  122.   
  123.    
  124.   
  125.               //判断PLL是否是系统时钟  
  126.   
  127.               while(RCC_GetSYSCLKSource() != 0x08);  
  128.   
  129.        }  
  130.   
  131.    
  132.   
  133.        //允许TIM2的时钟  
  134.   
  135.        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);  
  136.   
  137.        //允许GPIO的时钟  
  138.   
  139.        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);  
  140.   
  141.    
  142.   
  143. }  
  144.   
  145.    
  146.   
  147. void TIMER_cfg()  
  148.   
  149. {  
  150.   
  151.        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  152.   
  153.    
  154.   
  155.        //重新将Timer设置为缺省值  
  156.   
  157.        TIM_DeInit(TIM2);  
  158.   
  159.        //采用内部时钟给TIM2提供时钟源  
  160.   
  161.        TIM_InternalClockConfig(TIM2);  
  162.   
  163.        //预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz  
  164.   
  165.        TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;  
  166.   
  167.        //设置时钟分割  
  168.   
  169.        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  
  170.   
  171.        //设置计数器模式为向上计数模式  
  172.   
  173.        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
  174.   
  175.        //设置计数溢出大小,每计2000个数就产生一个更新事件  
  176.   
  177.        TIM_TimeBaseStructure.TIM_Period = 2000 - 1;  
  178.   
  179.        //将配置应用到TIM2中  
  180.   
  181.        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);  
  182.   
  183.    
  184.   
  185.        //清除溢出中断标志  
  186.   
  187.        TIM_ClearFlag(TIM2, TIM_FLAG_Update);  
  188.   
  189.        //禁止ARR预装载缓冲器  
  190.   
  191.        TIM_ARRPreloadConfig(TIM2, DISABLE);  
  192.   
  193.        //开启TIM2的中断  
  194.   
  195.        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);  
  196.   
  197. }  
  198.   
  199.    
  200.   
  201. void NVIC_cfg()  
  202.   
  203. {  
  204.   
  205.        NVIC_InitTypeDef NVIC_InitStructure;  
  206.   
  207.         //选择中断分组1  
  208.   
  209.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  
  210.   
  211.           
  212.   
  213.           
  214.   
  215.         //选择TIM2的中断通道  
  216.   
  217.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;        
  218.   
  219.         //抢占式中断优先级设置为0  
  220.   
  221.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  222.   
  223.        //响应式中断优先级设置为0  
  224.   
  225.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  226.   
  227.         //使能中断  
  228.   
  229.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  230.   
  231.         NVIC_Init(&NVIC_InitStructure);  
  232.   
  233. }  
  234.   
  235.    
  236.   
  237. void GPIO_cfg()  
  238.   
  239. {  
  240.   
  241.        GPIO_InitTypeDef GPIO_InitStructure;  
  242.   
  243.    
  244.   
  245.         
  246.   
  247.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                 //选择引脚5  
  248.   
  249.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz  
  250.   
  251.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //带上拉电阻输出  
  252.   
  253.        GPIO_Init(GPIOB,&GPIO_InitStructure);  
  254.   
  255. }  
#include "stm32f10x_lib.h"

void RCC_cfg();

void TIMER_cfg();

void NVIC_cfg();

void GPIO_cfg();

 

int main()

{

       RCC_cfg();

       NVIC_cfg();

       GPIO_cfg();

       TIMER_cfg();

 

       //开启定时器2

       TIM_Cmd(TIM2,ENABLE);

 

       while(1);

}

 

void RCC_cfg()

{

      

       //定义错误状态变量

       ErrorStatus HSEStartUpStatus;

      

       //将RCC寄存器重新设置为默认值

       RCC_DeInit();

 

       //打开外部高速时钟晶振

       RCC_HSEConfig(RCC_HSE_ON);

 

       //等待外部高速时钟晶振工作

       HSEStartUpStatus = RCC_WaitForHSEStartUp();

       if(HSEStartUpStatus == SUCCESS)

       {

              //设置AHB时钟(HCLK)为系统时钟

              RCC_HCLKConfig(RCC_SYSCLK_Div1);

 

              //设置高速AHB时钟(APB2)为HCLK时钟

              RCC_PCLK2Config(RCC_HCLK_Div1);

 

              //设置低速AHB时钟(APB1)为HCLK的2分频

              RCC_PCLK1Config(RCC_HCLK_Div2);

             

              //设置FLASH代码延时

              FLASH_SetLatency(FLASH_Latency_2);

 

              //使能预取指缓存

              FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

 

              //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz

              RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

 

              //使能PLL

              RCC_PLLCmd(ENABLE);

 

              //等待PLL准备就绪

              while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

 

              //设置PLL为系统时钟源

              RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

 

              //判断PLL是否是系统时钟

              while(RCC_GetSYSCLKSource() != 0x08);

       }

 

       //允许TIM2的时钟

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

       //允许GPIO的时钟

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

 

}

 

void TIMER_cfg()

{

       TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

 

       //重新将Timer设置为缺省值

       TIM_DeInit(TIM2);

       //采用内部时钟给TIM2提供时钟源

       TIM_InternalClockConfig(TIM2);

       //预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz

       TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;

       //设置时钟分割

       TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

       //设置计数器模式为向上计数模式

       TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

       //设置计数溢出大小,每计2000个数就产生一个更新事件

       TIM_TimeBaseStructure.TIM_Period = 2000 - 1;

       //将配置应用到TIM2中

       TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

 

       //清除溢出中断标志

       TIM_ClearFlag(TIM2, TIM_FLAG_Update);

       //禁止ARR预装载缓冲器

       TIM_ARRPreloadConfig(TIM2, DISABLE);

       //开启TIM2的中断

       TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

}

 

void NVIC_cfg()

{

       NVIC_InitTypeDef NVIC_InitStructure;

        //选择中断分组1

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

        

        

        //选择TIM2的中断通道

        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;      

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

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

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

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

        //使能中断

        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

        NVIC_Init(&NVIC_InitStructure);

}

 

void GPIO_cfg()

{

       GPIO_InitTypeDef GPIO_InitStructure;

 

      

       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                 //选择引脚5

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

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

       GPIO_Init(GPIOB,&GPIO_InitStructure);

}


stm32f10x_it.c中,我们找到函数TIM2_IRQHandler(),并向其中添加代码

[cpp] view plain copy print ?
  1. void TIM2_IRQHandler(void)  
  2.   
  3. {  
  4.   
  5.        u8 ReadValue;  
  6.   
  7.        //检测是否发生溢出更新事件  
  8.   
  9.        if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  
  10.   
  11.        {  
  12.   
  13.               //清除TIM2的中断待处理位  
  14.   
  15.               TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);  
  16.   
  17.               //将PB.5管脚输出数值写入ReadValue  
  18.   
  19.               ReadValue = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5);  
  20.   
  21.                
  22.   
  23.               if(ReadValue == 0)  
  24.   
  25.               {  
  26.   
  27.                      GPIO_SetBits(GPIOB,GPIO_Pin_5);  
  28.   
  29.               }      
  30.   
  31.               else  
  32.   
  33.               {  
  34.   
  35.                      GPIO_ResetBits(GPIOB,GPIO_Pin_5);        
  36.   
  37.               }  
  38.   
  39.        }  
  40.   
  41.    
  42.   
  43. }  

你可能感兴趣的:(STM32学习笔记6-定时器中断)