什么是APP定时器
APP 定时器基于实时计数器 RTC1 的软件定时器,我们看到 RTC,首先想到的是用来记录时间的实时时钟,但是要注意,nRF52832 的 RTC并不是指实时时钟,我们不能通过 nRF52832 的 RTC 直接获取时间信息,nRF52832 的 RTC指的是对振荡源脉冲进行计数的实时计数器。SDK 中的 APP 定时器是使用 RTC1 作为时基来实现的。APP 定时器是基于实时计数器 RTC1、通过链表实现的软件定时器,APP 定时器具有软件定时器的一般特征,应用程序可以配置、创建、启动和停止定时器,应用程序也可以同时创建多个定时任务。
APP定时器的优缺点
优点:BLE总会启动RTC1,软件定时器又是基于RTC1,可创建的定时器数量多,能实现更长时间的定时,使用更灵活、方便。更重要的是省电,尤其在 BLE 应用中,省电效果更明显。
缺点:如果调用者优先级高,则在返回之前不会执行软件定时器的回调,不适用短时间定时,占用CPU时间。
APP定时器的种类
单次定时器:定时器会从应用程序设置的初始时间开始,以tick为计时单位进行倒计时,当计数值减为0时调用回调函数执行。回调函数执行完毕,则定时器停止。
周期定时器:周期定时器在时间到期执行完回调函数后,重新开始计时,直到下次时间到期,再次执行回调函数,然后一直循环下去。
创建APP定时器流程
定义APP定时器和超时时间 -> 编写超时事件回调函数 -> 初始化APP定时器程序模块 -> 创建单次定时器/创建周期定时器 -> 启动创建定时器
接下来我们来具体看这个APP定时器如何使用
1.定义APP定时器
APP定时器使用宏APP_TIMER_DEF定义具体的定时器
2.确定定时时间
因为我们的APP定时器是基于RTC1的,RTC只能分辨出tick,也就是时钟节拍,但是这个时钟节拍和时间的对应关系需要我们去计算,需要修改时间时都要我们去计算的话,非常麻烦。所以我们的SDK专门提供了一个宏来解决我们此时的问题。
这里面的单位是ms。也就是我们的超时时间设置成了100ms。
3.编写超时事件回调函数
APP 定时器超时后即会回调创建定时器时注册的超时事件回调函数,该回调函数即是
应用程序实现功能的地方,在这个函数里面,我们可以编写功能代码。
4.初始化APP定时器
使用 APP 定时器时,需要引用头文件“app_timer.h”。
初始化函数
这直接在主函数中调用就可以APP定时器初始化完成了
5.创建APP定时器
APP 定时器通过调用 app_timer_create()函数创建的。
APP定时器模式分为两种
6.启动/停止APP定时器
APP 定时器创建成功后并不会启动,需要应用程序去启动。启动和停止一个 APP 定时
器的函数分别是 app_timer_start()和 app_timer_stop()。
app_timer_start():
app_timer_stop():
全部代码:
#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "boards.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "app_timer.h"
//定义APP定时器m_led_toggle_timer_id(LED定时器),用于驱动指示灯D1,每100ms翻转一次D1的状态
//定义一个APP定时器
APP_TIMER_DEF(led_toggle_timer_id);
//LED定时器超时时间:100ms
#define LED_TOGGLE_INTERVAL APP_TIMER_TICKS(100)
//配置低频时钟,时钟源设置的是外部32.768KHz晶体
static void lfclk_config(void)
{
//初始化时钟模块,设置低频时钟源
ret_code_t err_code = nrf_drv_clock_init();
APP_ERROR_CHECK(err_code);
//请求低频时钟,输入参数为NULL表示低频时钟启动后不产生事件
nrf_drv_clock_lfclk_request(NULL);
}
//LED定时器超时事件回调函数
static void led_toggle_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
nrf_gpio_pin_toggle(LED_1);
}
//初始化APP定时器程序模块和创建APP定时器
static void timers_init(void)
{
ret_code_t err_code;
//初始化APP定时器程序模块
err_code = app_timer_init();
//检查错误代码
APP_ERROR_CHECK(err_code);
//创建APP定时器:LED定时器,周期定时器,启动后周期运行,用于驱动指示灯闪烁
err_code = app_timer_create(&led_toggle_timer_id,
APP_TIMER_MODE_REPEATED,
led_toggle_timeout_handler);
APP_ERROR_CHECK(err_code);//检查错误代码
}
int main(void)
{
ret_code_t err_code;
//初始化开发板上的4个LED,即将驱动LED的GPIO配置为输出,
bsp_board_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS);
//初始化APP定时器程序模块和创建APP定时器
timers_init();
//初始化低频时钟LFCLK
lfclk_config();
while (true)
{
if(nrf_gpio_pin_read(BUTTON_2) == 0)
{
//软件消抖
nrf_delay_ms(20);
//按键S2有效
if(nrf_gpio_pin_read(BUTTON_2) == 0)
{
//停止LED定时器
err_code = app_timer_stop(led_toggle_timer_id);
APP_ERROR_CHECK(err_code);
}
}
//检测按键S3是否按下
if(nrf_gpio_pin_read(BUTTON_3) == 0)
{
//软件消抖
nrf_delay_ms(20);
//如果按键S3有效
if(nrf_gpio_pin_read(BUTTON_3) == 0)
{
//开启LED定时器
err_code = app_timer_start(led_toggle_timer_id,LED_TOGGLE_INTERVAL,led_toggle_timeout_handler);
APP_ERROR_CHECK(err_code);
}
}
}
}
这是周期执行的代码,用两个按键控制LED定时任务的执行和停止。