定时器1使用总结

  • 格式:pdf
  • 大小:661.74 KB
  • 文档页数:6

定时器1

1 目的说明

实现定时器最简单的溢出中断

的速度不断闪烁。这样的实验还是非

码,自己第一次在CC2430上实现

2 使用方法概述

需要使用定时器的中断,需要知

需要两个条件,第一IEN1.T1EN需要置

模式,使用该模式可以改变定时器溢

3 代码总览

先来看看所有的代码,然后再分

//头文件

#include "hal.h"

//函数声明

void Timer1_Init();

//主函数

void main(){

//初始化外部时钟

SET_MAIN_CLOCK_SOURCE(CRYST

//P1_0 输出

IO_DIR_PORT_PIN(1,0,IO_OUT);

//初始化定时器1

Timer1_Init();

while(1){

} 使用总结——溢出中断

中断,结合我手头的开发板,使得位于P10的LED灯

还是非常亲切的,让我想起了第一次在51上实现这样

实现,依然非常激动。

需要知道如何操作才可以产生这个中断请求。数据手册

需要置位,第二TIMIF.OVFIM需要置位。代码中使用mod

时器溢出的频率。

后再分步解释。

(CRYSTAL);

UT); ,以2HZ

了这样的代

手册中提到modulo、}

void Timer1_Init(){

//定时器1复位

TIMER1_INIT();

//设定定时器相关参数

//128分频0000 1100

T1CTL = 0x0c;

//溢出值低8位

T1CC0L=0x24;

//溢出值高8位

T1CC0H=0xF4;

//定时器T1溢出中断使能

TIMER1_ENABLE_OVERFLOW_INT(TRUE);

//定时器T1中断使能

INT_ENABLE(INUM_T1,INT_ON);

//全局中断使能

INT_GLOBAL_ENABLE(INT_ON);

//启动定时器1

TIMER1_RUN(TRUE);

}

//定时器1中断函数

#pragma vector=T1_VECTOR

__interrupt void Timer1_ISR(void)

{

//检查中断标志位

if(T1CTL & 0x10){

//LED灯反转

P1_0 = !P1_0;

//清中断标志

T1CTL &= ~0x10;

}

}

4 主函数说明

//初始化外部时钟

SET_MAIN_CLOCK_SOURCE(CRYSTAL);

//P1_0 输出 IO_DIR_PORT_PIN(1,0,IO_OUT);

//初始化定时器1

Timer1_Init();

操作CC2430之前,先指定系统

率有关,所以必须要设定好系统的时

把系统时钟设定为32MHz。(该宏前

请注意定时器的时钟频率 默认为

请注意CLKCON的5:3位,

时器的时钟频率。在定时器1的相关

特有的,这里的定时器分频参数是分

为了操作IO口,定义LED相关的

代码所示: #define IO_DIR_PORT_PIN(port, pin, di

do {

if (dir == IO_OUT)

P##port##DIR |= (0x01<<(p

else

P##port##DIR &= ~(0x01<<

}while(0)

该宏操作了PXDIR寄存器,定义

5 定时器初始化操作

TIMER1_INIT()把定时器1的寄存

#define TIMER1_INIT() \

do { \

T1CTL = 0x00; \

T1CCTL0 = 0x00; \

T1CCTL1 = 0x00; \

T1CCTL2 = 0x00; \

TIMIF &= ~0x40; \

} while (0)

从这个代码中也可以看出定时器

手册,这里不多做说明。

6 设定定时器中断频率

操作代码如下

时钟,这是一个好习惯。由于定时器时钟和系统

统的时钟。在SET_MAIN_CLOCK_SOURCE()在这个

宏前面的文章已经提到,不多做说明)

16MHz,而不是32MHz。 该3位组成了一个定时器时钟的分频器,该参

操作中还有定时器时钟的分频系数设置,那是定时

数是分频了定时器1,3,4的时钟。相见数据手册或下图

IO口为输出。IO_DIR_PORT_PIN()的相关操作如下

pin, dir) \

\

\

1<<(pin)); \

\

x01<<(pin)); \

定义了IO口的方向。

器全部复位。具体的代码如下:

定时器1的操作和哪些寄存器有关。具体的定义可以看

频率

系统时钟频

动作宏中,

数决定了定

是定时器1

下图:

作如下面的

以查看数

据 //128分频0000 1100

T1CTL = 0x0c;

//溢出值低8位

T1CC0L=0x24;

//溢出值高8位

T1CC0H=0xF4;

由于CC2430的运行速度比较快,所以需要对定时器1进行分频。由于T1CTL在前面的

函数中已经被全部复位,所以可以舒服的操作T1CTL寄存器。在这里把系统时钟设定为128

分频,定时器T1的运行速度只有125K。这个速度对于0.5闪烁来说,还是非常快的。 接着设定T1CC0寄存器。这个寄存器还是非常特殊的。请注意,T1CC0在modulo模式

