【第四批】从51跳新唐cortex学习3——细说新唐两种定时器
新唐中的有关时间的寄存器
我们知道,我们在使用任何一种芯片的时候,定时器对我们的编程和使用是至关重要的,对于51的定时器我们已经是相当熟悉啦。但是,对于第一次接触新唐,第一次接触cortex的人来说,对其上定时器可能还是比较模糊的。严格来说,新唐 cortex是有两种定时器(注意,是两种)。
1.
时钟控制寄存器为整个芯片提供时钟源(五种时钟源选择),包括系统时钟和外设时钟,该控制器还通过个别时钟的关或开,时钟源的选择和分频器来进行功耗控制。
2.
定时器控制寄存器(和51的定时器一样,都是加1计数,但是功能和容量变大了),包括4个32位定时器(里面放24位的数据),还有分频功能。TMER0到TMER3。他支持频率测量、计数、间隔时间测量、时钟产生、延时时间等。定时器可以在计时溢出时产生中断,也可在计数中间修改当前值。新唐定时器的中断没有固定的中断入口,也就是我们可以自己设定中断函数(以前在51中我们用的是 函数后加interrupt
而新唐中我们用的是 指向函数的指针)
3.
Cortex中特有的 系统定时器(注意,这与定时器不同,是减1计数)。这是一种简单的24位写清零、递减、子封装灵活控制的计数器。他可以作为rtos的定时器和简单的计数器。系统时钟也是也是可以产生中断的,但是它的中断有固定的中断入口地址(这里又和51变成一样的啦),也就是中断函数放在SysTick_Handler() 中(用过OS的人相比对这个函数是相当熟悉的)。所以,我们一般将这个系统定时器保留给操作系统,这里是我见论坛里有人将他当做普通的定时器用,所以特意指出来以供新手了解。
由以上可知,自己的工程中要使用定时器,无非就是两种,一种是我们普通的定时器(TMR) ,另一种是使用系统定时器(SysClk)。而无论我们使用那种定时器之前都要先对时钟控制寄存器进行配置。下面我们依次讲解两种定时器的使用:
一、系统定时器(SYSTick)
先说使用系统定时器作为定时器的方式配置。
1、首先为系统时钟选择时钟源(晶振)。
主要是设定AHB ->CLK_BA->CLKSEL0->STCLK_S 。我们一般选择外部晶振(要是当做普通的定时器来用的话)
2、之后配置系统定时控制寄存器SysTick
SysTick主要配置SYST_CSR,SYST_RVR,SYST_CVR。
SYST_CSR下配置的第0,1,2位;
SYST_RVR 下配置第0到23位
SYST_CVR下配置第0到23位
以上寄存器配置完成后,系统会自动进行定时。定时时间到,系统自动跳去执行中断函数SysTick_Handler()中的程序。
二、定时器TMR
1、和上面一样,首先配置时钟控制寄存器,选择时钟源(晶振)
AHB 下的CLK_BA -> CLKSEL1的 TMRx 位。
我们现在用他的定时器功能,选择外部晶振。
2、定时控制器TMR配置
新唐的定时器好多模式,什么4种模式5个时钟源什么的,好多,所以我们基本上是先查自己需要的模式,在进行设置。
我们就以TMR0为例
TCSR主要设置第0-31位,当然,上面有许多是无定义的位。
TCMPR下主要设置第0-23位。
TISR设置第0位。
TDR设置第0-23位
这里需要说明一点的是,定时器中断函数的入口地址是由我们用户来进行设定的。其函数为DrvTIMER_SetTimerEvent()来设置的。其中有一个指向函数的指针来调用中断函数。
上面我们介绍了如何进行两种定时器的配置,那么接下来我们就通过一个例子,来了解具体工程中是如何应用两种定时器的。本来是不打算上例子的,因为从我的心里一直感觉:一种东西的思想远比一种东西的用法重要,所以在我的前两篇51跳新唐cortex——思想转变和程序详解中,都是以讲述新唐思想、编程思想为主。但是近期看了一下大家的笔记,可能更是热衷于贴出来程序。呵呵 不过我也从大家的程序中找到了许多应用的知识。所以,在此,我也贴上一个定时器有关的例程,以供大家对照、比对、参考学习。
本例程led_bee_timer 主要是使用新唐中的两种定时器,分别用作led灯和蜂鸣器的计时。其中,使用系统定时器(SYSTICK)来为蜂鸣器定时,蜂鸣器间歇性开关发声;使用定时器(TMR0)来控制LED流水灯定时。两种定时器都使用了中断函数进行目标的控制,大家要注意两种中断的异同。例程中保留了调试时的东西,希望大家也可以从中看到些许调试技巧。例程中为了方便,并没有套用程序框架,是进行的裸编程,而适合新唐的程序框架,笔者也正在摸索之中,哪位有比较成熟的框架结构,还希望共享一下。呵呵,先啰嗦到这里,下面附上例程:
#include"include.h"
E_TYPE_LED temp_led;
static uint32_t flag_100ms = 0;
//uint8_t test = 0;
void AllLedOff()
{
DrvGPIO_SetBit(E_GPA,2);
DrvGPIO_SetBit(E_GPA,3);
DrvGPIO_SetBit(E_GPA,4);
DrvGPIO_SetBit(E_GPA,5);
}
void Tim0CALLBACK(void) //定时器0中断函数 执行LED
{
// DrvGPIO_ClrBit(E_GPA,2);
// DrvGPIO_ClrBit(E_GPA,5);
switch(temp_led++)//(test++)
{
case LED1 ://1:
AllLedOff();
DrvGPIO_ClrBit(E_GPA,2);
break;
case LED2 ://2:
AllLedOff();
DrvGPIO_ClrBit(E_GPA,3);
break;
case LED3 ://3:
AllLedOff();
DrvGPIO_ClrBit(E_GPA,4);
break;
case LED4 : //4:
AllLedOff();
DrvGPIO_ClrBit(E_GPA,5);
break;
default :
AllLedOff();
temp_led = LED1;//test = 1;
break;
}
}
void BeeOn() //蜂鸣器
{
DrvGPIO_SetBit(E_GPB,10); //怎么读入某位的值
}
void BeeOff()
{
DrvGPIO_ClrBit(E_GPB,10);
}
void SysTick_Handler(void) //系统定时器中断函数
{
flag_100ms++;
if(flag_100ms <= 100)
{
// DrvGPIO_ClrBit(E_GPA,4);
// DrvGPIO_SetBit(E_GPA,5);
BeeOn();
}
else if((flag_100ms > 100) && (flag_100ms <= 200))
{
// DrvGPIO_ClrBit(E_GPA,5);
// DrvGPIO_SetBit(E_GPA,4);
BeeOff();
}
else if(flag_100ms > 200)
{
flag_100ms = 0;
}
}
void GPIOInit()
{
DrvGPIO_Open(E_GPA,2,E_IO_OUTPUT);
DrvGPIO_Open(E_GPA,3,E_IO_OUTPUT);
DrvGPIO_Open(E_GPA,4,E_IO_OUTPUT);
DrvGPIO_Open(E_GPA,5,E_IO_OUTPUT);
DrvGPIO_Open(E_GPB,10,E_IO_OUTPUT);
}
void TIMERInit()
{
DrvTIMER_Init();
DrvSYS_SelectIPClockSource(E_SYS_TMR0_CLKSRC,0);
DrvTIMER_Open(E_TMR0,1,E_PERIODIC_MODE); //每秒tick数 每秒tick一次
DrvTIMER_SetTimerEvent(E_TMR0,1,(TIMER_CALLBACK) Tim0CALLBACK,0); //定时器的tick周期 每秒1次
// DrvTIMER_Open(E_TMR0,1,E_PERIODIC_MODE); //每秒tick数 每秒tick一次
DrvTIMER_EnableInt(E_TMR0);
DrvTIMER_Start(E_TMR0);
}
void SYSCLKInit()
{
DrvSYS_SelectSysTickSource(0);
SysTick->CTRL = 0x00000003; SysTick->VAL = 0x00000000;
SysTick->LOAD = 0x6000; //100ms
}
void SysInit()
{
UNLOCKREG();
SYSCLK->PWRCON.XTL12M_EN = 1;
LOCKREG();
GPIOInit(); //GPIO 初始化
TIMERInit();
SYSCLKInit();
}
int main()
{
SysInit();
while(1)
{
;
}
}
|