1.概述
nRF51822拥有三个定时器,分别是:TIMER0,TIMER1,TIMER2,如下图:
三个定时器有不同的位宽,位宽大小决定了计数器的最大溢出时间。
2. 内部结构分析
(1)时钟源选择:
定时器TIMER工作在高时钟源(HFLCK)下,同时包含了一个4位的分频器(PRESCALER),可以对高频时钟源进行分频。时钟源的输入包含两种模式: 1MHZ(PCLK1M)和(PCLK16M)模式,经过分频后得到一个频率f_timer,系统根据f_timer自动选择时钟源,不需要设置。
频率 | 时钟 |
f_timer > 1MHz | 选择PCLK16M |
f_timer <= 1MHz | 选择PCLK1M |
(2)分频器:
分频器计算如下:
HFCLK无论哪种时钟源,均为16MHz,PRESCALER为一个4位分频器,分频值为0——15。当PRESCALER大于9后,分频始终为2的9次方,即最小频率f=16mhz / 2^9。
(3)工作模式:
分别为定时器(TIMER)和计数器(COUNTER)。通过寄存器MODE进行设置,MODE = 0—>定时器;MODE= 1 —>计数器。
定时器为递增计数,每一个时钟频率,计数器自增加1;
计数器模式下,每当触发一次寄存器COUNT event,定时器内部的计数器寄存器就会增加1。
(4)比较/捕获功能:
定时器模式下设置比较(COMPARE)/捕获(CAPTURE)寄存器CC[n]的值,可以设置定时时间(Timer value),当定时时间的值和CC[n]寄存器的值相等时,将触发一个比较(COMPARE[n] event)事件。
计数器模式下通过设置一个CAPTURE TASK,当计数器的值和比较/捕获寄存器设定的值(Timer value)相等的时候,将产生一个捕获事件(Capture[n] event)。捕获的值将会存储到寄存器CC[n]中读取。
COMPARE[n] event和Capture[n] event都可以触发中断,若为周期性触发,需要在出发后清除计数值,否则会一直计数,直至溢出。
3. 简单实现例程
//定时器初始化
volatile NRF_TIMER_Type *timer_init(timer_t timer)
{
volatile NRF_TIMER_Type *p_timer;
//开启高速16MHZ时钟
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
//等待外部振荡器启动
while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
{
}
switch(timer)
{
case TIMER0:
p_timer = NRF_TIMER0;
break;
case TIMER1:
p_timer = NRF_TIMER1;
break;
case TIMER2:
p_timer = NRF_TIMER2;
break;
default:
p_timer = 0;
break;
}
return p_timer;
}
void nrf_timer_delay_ms(timer_t timer,uint_fast16_t volatile number_of_ms)
{
volatile NRF_TIMER_Type *p_timer = timer_init(timer);
if(p_timer == 0)
{
while(1);
}
p_timer->MODE = TIMER_MODE_MODE_Timer;//定时or计数模式选择
p_timer->PRESCALER = 9;//分频:16MHZ/9=31250Hz
p_timer->BITMODE = 16;//16位模式
p_timer->TASKS_CLEAR = 1;//清除定时器
p_timer->CC[0] = number_of_ms * 31;//值为:31000
p_timer->CC[0] += number_of_ms / 4;//值为:250
p_timer->TASKS_START = 1;//开始定时器
while(p_timer->EVENTS_COMPARE[0] == 0)//触发后将事件置为1
{
}
p_timer->EVENTS_COMPARE[0] = 0;//清0比较定时器
p_timer->TASKS_STOP = 1;//停止定时器
}