• nrf52382之定时器使用


    简介

    定时器几乎是每个单片机必有的重要外设之一,可用于定时、精确延时、计数等等,在检测、控制领域有广泛应用。

    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)
    
    • 1

    分频系数可设置的范围是 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"
    
    • 1

    2.定义Timer0

    驱动程序实例的ID对应Timer的ID,如NRF_DRV_TIMER_INSTANCE(0)对应Timer0

    const nrfx_timer_t TIMER_LED = NRFX_TIMER_INSTANCE(0);
    
    • 1

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    实验效果

    每隔200切换一次LED等的亮灭。

    关于nrf52382计数器的使用(以timer0为例)

    //定义Timer0的驱动程序实例。驱动程序实例的ID对应Timer的ID,如NRF_DRV_TIMER_INSTANCE(0)对应Timer0

    头文件

    const nrfx_timer_t TIMER_COUNTER = NRFX_TIMER_INSTANCE(0);
    
    • 1

    //Timer事件回调函数

    void my_timer_event_handler(nrf_timer_event_t event_type, void* p_context){}
    
    • 1

    定时器计数器配置

    //定时器配置计数器初始化
    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    启动定时器计数器

    //启动定时器
    nrfx_timer_enable(&TIMER_COUNTER);
    
    • 1
    • 2
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    实验效果

    每次主动加1,获取的计数值则加1, 否则计数值不变。
    在这里插入图片描述

  • 相关阅读:
    Python __new__()方法详解
    【机器学习】随机种子Random Seed介绍(在Python、Pytorch、TensorFlow中的设置代码汇总)
    计算机毕业设计(附源码)python疫情管理系统
    数据结构:(c实现)手把手教你实现栈和队列(内附详细代码)
    练习实践:ubuntu18.04安装、配置Nginx+PHP环境,两种配置方式,多站点
    [鹏程杯2023]复现
    RabbitMQ快速入门
    ts的交叉类型是什么
    Revit二次开发-WPF ProgressBar 执行程序中显示进度条
    [面试直通版]数据库核心之索引,性能与安全(下)
  • 原文地址:https://blog.csdn.net/qq_32348883/article/details/126569801