SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.sydtek.com/

nrf51822学习之定时器的探究

主程序调用的定时器初始化函数:timers_init();

内容如下:

static void timers_init(void)
{
    // Initialize timer module, making it use the scheduler
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);

/* YOUR_JOB: Create any timers to be used by the application.
                 Below is an example of how to create a timer.
                 For every new timer needed, increase the value of the macro APP_TIMER_MAX_TIMERS by
                 one.
    err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
    APP_ERROR_CHECK(err_code); */
}

这个定时器初始化函数最终使用的是RTC时钟,作为整个程序的宏观脉搏,为调度器使用,当然用户也可以创建时钟。

static uint32_t APP_TIMER_BUF[CEIL_DIV(APP_TIMER_BUF_SIZE((MAX_TIMERS),                    \
                                                                  (OP_QUEUES_SIZE) + 1),           \
                                               sizeof(uint32_t))];                                 \

这是计算要分配的定时器内存区大小,说到底就是分配一个静态的数组,这个数组的类型是uint32_t,细看这个数组的项数,有下面这个函数:

#define CEIL_DIV(A, B)      \
    /*lint -save -e573 */   \
    ((((A) - 1) / (B)) + 1) \
    /*lint -restore */

可以看到,这个数组是以uint32_t就是4个字节为单位的,具体计算再看:

APP_TIMER_BUF_SIZE((MAX_TIMERS),                    \
                                                                  (OP_QUEUES_SIZE) + 1),

这里各个含义如下:

#define APP_TIMER_BUF_SIZE(MAX_TIMERS, OP_QUEUE_SIZE)                                              \
    (                                                                                              \
        ((MAX_TIMERS) * APP_TIMER_NODE_SIZE)                                                       \
        +                                                                                          \
        (                                                                                          \
            APP_TIMER_INT_LEVELS                                                                   \
            *                                                                                      \
            (APP_TIMER_USER_SIZE + ((OP_QUEUE_SIZE) + 1) * APP_TIMER_USER_OP_SIZE)                 \
        )                                                                                          \
    )

其中传入的变量:

#define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
#define APP_TIMER_MAX_TIMERS            2                                           /**< Maximum number of simultaneously created timers. */
#define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */

也就是说 MAX_TIMERS=2  OP_QUEUE_SIZE)=4,再看其他的变量:

#define APP_TIMER_NODE_SIZE          40                         /**< Size of app_timer.timer_node_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_OP_SIZE       24                         /**< Size of app_timer.timer_user_op_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_SIZE          8                          /**< Size of app_timer.timer_user_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_INT_LEVELS         3                          /**< Number of interrupt levels from where timer operations may be initiated (only for use inside                      APP_TIMER_BUF_SIZE()). */

从这里看APP_TIMER_BUF_SIZE函数的功能就是计算出time模块一共需要多少内存区域,然后经过CEIL_DIV函数对齐4字节的计算就知道了要分配多少个数组项给定时器模块

分配了内存区,然后下来的就是初始化rtc时钟了:

uint32_t ERR_CODE = app_timer_init((PRESCALER),                                            \
                                           (MAX_TIMERS),                                           \
                                           (OP_QUEUES_SIZE) + 1,                                   \
                                           APP_TIMER_BUF,                                          \
                                           (USE_SCHEDULER) ? app_timer_evt_schedule : NULL);       \

该函数的源代码如下:

