GBA探索日记(6)(Timer)

 

这一节也是将来实现声音播放的基础部分.这一部分的东西十分简单,不过后一节关于中断的部分就有点困难,我们只需要知道怎么用就可以了,所以这一节总体是十分简单的.

 

首先我要自我介绍一下.写了这么多日记,大家可能还不知道我是谁.

我叫tangl_99,email:[email protected],QQ:8664220(Min-Kyeong)

如果你在做GBA过程中有什么问题,可以联系我,我会尽可能地帮助你(只要你不是日本人).

 

 

GBA中的计时器有4个.就是Timer0,Timer1,Timer2,Timer3.

也是很简单地通过读写寄存器就可以实现对它们的使用了.你可以对它们任意使用.不过需要提醒的是Timer0,Timer1通常用来控制声音播放的速度.

每个Timer有两个寄存器来实现使用和控制.

我们先来看看Timer的计数器寄存器.

TMXD就是TimerX的计数器的寄存器.它们都是16位的寄存器,从Address可以看到它们的总线地址,从Attributes可以看出它们都是可读可写的寄存器.

很奇怪的第一点,在官方开发包里对应它们的定义的名字却不是TMXD,而是REG_TMXCNT_L,比如看看Timer0的计数器的定义.

#define REG_TM0CNT_L    (REG_BASE + 0x100)

 

有了计数器,你通过对它的读写,就可以知道现在时间走了多少.

 

然后我们来看看Timer的属性设置寄存器

TMXCNT就是TimerX的属性寄存器.它们的属性很简单,我们大致来看看吧.

 

7位的Timer Operation Flag就是Timer的开关.

如果设置成0,就是关于这个Timer;如果设置成1,就是开始使用这个Timer.

 

6位是Timer中断的开关.

Timer的中断是当Timer的计数器产生一个溢出,就产生一个中断.溢出简单地说就是前面的Timer的计数器的值超过了最大值(0xFFFF).至于如何编写中断服务程序我将在后面说使用的方法.

 

2位是Count-up Timing表明是否需要使用Prescalar Selection的协调

设置成0,表示使用后面的Prescalar Selection.

设置成1的时候我就不知道是什么意思了,我也从来没有用过,如果你有兴趣,你可以研究一下.AgbLib中这么描述它的.

With a setting of 0, count-up is performed in accordance with the prescalar specification in [d01-00]. With a setting of 1, overflow of the timer channel one number lower starts a count-up regardless of the prescalar specification.

This mode is suitable for purposes such as time measurement over relatively long periods.

The count-up timing specification is disabled for Timer 0, which counts up in accordance with the prescalar specification

我们一般都不管它,一般都设置0,使用.

不过对于Timer0这个选项是无效的.

 

0,1位是Prescalar Selection,就是Timer的时间标准.

所有的Prescalar都是以GBA的16.78MHz的CPU时钟频率为基础

Setting       Prescalar (Count-Up Interval) 

00            System clock   (59.595 ns) 

01            64 cycles of system clock   ( 3.814 us) 

10            256 cycles of system clock  (15.256 us) 

11            1024 cycles of system clock  (61.025 us) 

其中ns是1/10^9秒,us是1/10^6秒.

可以说都是很快的了.

比如我把它设置成11,那么每61.025 us,Timer的计数器就自加1.同理设置成10那么就是15.256 us,Timer的计数器就自加1.

 

 

好了,我们来看看一个例子,写个延时的函数(相当于Windows里的Sleep函数)

#define REG_TM0CNT      (REG_BASE + 0x100)  // Timer 0

#define REG_TM0CNT_L    (REG_BASE + 0x100)

#define REG_TM0CNT_H    (REG_BASE + 0x102)

#define REG_TM1CNT      (REG_BASE + 0x104)  // Timer 1

#define REG_TM1CNT_L    (REG_BASE + 0x104)

#define REG_TM1CNT_H    (REG_BASE + 0x106)

#define REG_TM2CNT      (REG_BASE + 0x108)  // Timer 2

#define REG_TM2CNT_L    (REG_BASE + 0x108)

#define REG_TM2CNT_H    (REG_BASE + 0x10a)

#define REG_TM3CNT      (REG_BASE + 0x10c)  // Timer 3

#define REG_TM3CNT_L    (REG_BASE + 0x10c)

#define REG_TM3CNT_H    (REG_BASE + 0x10e)

 

再次提醒大家,REG_TMXCNT_H是属性控制寄存器,REG_TMXCNT_L是计数器.

void wait(u16 ms)

{

                //Start the timer

            *(vu16 *)REG_TM3CNT_H  = 1|2 | 128;

                //zero the timer

                *(vu16 *)REG_TM3CNT_L = 0;

                while(ms--)

                {

                                                while(*(vu16 *)REG_TM3CNT_L <= 16.386){}                //wait

                                                *(vu16 *)REG_TM3CNT_L = 0;          //reset the timmer

                }

}

这个函数很简单,参数ms是需要延时的毫秒数.

至于里面的16.386是因为16.386*61.025us近似等于1ms.

你可以把这个函数写到你的程序里面,然后用wait(1000),就可以延长一秒钟了.很简单吧.

金点 tangl_99

2003/2/9