zoukankan      html  css  js  c++  java
  • [nRF51822] 8、基础实验代码解析大全 · 实验11

    前一篇分析了前十个基础实验的代码,从这里开始分析后十个~

    一、PPI原理:

    PPI(Programmable Peripheral Interconnect),中文翻译为可编程外设互连。

    在nRF51822 内部设置了PPI 方式,可以通过任务和事件让不同外设之间进行互连,而不需要CPU 进行参与。

    PPI 通过通道让任务和事件连接在一起。PPI 通道由两个端点组成:

    • 任务端点:Task End-Point (TEP)。
    • 事件端点:Event End-Point (EEP)。

    所谓的互联就是将任务端点写入需要连接的任务寄存器地址,事件端点写入需要连接事件寄存器地址,之后,使能该PPI 通道,即实现了任务和事件的互联。

    可以通过如下两种方式使能和关闭PPI 通道:

    • 1) 通过独立设置CHEN,CHENSET 和CHENCLR 寄存器。
    • 2) 通过PPI 通道组的使能和关闭任务。使用这种方式,在触发任务之前,需要先配置好哪些PPI 通道属于哪个组。

    二、运行逻辑:

    实验中,用到了3 个定时器:Timer 0、Timer 1 和Timer 2。

    1) Timer 0 配置为计数器,在主循环中每100ms 被触发一次,并通过串口打印出计数值。
    2) Timer 1 每个偶数秒(2、4、6、8……)产生一次比较匹配事件,该事件通过PPI通道0 和Timer 0 的STOP Task 互联,互联后通过该事件触发Timer 0 的STOP Task。
    3) Timer 2 每个奇数秒(1、3、5、7……)产生一次比较匹配事件,该事件通过PPI通道1 和Timer 0 的START Task 互联,互联后通过该事件触发Timer 0 的START Task。

    实验原理框图如图1 所示:

    三、核心代码分析

    系统运行后,在循环中Timer 0 计数器的计数值每100ms 增加一次,在偶数秒时,Timer2 产生比较匹配事件,通过PPI 触发Timer 0 的STOP Task,Timer 0 停止计数。此时,尽管主循环中每隔100ms 触发一次Timer 0 计数,但是由于Timer 0 已经停止,所以,计数值不会增加。每个奇数秒,Timer2 产生比较匹配事件,通过PPI 触发Timer 0 的START Task,Timer 0 恢复计数。

    main函数部分:

     1 int main(void)
     2 {
     3     timer0_init(); // Timer used to blink the LEDs.
     4     timer1_init(); // Timer to generate events on even number of seconds.
     5     timer2_init(); // Timer to generate events on odd number of seconds.
     6     ppi_init();    // PPI to redirect the event to timer start/stop tasks.
     7 
           串口初始化(略)
    28 
    29     // Enabling constant latency as indicated by PAN 11 "HFCLK: Base current with HFCLK 
    30     // running is too high" found at Product Anomaly document found at
    31     // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
    32     //
    33     // @note This example does not go to low power mode therefore constant latency is not needed.
    34     //       However this setting will ensure correct behaviour when routing TIMER events through 
    35     //       PPI (shown in this example) and low power mode simultaneously.
    36     NRF_POWER->TASKS_CONSTLAT = 1;
    37     
    38     // Start clock.
    39     nrf_drv_timer_enable(&timer0);
    40     nrf_drv_timer_enable(&timer1);
    41     nrf_drv_timer_enable(&timer2);
    42 
    43     // Loop and increment the timer count value and capture value into LEDs. @note counter is only incremented between TASK_START and TASK_STOP.
    44     while (true)
    45     {
    46 
    47         printf("Current cout: %d
    ", (int)nrf_drv_timer_capture(&timer0,NRF_TIMER_CC_CHANNEL0));
    48 
    49         /* increment the counter */
    50         nrf_drv_timer_increment(&timer0);
    51 
    52         nrf_delay_ms(100);
    53     }
    54 }

    定时器初始化部分:

     1 // Timer even handler. Not used since timer is used only for PPI.
     2 void timer_event_handler(nrf_timer_event_t event_type, void * p_context){}
     3 
     4 /** @brief Function for Timer 0 initialization, which will be started and stopped by timer1 and timer2 using PPI.
     5 */
     6 static void timer0_init(void)
     7 {
     8     ret_code_t err_code = nrf_drv_timer_init(&timer0, NULL, timer_event_handler);
     9     APP_ERROR_CHECK(err_code);
    10 }
    11 
    12 /** @brief Function for Timer 1 initialization.
    13  *  @details Initializes Timer 1 peripheral, creates event and interrupt every 2 seconds,
    14  *           by configuring CC[0] to timer overflow value, we create events at even number of seconds
    15  *           for example, events are created at 2,4,6 ... seconds. This event can be used to stop Timer 0
    16  *           with Timer1->Event_Compare[0] triggering Timer 0 TASK_STOP through PPI.
    17 */
    18 static void timer1_init(void)
    19 {
    20     // Configure Timer 1 to overflow every 2 seconds. Check TIMER1 configuration for details
    21     // The overflow occurs every 0xFFFF/(SysClk/2^PRESCALER).
    22     // = 65535/31250 = 2.097 sec
    23     ret_code_t err_code = nrf_drv_timer_init(&timer1, NULL, timer_event_handler);
    24     APP_ERROR_CHECK(err_code);
    25 
    26     nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, 0xFFFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//比较模式,Timer 1 每个偶数秒(2、4、6、8……)产生一次比较匹配事件,该事件通过PPI通道0 和Timer 0 的STOP Task 互联,互联后通过该事件触发Timer 0 的STOP Task。
    27 }
    28 
    29 /** @brief Function for Timer 2 initialization.
    30  *  @details Initializes Timer 2 peripheral, creates event and interrupt every 2 seconds
    31  *           by configuring CC[0] to half of timer overflow value. Events are created at odd number of seconds.
    32  *           For example, events are created at 1,3,5,... seconds. This event can be used to start Timer 0
    33  *           with Timer2->Event_Compare[0] triggering Timer 0 TASK_START through PPI.
    34 */
    35 static void timer2_init(void)
    36 {
    37     // Generate interrupt/event when half of time before the timer overflows has past, that is at 1,3,5,7... seconds from start.
    38     // Check TIMER1 configuration for details
    39     // now the overflow occurs every 0xFFFF/(SysClk/2^PRESCALER)
    40     // = 65535/31250 = 2.097 sec */
    41     ret_code_t err_code = nrf_drv_timer_init(&timer2, NULL, timer_event_handler);
    42     APP_ERROR_CHECK(err_code);
    43 
    44     nrf_drv_timer_extended_compare(&timer2, NRF_TIMER_CC_CHANNEL0, 0x7FFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//Timer 2 每个奇数秒(1、3、5、7……)产生一次比较匹配事件,该事件通过PPI通道1 和Timer 0 的START Task 互联,互联后通过该事件触发Timer 0 的START Task。
    45 }

    PPI连接事件部分:

     1 /** @brief Function for initializing the PPI peripheral.
     2 */
     3 static void ppi_init(void)
     4 {
     5     uint32_t err_code = NRF_SUCCESS;
     6 
     7     err_code = nrf_drv_ppi_init();
     8     APP_ERROR_CHECK(err_code);
     9 
    10     // Configure 1st available PPI channel to stop TIMER0 counter on TIMER1 COMPARE[0] match, which is every even number of seconds.
    11     err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
    12     APP_ERROR_CHECK(err_code);
    13     err_code = nrf_drv_ppi_channel_assign(ppi_channel1,//PPI连接事件
    14                                           nrf_drv_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
    15                                           nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_STOP));
    16     APP_ERROR_CHECK(err_code);
    17 
    18     // Configure 2nd available PPI channel to start timer0 counter at TIMER2 COMPARE[0] match, which is every odd number of seconds.
    19     err_code = nrf_drv_ppi_channel_alloc(&ppi_channel2);
    20     APP_ERROR_CHECK(err_code);
    21     err_code = nrf_drv_ppi_channel_assign(ppi_channel2,
    22                                           nrf_drv_timer_event_address_get(&timer2, NRF_TIMER_EVENT_COMPARE0),
    23                                           nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_START));
    24     APP_ERROR_CHECK(err_code);
    25 
    26     // Enable both configured PPI channels
    27     err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
    28     APP_ERROR_CHECK(err_code);
    29     err_code = nrf_drv_ppi_channel_enable(ppi_channel2);
    30     APP_ERROR_CHECK(err_code);
    31 }

     

    @beautifulzzzz - 物联网&普适计算实践者
    e-mail:beautifulzzzz@qq.com 
    i-blog:blog.beautifulzzzz.com 

  • 相关阅读:
    L1-047 装睡 (10分)
    QT 文件的读写,将txt中的数据存储到QVector
    C++Primer第五版 第十二章 动态内存
    C++Primer第五版 第十一章 关联容器
    从《上瘾》到 《不被干扰》
    MySQL模糊查询用法(正则、通配符、内置函数等)
    MySQL-SQL优化总结
    MySQL中特别实用的几种SQL语句
    public、private、protected 和 default
    DO,DTO,VO,POJO详解
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/5752520.html
Copyright © 2011-2022 走看看