和up-down模式中,始终作为定时器T1计数的最大值。数据手册上说定时器1有3个比较

匹配中断,其实这个和AVR的定时器1有的两个比较匹配时一样的,因为CC2430没有一个

专用寄存器储存计数的最大值,那么定时器1的比较通道0就“牺牲”了比较通道的作用。

所以要产生两路频率指定的PWM波的时候,T1CC0作为最大值决定PWM的频率,而T1CC1

和T1CC2决定PWM的相位。 下面再讲讲计数值的计算方法。我是从分频的角度思考的,写出这个等式:

Ftimer/(N*T1CC0) = Fdesi。

其中Ftimer为定时器的运行时钟,此处为16,000,000Hz;N为分频系数,此处为128;T1CC0为定时器的计数值;Fdesi为期望溢出频率,此处为2Hz。带入这个等式可以计算出

T1CC0的值为62500,写成16进制为F424。如果计算出来的结果大于65536,那么只能进

一步降低定时器的运行频率,在这里只能调整Ftimer了。

7 使能该使能的内容

//定时器T1溢出中断使能

TIMER1_ENABLE_OVERFLOW_INT(TRUE);

//定时器T1中断使能

INT_ENABLE(INUM_T1,INT_ON);

//全局中断使能

INT_GLOBAL_ENABLE(INT_ON);

开篇的时候就说了需要操作哪两个寄存器——第一IEN1.T1EN,第二TIMIF.OVFIM。操作

时分别使用了以下两个宏。具体的代码如下: #define TIMER1_ENABLE_OVERFLOW_INT(val) \

(TIMIF = (val) ? TIMIF | 0x40 : TIMIF & ~0x40)

#define INT_ENABLE(inum, on) \

do { \

if (inum==INUM_RFERR) { RFERRIE = on; } \

else if (inum==INUM_ADC) { ADCIE = on; } \

else if (inum==INUM_URX0) { URX0IE = on; } \

else if (inum==INUM_URX1) { URX1IE = on; } \

else if (inum==INUM_ENC) { ENCIE = on; } \

else if (inum==INUM_ST) { STIE = on; } \

else if (inum==INUM_P2INT) { (on) ? (IEN2 |= 0x02) : (IEN2 &= ~0x02); } \

else if (inum==INUM_UTX0) { (on) ? (IEN2 |= 0x04) : (IEN2 &= ~0x04); } \ else if (inum==INUM_DMA) { DMAIE = on; } \

else if (inum==INUM_T1) { T1IE = on; } \

else if (inum==INUM_T2) { T2IE = on; } \

else if (inum==INUM_T3) { T3IE = on; } \

else if (inum==INUM_T4) { T4IE = on; } \

else if (inum==INUM_P0INT) { P0IE = on; } \

else if (inum==INUM_UTX1) { (on) ? (IEN2 |= 0x08) : (IEN2 &= ~0x08); } \

else if (inum==INUM_P1INT) { (on) ? (IEN2 |= 0x10) : (IEN2 &= ~0x10); } \

else if (inum==INUM_RF) { (on) ? (IEN2 |= 0x01) : (IEN2 &= ~0x01); } \

else if (inum==INUM_WDT) { (on) ? (IEN2 |= 0x20) : (IEN2 &= ~0x20); } \

} while (0)

最后还要操作一个“总”中断,这个是51中断的老大——全局中断EA。有点基础的一

定知道这个东西,代码如下: // Global interrupt enables

#define INT_GLOBAL_ENABLE(on) EA=(!!on)

(不知道为什么来个双重否定????)

8 启动定时器T1

准备好所有的初始化代码之后,才开始启动定时器。在启动定时器就是选择工作方式(也

搞不明白为什么CC2430不来一个定时器启动相关的寄存器),把工作方式定义为modulo模

式。具体的代码如下: #define TIMER1_RUN(value) (T1CTL = (value) ? T1CTL|0x02 : T1CTL&~0x03)

由于默认的初始值为00(从第0位开始),把第1位置位就相当于选择了modulo模式,清

零保留默认模式。

9 定时器中断

#pragma vector=T1_VECTOR

__interrupt void Timer1_ISR(void)

{

//检查中断标志位

if(T1CTL & 0x10){

//LED灯反转

P1_0 = !P1_0;

//清中断标志

T1CTL &= ~0x10;

}

}

所有的中断都有固定的写法,这个大家必须牢牢记住。先使用伪命令定义中断入口地址:#pragma vector=T1_VECTOR,然后定义函数名称__interrupt void Timer1_ISR(void)。通过检测

OVFIM(T1CTL 第4位)来判断是否发生了溢出中断,最后通过软件清除中断标志位。(但

是我发现不清除中断标志位同样可以再次进入中断,最后查看数据手册,如何清除这个中断