uint32_t app_timer_init(uint32_t                      prescaler,//预分频器
                        uint8_t                       max_timers,//最大时间
                        uint8_t                       op_queues_size,
                        void *                        p_buffer,
                        app_timer_evt_schedule_func_t evt_schedule_func)
{
    int i;

// Check that buffer is correctly aligned检查缓冲区是否正确字对齐
    if (!is_word_aligned(p_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;//无效的参数
    }
    // 检查空缓冲区
    if (p_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    
    // Stop RTC to prevent any running timers from expiring (in case of reinitialization)RTC停止
    rtc1_stop();
    
    m_evt_schedule_func = evt_schedule_func;//按键调度事件

// Initialize timer node array初始化定时器节点数组
    m_node_array_size = max_timers;
    mp_nodes          = p_buffer;
    
    for (i = 0; i < max_timers; i++)
    {
        mp_nodes[i].state      = STATE_FREE;
        mp_nodes[i].is_running = false;
    }
    
    // Skip timer node array
    p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
    
    // Initialize users array
    m_user_array_size = APP_TIMER_INT_LEVELS;
    mp_users          = p_buffer;
    
    // Skip user array
    p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];

// Initialize operation queues
    for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
    {
        timer_user_t * p_user = &mp_users[i];
        
        p_user->first              = 0;
        p_user->last               = 0;
        p_user->user_op_queue_size = op_queues_size;
        p_user->p_user_op_queue    = p_buffer;
    
        // Skip operation queue
        p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
    }

m_timer_id_head             = TIMER_NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

NVIC_ClearPendingIRQ(SWI0_IRQn);
    NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
    NVIC_EnableIRQ(SWI0_IRQn);

rtc1_init(prescaler);

m_ticks_latest = rtc1_counter_get();
    
    return NRF_SUCCESS;
}

首先要做的就是检查内存区是否是4字节对齐和是否存在

// Check that buffer is correctly aligned检查缓冲区是否正确字对齐
    if (!is_word_aligned(p_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;//无效的参数
    }
    // 检查空缓冲区
    if (p_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

然后停止rtc

// Stop RTC to prevent any running timers from expiring (in case of reinitialization)RTC停止
    rtc1_stop();

源码如下:

static void rtc1_stop(void)
{
    NVIC_DisableIRQ(RTC1_IRQn);

NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;         //清除比较器
    NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;    //停止比较器使能

NRF_RTC1->TASKS_STOP = 1;    //停止RTC模块
    nrf_delay_us(MAX_RTC_TASKS_DELAY);
}

然后根据传入进来的参数给全局变量赋值:

m_evt_schedule_func = evt_schedule_func;//按键调度事件
    // Initialize timer node array初始化定时器节点数组
    m_node_array_size = max_timers;
    mp_nodes          = p_buffer;

主意这些全局变量,在后面才会使用,在本函数没有使用,只是赋值而已,下面给初始化定时器各个队列,比如设置定时器的使用标志和是否运行标志以及初始化操作队列

for (i = 0; i < max_timers; i++)
    {
        mp_nodes[i].state      = STATE_FREE;
        mp_nodes[i].is_running = false;
    }

// Skip timer node array
    p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
    
    // Initialize users array
    m_user_array_size = APP_TIMER_INT_LEVELS;
    mp_users          = p_buffer;
    
    // Skip user array
    p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];

// Initialize operation queues
    for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
    {
        timer_user_t * p_user = &mp_users[i];
        
        p_user->first              = 0;
        p_user->last               = 0;
        p_user->user_op_queue_size = op_queues_size;
        p_user->p_user_op_queue    = p_buffer;
    
        // Skip operation queue
        p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
    }

m_timer_id_head             = TIMER_NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

然后初始化一个软件中断,这个也是给后面的定时各个函数使用的使用的

NVIC_ClearPendingIRQ(SWI0_IRQn);
    NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
    NVIC_EnableIRQ(SWI0_IRQn);

然后是rtc时钟的初始化

rtc1_init(prescaler);

这里传入的参数是#define APP_TIMER_PRESCALER             0    下面细看这个函数

static void rtc1_init(uint32_t prescaler)
{
    NRF_RTC1->PRESCALER = prescaler;
    NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI);
}

主意这里只是设置rtc的分频和中断优先级,优先级不论,说说这个分频,也就是rtc的频率是32768   ,中断不可能以这个频率去跑,那只能够说明定时器模块的频率毕竟和RTC的比较器有关了,或许不同的定时器模块他的比较器的值是不一样的吧。

最后是获取一下计数值,以更新一个全局变量:

m_ticks_latest = rtc1_counter_get();

主意到这里并没有开始定时器

还有这里的定时器指的是RTC而不是51822的定时计数模块

到此初始化是分析完毕了

nrf51822学习之定时器的探究相关推荐

  1. JavaScript学习05 定时器

    JavaScript学习05 定时器 定时器1 用以指定在一段特定的时间后执行某段程序. setTimeout(): 格式:[定时器对象名=] setTimeout("<表达式> ...

  2. 嵌入式学习——使用定时器输出PWM波形,实现 LED呼吸灯的效果

    嵌入式学习--使用定时器输出PWM波形,实现 LED呼吸灯的效果 目录 嵌入式学习--使用定时器输出PWM波形,实现 LED呼吸灯的效果 1. 任务要求 2 PWM波介绍, 2.1 什么是PWM(Pu ...

  3. STM32CubeMX与HAL库学习--基本定时器定时中断

    STM32CubeMX与HAL库学习--基本定时器定时中断 背景 STM32CubeMX生成初始化代码 在MDK-ARM里编辑代码 其他 背景 本人小白,最近在学着使用STM32CubeMX与HAL库 ...

  4. buck电路 dac stm32_STM32定时器学习---基本定时器

    STM32F1系列的产品,除了互联网产品外,工作8个,3种定时器,其中一种就是基本定时器.那么STM32单片机的基本定时器如何操作以及编程呢? 下面我们就来详细的了解一下 STM32F1系列的产品,除 ...

  5. 【JAVA 学习笔记】HashMap 探究

    前言 文章仅是笔者个人的学习笔记,存在一些只有笔者个人能看到的用词或者描述,如果有不明确的地方,欢迎留言,理性讨论. 一.概述 HashMap是Map的一种,它的继承结构如下: public clas ...

  6. LPC2103学习之定时器0和定时器1

    2019独角兽企业重金招聘Python工程师标准>>> 这两天学习LPC2103的定时器.开始看前面的寄存器介绍看的有点头晕,一会儿就搞混了.不过当我看到后面用图片描述定时器相关寄存 ...

  7. STM32学习总结——定时器

    文章目录 一.STM32定时器是什么? 二.STM32定时器的功能 1.计时&&中断 2. PWM产生 3.输入捕获 三.总结 一.STM32定时器是什么? 定时器顾名思义就是可以用来 ...

  8. 嵌入式学习--使用定时器输出PWM波形,实现LED呼吸灯的效果

    目录 1.任务要求 2.PWM介绍 关于PWM的定义 分频-计数时钟 计数器 定时器输出PWM的原理 定时器的初始化 3.配置STM32CubeMX 4.keil5的代码 5.运行结果 6.心得与体会 ...

  9. STM32定时器学习---基本定时器

    STM32F1系列的产品,除了互联型产品外,工位8个定时器  TIM6.TIM7:基本定时器  TIM2/3/4/5:通用定时器  TIM1.TIM8:高级定时器 三种定时器的区别:  基本定时器:  ...

最新文章

  1. ios网络学习------8 xml格式数据的请求处理 用代码块封装
  2. 浅谈5G机房配套那些事
  3. 使用双重循环,输出数字金字塔
  4. python基础技巧总结(四)
  5. 计算机第二章基础知识习题,计算机基础知识习题.docx
  6. SDRAM学习笔记(二)
  7. listary——一个强大的windows高效工具
  8. 有道云笔记数学公式大全
  9. 怎样批量分析安能物流中含有提前签收的单号
  10. addr2line方法使用总结
  11. 日本作家将编程语言变成了动漫人物,你猜C语言是萝莉还是御姐?不得不说脑洞实在太大了!
  12. Luckily general gradient for spherical harmonics is defined
  13. 为什么我的单片机不是“跑车”而是“牛车”,过来人告诉你。
  14. Android监听电池电量
  15. 简要概述服装设计管理
  16. 计算机Excel批量改试卷,Excel批量修改标准化试卷(转)
  17. 用上赶机场带你行走天下,让你想去哪就去哪
  18. python数星星_最好的朋友:C++11 移动语义和 Pimpl 手法
  19. Python的网易云音乐数据分析系统 爬虫 echarts可视化 Flask框架 音乐推荐系统 源码下载
  20. java版微信公众号支付

热门文章

  1. Wijmo 更优美的jQuery UI部件集:活动日历控件(Event Calendar)
  2. 工作空间初始化路径错误 WARNING: Source space `/home/xxx/src` does not yet exist.
  3. 通信小常识(手机上网使用几G网络)[手机信号G、E、O、3G、H、H+的什么意思]
  4. 自动驾驶不等于无人驾驶,无人驾驶的概念是什么
  5. Ext Js ComboBox 下拉及获取下拉值
  6. 运筹优化学习15:求解线性规划的单纯形法【手把手计算,够你应付考试了,看不懂算我输】
  7. Python动画实现
  8. 无法使用evince命令打开pdf文档
  9. Portainer容量管理工具的基本使用
  10. 软件集成测试策略有哪些,面向对象的集成测试与传统的软件集成测试有什么不同?分别有哪些策略?...