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),就可以延长一秒钟了.很简单吧.