文章归档友情连接照片地图

STM32定时器中断

分类:电子设计  作者:rming  时间:2012-07-21

STM32的定时器

stm32的定时器功能十分强大,有TIME1和TIME8等高级定时器,也有TIME1~TIME5等通用定时器,还有TIME6和TIME7等基本定时器,下面着重学习下难度适中的通用定时器。

 STM32 通用定时器简介

通用计时器的使用,需要先配置一个时基单元,就是设定一个基准时间,确定计数一次耗去的时间,可以设定在几个微妙到几个毫秒之间。

通用定时器的都有4个独立通道(TIMx_CH1~4),这些通道可以用来作为:

  • 输入捕获
  • 输出比较
  • PWM生成
  • 单脉冲模式输出
时基单元核心部件是一个16位分频器,通过对定时器时钟的分频实现确定时间基准的功能。
根据手册可以知道 基准时钟的计算公式:

T = (分频寄存器+1)/TIM时钟
需要注意的是TIM时钟的大小,以TIM2为例,虽然其挂载在APB1总线上,PCLK时钟为36Mhz,但TIM2得到的却是72Mhz。所有挂载在APB1总线上的通用定时器时钟频率都为72Mhz;
通用寄存器的四个通道,每一个通道相当于一个中断触发源,可以设置一个计数值,当TIM计数值和此计数值相等时,触发中断。 

 寄存器简介

控制寄存器1(TIMx_CR1)

需要注意的是

ARPE位 :要开启自动重装必须将此为置1;
DIR位 0:计数器向上计数;    1:计数器向下计数。 注:当计数器配置为中央对齐模式或编码器模式时,该位为只读。
CEN位计数器使能位

DMA/中断使能寄存器(TIMx_DIER)

该寄存器是一个16 位的寄存器

这里我们仅关心它的第6 位第0 位,第 6 位TIE 为触发中断使能位,通过将该位置 1 使能TIMx的中断触发,注意只要是 TIMx需要使用中断,该位必须为 1 。而第 0 位,则为允许更新中断位,通过置1 ,来允许由于更新事件而产生的中断

TIE:触发中断使能位;

UIE:允许更新中断位,允许由更新事件来产生中断;
  • 更新事件包括: 计数器向上/向下溢出,计数器初始化
  • 触发时间包括:计数器启动,停止,初始化
CC1IE~CC4IE:允许捕获/比较1~4中断

预分频寄存器(TIMx_PSC)

该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟

TIMx_CNT 寄存器,该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值

自动重装载寄存器(TIMx_ARR )

该寄存器在物理上实际对应着2 个寄存器。

一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《STM32参考手册》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。根据 TIMx_CR1 寄存器中APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。

状态寄存器(TIMx_SR)

该寄存器用来标记当前与定时器相关的各种事件/ 中断是否发生。

寄存器操作步骤

1 、TIM3 时钟使能。

这里我们通过APB1ENR的第1 位来设置TIM3的时钟,因为Stm32_Clock_Init函数里面把APB1的分频设置为2 了,所以我们的 TIM3时钟就是 APB1时钟的 2 被,等于系统时钟。

2 、设置TIM3_ARR和TIM3_PSC 的值。

通过这两个寄存器,我们来设置自动重装的值,以及分频系数。这两个参数加上时钟频率就决定了定时器的溢出时间。

3 、设置TIM3_DIER 允许更新中断。

因为我们要使用TIM3的更新中断,所以设置 DIER的UIE 位,并使能触发中断

4 、允许TIM3 工作。

光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过TIM3_CR1 的CEN位来设置。

5 、TIM3 中断分组设置。

在定时器配置完了之后,因为要产生中断,必不可少的要设置NVIC相关寄存器,以使能 TIM3中断

6 、编写中断服务函数。

在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器SR 的最低位。在处理完中断之后应该向TIM3_SR的最低位写 0 ,来除该中断标志

程序设计

//TIMER.C

#include "timer.h"
#include "led.h"
//通用定时器 驱动代码
//定时器3中断服务程序
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
LED1=!LED1;
}
TIM3->SR&=~(1<<0);//清除中断标志位
}
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void timerx_init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1;//TIM3时钟使能
TIM3->ARR=arr; //设定计数器自动重装值//刚好1ms
TIM3->PSC=psc; //预分频器7200,得到10Khz的计数时钟
//这两个东东要同时设置才可以使用中断
TIM3->DIER|=1<<0; //允许更新中断
TIM3->DIER|=1<<6; //允许触发中断
TIM3->CR1|=0x01; //使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//抢占1,子优先级3,组2
}

Timerx_Init 函数就是执行我们上面介绍的那5 个步骤,使得TIM3开始工作,并开启中断。

该函数的2 个参数用来设置 TIM3 的溢出时间

因为我们在 Stm32_Clock_Init 函数里面已经初始化APB1的时钟为 2 分频,所以APB1的时钟为36M ,而从 STM32的内部时钟树图(<<STM32参考手册>>第56 页,图 8 )得知:当 APB1的时钟分频数为1 的时候,TIM2~7 的时钟为 APB1的时钟而如果 APB1的时钟分频数不为1 ,那么 TIM2~7 的时钟频率将为APB1时钟的两倍。因此,TIM3的时钟为72M ,再根据我们设计的 arr和psc 的值,就可以计算中断时间了。

计算公式如下:

Tout= (arr*(psc+1))/Tclk;

Tclk :TIM3的输入时钟频率(单位为Khz)。
Tout :TIM3溢出时间(单位为ms)。

//MAIN.C

#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdg.h"
#include "timer.h"
//定时器中断
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72);	//延时初始化
uart_init(72,9600); //串口初始化
led_init();	//初始化与LED连接的硬件接口
timerx_init(5000,7199);//10Khz的计数频率,计数到5000为500ms
while(1)
{
LED0=!LED0;
delay_ms(200);
}
}

此段代码对TIM3 进行初始化之后,进入死循环等待TIM3溢出中断,当TIM3_CNT 的值等于TIM3_ARR 的值的时候,就会产生TIM3 的更新中断,然后在中断里面取反LED1,TIM3_CNT 再从0 开始计数。



提交评论