[nRF51822] 8、基础实验代码解析大全 · 实验11 - PPI

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

一、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\r\n", (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:[email protected] 
i-blog:blog.beautifulzzzz.com

时间: 2024-12-09 02:21:31

[nRF51822] 8、基础实验代码解析大全 · 实验11 - PPI的相关文章

[nRF51822] 10、基础实验代码解析大全 · 实验15 - RTC

一.实验内容: 配置NRF51822 的RTC0 的TICK 频率为8Hz,COMPARE0 匹配事件触发周期为3 秒,并使能了TICK 和COMPARE0 中断. TICK 中断中驱动指示灯D1 翻转状态, 即指示灯D1 以8Hz 的速率翻转状态 COMPARE0 中断中点亮指示灯D2 二.nRF51822的内部RTC结构: NRF51822 有两个RTC 时钟:RTC0,RTC1.两个RTC 均为24 位,使用LFCLK 低频时钟,并带有12 位分频器,可产生TICK.compare 和溢出

[nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM

一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指在一个周期内,信号处于高电平的时间占整个信号周期的百分比,方波的占空比是50%. 2) 调制频率:周期的倒数. 3) 脉冲宽度:信号处于高电平的时间. 二.nRF51822的PWM产生: NRF51822 通过Timer.PPI 和GPIOTE 的配合实现PWM 的功能,由Timer 产生一个事件,

[nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写

 一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识: EN-nRF51D 开发板使用NRF51822 芯片为nRF51822-QFAA,如下图所示,共有256KBFLASH,256 页,页大小为1024 字节. NRF51822 内部FLASH 写流程如下: 三.代码解析: main: 1 int main(void) 2 { 3 ... 4 5

[nRF51822] 7、基础实验代码解析大全(前十)

实验01 - GPIO输出控制LED 引脚输出配置:nrf_gpio_cfg_output(LED_1); 引脚输出置高:nrf_gpio_pin_set(LED_1); 引脚电平转换:nrf_gpio_pin_toggle(LED_1); 毫秒延时:nrf_delay_ms(100); 1 int main(void) 2 { 3 nrf_gpio_cfg_output(LED_1);//配置P0.21为输出 4 nrf_gpio_pin_set(LED_1); //指示灯D1初始状态为熄灭

MYSQL常见出错mysql_errno()代码解析

如题,今天遇到怎么一个问题, 在理论上代码是不会有问题的,但是还是报了如上的错误,把sql打印出來放到DB中却可以正常执行.真是郁闷,在百度里面 渡 了很久没有相关的解释,到时找到几个没有人回复的 "网站出现Query was empty 报错" 帖子,后来我查阅了 MYSQL常见出错代码解析大全mysql_errno()才知道是 1065:无效的SQL语句,SQL语句为空 导致的错误. 所以我们应该把重点放在sql语句上,最后发现是我的SQL语句的变量用了大写,而执行的时候该变量用了

JAVA将数字字符串强制转换成整型变量----求参数之和实验代码

实验代码: package demo; public class CommandParameter {  /**  * @param args  */  public static void main(String[] args) {   // TODO Auto-generated method stub    int sum=0;                                                                             //设数值

【原创】大数据基础之Spark(4)RDD原理及代码解析

一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-distributed-datasets-rdds官方描述如下:重点是可容错,可并行处理 Spark revolves around the concept of a resilient distributed dataset (RDD), which is a fault-tolerant colle

Android学习xml解析大全之SAX和DOM

  随着android的学习解析xml成为了很多朋友面临的问.想学习如何解析xml就要先了解xml是什么. XML称为可扩展标记语言(Extensible Markup Language),由标准通用标记语言(SGML:Standard Generalized Markup Language)发展而来,允许开发者自定义标签,可以实现标签和内容的有效分离. 与HTML不同,XML不再侧重于数据如何表现,而是更多的关注数据如何存储和传输.因此,XML逐渐演变成为一种跨平台的数据交换格式.通过使用XM

20172302 《Java软件结构与数据结构》实验二:树实验报告

课程:<Java软件结构与数据结构> 班级: 1723 姓名: 侯泽洋 学号:20172302 实验教师:王志强老师 实验日期:2018年11月5日 必修/选修: 必修 实验内容 (1)参考教材p212,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder:用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息 (2)基于Linked