接着我们上一章(LED灯的点亮)的旅行!上一章我们使用了DSP的GPIO去点亮我们的LED灯,我们为了让人眼能够直接的感受LED的闪烁我们用到了一个延迟函数。但是这样的延迟是让CPU空转,while内部的。当然这样我们不好精确的计算出延迟了多长时间,幸好DSP内部用一个32bit的定时计数器(其实最简单的单片机里面都会有集成的8bit或者16bit定时计数器),我们可以使用它来精确的定时。一般定时计数器有两个功能,一是定时:时钟源一般来源于DSP内部,当然也可以选择来自于外部。二是计数:我们可以利用它的功能来计算外部脉冲在一段时间内到来的次数,所以叫做计数器(记录外部脉冲的次数)。因为内部有一个计数的count,如果用作定时就是先输入一个数字,然后在来了一个时钟之后count自动减一。如果用成计数就是在一个脉冲到来之后count自动加一!
DSP6713内部有两个32bit的定时计数器(timer0和timer1),两个基本上是一样的。我们先来看看定时器的内部构造:
大家通过这样的原理框图就可以看出哪些bit影响哪些功能,比如CLKSRC bit就是选择时钟源,为“0”选择TINP脚的和INVINP的异或信号作为时钟源,“1”选择的是CPU内部时钟源,为CPU主频的1/4.我们的DSP主频可以达到450MHz,那么我们的定时器使用的时钟就是112.5MHz。GO bit就是使能定时器,让定时器开始计数,也就是定时开始信号。HLD bit就是暂停和继续计数器控制位。我们来看看Timer Control Register (CTL)寄存器的的实际用法
我们这儿使用的是定时功能,所以我们就把红色标记的几个bit置成“1”,我们先分析一下这几个bit的意义。
一、设置CLKSRC bit位为“1”,这样就使用CPU内部的时钟源,CPU的主频的4分频。
二、设置CP bit位为“1”,这样我时钟源的占空比就为50%了。这样就把timer的时钟源选定了!
三、设置PWID bit为“1”这样我们的定时器到时时,产生一个脉冲信号,这个信号的有效电平的时钟长度为两个时钟源周期。如果为“0”那么就是一个时钟源周期。
四、设置GO bit为“0”这样定时器暂时不计数!
看看timer1模块在DSP内部的地址映射
设置控制器CTL *(unsigned int *)0×01980000 &=~(1<<7|1<<6) ;停止定时器,*(unsigned int *)0×01980000 |=1<<9|1<<8|1<<4;设置定时器的运行模式。*(unsigned int *)0×01980004=0x0000ffff;设置定时器周期为0xffff,这个值会在定时器开始时把这个值装入count中,然后在每一个时钟源周期自动将这个值减一。当这个count减成“0”时就在TSTAT位置“1”这样就产生一个timer事件,这个事件可以中断CPU和使能EDMA。最后在打开定时器计数,开始运行。*(unsigned int *)0×01980000 |=1<<6;置GO bit为“1”。我们可以查询一下cnt寄存器的值,这个是实时的定时器的计数值。为“0”的时候就是定时器到时了我们可以用语句:while((*(unsigned int *)0×01980008)!=0);这样CPU也是空循环等待定时器到时!
主要的程序代码为:
void main()
{
*(unsigned int *)0×01980000 &=~(1<<7|1<<6) ;
*(unsigned int *)0×01980000 |=1<<9|1<<8|1<<4;
*(unsigned int *)0×01980004=0x0000ffff;
while(1)
{
while((*(unsigned int *)0×01980008)!=0);
*(unsigned int *)0x01B00008 &=~(1<<13);//点亮LED
while((*(unsigned int *)0×01980008)!=0);
*(unsigned int *)0x01B00008|=1<<13; //熄灭LED
}
} |