Nordic52810入門篇-定時器模塊

一、前言背景

爲了精確控制led週期閃爍,通過引入定時器中斷來處理。看了數據手冊和例程,發現Nordic有提供了兩種截然不同的定時器應用方案

二、定時器歸類

TIMER: 定時器外設,可以理解爲硬件定時器(類似STM32的通用定時器),運行在高頻時鐘源上(HFCLK),兩種工作模式,定時與計數(捕捉與比較);Nordic52810總共有三路定時器外設,TIMER0 TIMER1 TIMER1

  • 優點: 功能豐富,可配置高中斷優先級,精確高
  • 缺點: 功耗較高

app_timer:定時模塊,可以理解爲軟件定時器(軟件模擬的定時器),基於低頻時鐘(32kHZ)RTC1,配合協議棧使用,當定時時間溢出時(timeout),會通過藍牙協議棧回調預先配置好的函數接口

  • 優點:功耗極低(uA),可配置多個定時器中斷(理論上RAM充裕的話,可以一直往隊列裏面插入)
  • 缺點:精度較低,最小計時精度爲1ms,由於是軟定時器,會被其他高優先級任務搶佔,多多少少會被影響計時精度

三、接口講解

考慮到功耗至上的原則,選擇app_timer中斷來控制LED燈光閃爍(這個精度也不需要太高)

協議棧運行前需要初始化app_timer模塊

ret_code_t app_timer_init(void)
{
    // Stop RTC to prevent any running timers from expiring (in case of reinitialization)
    rtc1_stop();//先停止rtc1

    // Initialize operation queue
    m_op_queue.first           = 0;
    m_op_queue.last            = 0;
    m_op_queue.size            = APP_TIMER_CONFIG_OP_QUEUE_SIZE+1;//最大支持的隊列大小,可根據實際應用需要調整宏

    mp_timer_id_head            = NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

#if APP_TIMER_WITH_PROFILER
    m_max_user_op_queue_utilization   = 0;
#endif

    NVIC_ClearPendingIRQ(SWI_IRQn);//通過swi異常中斷後來觸發定時回調
    NVIC_SetPriority(SWI_IRQn, SWI_IRQ_PRI);
    NVIC_EnableIRQ(SWI_IRQn);

    rtc1_init(APP_TIMER_CONFIG_RTC_FREQUENCY);

    m_ticks_latest = rtc1_counter_get();

    return NRF_SUCCESS;
}

初始化軟定時器模塊後,需要進行定時器的創建,通過接口app_timer_create

ret_code_t app_timer_create(app_timer_id_t const *      p_timer_id,
                            app_timer_mode_t            mode,
                            app_timer_timeout_handler_t timeout_handler)
{
    // Check state and parameters
    VERIFY_MODULE_INITIALIZED();

    if (timeout_handler == NULL)//定時中斷回調的函數,爲空返回無效參數
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    if (p_timer_id == NULL)//句柄,爲空返回無效參數
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    if (((timer_node_t*)*p_timer_id)->is_running)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    timer_node_t * p_node     = (timer_node_t *)*p_timer_id;//保存到隊列中
    p_node->is_running        = false;
    p_node->mode              = mode;
    p_node->p_timeout_handler = timeout_handler;
    return NRF_SUCCESS;
}

軟定時器創建完成後,可通過模塊啓動接口app_timer_start使能定時,也可以通過app_timer_stop停止定時

四、代碼實例

通過配置1秒重複觸發回調進行led燈的翻轉閃爍

APP_TIMER_DEF(led_timer_id);   //定義句柄

//定時器觸發回調
static void led_callback(void * p_context)
{
    bsp_LedToggle(BSP_LED0);//翻轉led
}

int main(void)
{
    app_timer_init();//初始化app_timer模塊
    // Initialize.
    ble_stack_init();//初始化協議棧
    
    bsp_InitLED();//初始化led

    app_timer_create(&led_timer_id,APP_TIMER_MODE_REPEATED,led_callback);//註冊句柄,重複觸發,回調函數
    app_timer_start(led_timer_id,APP_TIMER_TICKS(1000), NULL); //1秒觸發一次

    while(1);

}

五、備註

  • 未初始化app_timer的情況下進行創建定時器將會導致非法訪問空指針,導致系統異常復位
  • 未創建定時器任務,調用開啓、停止接口也會導致訪問空指針,導致系統異常復位
  • 重複調用開啓、停止接口,將會出現產生不可預知的結果
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章