1.概述

nRF51822拥有三个定时器,分别是:TIMER0,TIMER1,TIMER2,如下图:

freemodbus定时器 定时器prescaler_工作模式

三个定时器有不同的位宽,位宽大小决定了计数器的最大溢出时间。

2. 内部结构分析

freemodbus定时器 定时器prescaler_工作模式_02

(1)时钟源选择:

定时器TIMER工作在高时钟源(HFLCK)下,同时包含了一个4位的分频器(PRESCALER),可以对高频时钟源进行分频。时钟源的输入包含两种模式: 1MHZ(PCLK1M)和(PCLK16M)模式,经过分频后得到一个频率f_timer,系统根据f_timer自动选择时钟源,不需要设置。

频率

时钟

f_timer > 1MHz

选择PCLK16M

f_timer <= 1MHz

选择PCLK1M

(2)分频器:

分频器计算如下:

freemodbus定时器 定时器prescaler_工作模式_03

HFCLK无论哪种时钟源,均为16MHz,PRESCALER为一个4位分频器,分频值为0——15。当PRESCALER大于9后,分频始终为2的9次方,即最小频率f=16mhz / 2^9。

freemodbus定时器 定时器prescaler_freemodbus定时器_04

(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;//停止定时器
}