简介
定时器几乎是每个单片机必有的重要外设之一,可用于定时、精确延时、计数等等,在检测、控制领域有广泛应用。
Timer 运行时不占用 CPU 时间,配置好之后,可以与 CPU 并行工作,实现精确的定时和计数,并且可以通过软件控制其是否产生中断,使用起来灵活方便
。
nRF52832 共有 5 个 32 位的 Timer (Timer0~Timer4),它们都可以工作于定时和计数两种模式,并且 Timer的时钟频率和位宽都可以配置。
Timer 时钟源
Timer 使用的时钟源来自 PCLK1M 或 PCLK16M,系统会根据设置的 Timer 时钟频率,fTIMER 自动选择使用哪一个时钟源,即时钟源的设置是无需软件操作的,当我们设置了 Timer时钟频率后,系统会根据时钟频率自动选择时钟源
,选择的依据如下:
⚫ 当 fTIMER > 1 MHz 时,定时器模块使用 PCLK16M 作为时钟源。
⚫ 当 fTIMER <= 1 MHz 时,定时器模块使用 PCLK1M 代替 PCLK16M,从而降低功耗
nRF52832 Timer 时钟频率
Timer 的时钟频率 fTIMER 计算公式如下,无论时钟源使用的是 PCLK1M 或 PCLK16M,时钟频率计算时都以 16 MHz 为基准
。
f_TIMER = 16 MHz / (2^PRESCALER)
分频系数可设置的范围是 0~9, 根据上式可计算出时钟频率.
Timer 位宽
nRF52832 的 5 个定时器最大位宽都是 32 位,位宽可以通过 BITMODE 寄存器配置,可配置的位宽有 8 位、 16 位、 24 位和 32 位
Timer 启动和停止
Timer 可以工作于定时或计数模式,无论在哪种模式下, Timer 都是通过触发 START 任务启动,通过触发 STOP 任务寄存器来停止的。 Timer 停止后,触发 START 任务寄存器可以让它再次启动,启动后,定时器将继续从它之前被停止时的值继续计数
。
Timer0定时器使用代码示例
1.定时器需要引用的头文件
#include "nrf_drv_timer.h"
2.定义Timer0
驱动程序实例的ID对应Timer的ID,如NRF_DRV_TIMER_INSTANCE(0)对应Timer0
const nrfx_timer_t TIMER_LED = NRFX_TIMER_INSTANCE(0);
3.Timer事件回调函数
void timer_led_event_handler(nrf_timer_event_t event_type, void* p_context)
{
switch (event_type)
{
//因为我们配置的是使用CC通道0,所以事件回调
//函数中判断NRF_TIMER_EVENT_COMPARE0事件
case NRF_TIMER_EVENT_COMPARE0:
//翻转指示灯D1状态
nrf_gpio_pin_toggle(LED_1);
break;
default:
//Do nothing.
break;
}
}
4.定时器初始化
void timer_init(void)
{
uint32_t err_code = NRF_SUCCESS;
//定时时间200ms
uint32_t time_ms = 200;
//保存定时时间对应的Ticks
uint32_t time_ticks;
//定义定时器配置结构体,并使用默认配置参数初始化结构体
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
//初始化定时器,初始化时会注册timer_led_event_handler事件回调函数
err_code = nrfx_timer_init(&TIMER_LED, &timer_cfg, timer_led_event_handler);
APP_ERROR_CHECK(err_code);
//定时时间(单位ms)转换为ticks
time_ticks = nrfx_timer_ms_to_ticks(&TIMER_LED, time_ms);
//设置定时器捕获/比较通道及该通道的比较值,使能通道的比较中断
nrfx_timer_extended_compare(
&TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
}
实验效果
每隔200切换一次LED等的亮灭。
关于nrf52382计数器的使用(以timer0为例)
//定义Timer0的驱动程序实例。驱动程序实例的ID对应Timer的ID,如NRF_DRV_TIMER_INSTANCE(0)对应Timer0
头文件
const nrfx_timer_t TIMER_COUNTER = NRFX_TIMER_INSTANCE(0);
//Timer事件回调函数
void my_timer_event_handler(nrf_timer_event_t event_type, void* p_context){}
定时器计数器配置
//定时器配置计数器初始化
void timer_init(void)
{
uint32_t err_code = NRF_SUCCESS;
//定义定时器配置结构体,并使用默认配置参数初始化结构体
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
//Timer0配置为计数模式
timer_cfg.mode = NRF_TIMER_MODE_COUNTER;
//初始化定时器,定时器工作于计数模式时,没有事件,所以无需回调函数,但是nrfx_timer_init函数说明中要求必须提供回调函数,
//这里我们提供一个空的回调函数用于注册。
//另外,经过实际测试,不提供回调函数,即参数设置为NULL也是可以的
err_code = nrfx_timer_init(&TIMER_COUNTER, &timer_cfg, my_timer_event_handler);
//err_code = nrfx_timer_init(&TIMER_COUNTER, &timer_cfg, NULL);
APP_ERROR_CHECK(err_code);
}
启动定时器计数器
//启动定时器
nrfx_timer_enable(&TIMER_COUNTER);
int main()
{
//用于保存读取的计数值
uint32_t timVal = 0;
while(1)
{
//定时器计数值加1
nrfx_timer_increment(&TIMER_COUNTER);
//获取计数值
timVal = nrfx_timer_capture(&TIMER_COUNTER,NRF_TIMER_CC_CHANNEL2);
printf("conut value: %d\r\n", timVal);
//延时1秒
nrf_delay_ms(1000);
}
}
实验效果
每次主动加1,获取的计数值则加1, 否则计数值不变。