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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:


 

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

 

一、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博客园博客,原文链接:http://www.cnblogs.com/zjutlitao/p/5752520.html,如需转载请自行联系原作者
相关文章
|
1月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
107 10
|
1月前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
36 1
|
2月前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
80 2
|
2月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
39 3
|
2月前
|
SQL 监控 关系型数据库
SQL错误代码1303解析与处理方法
在SQL编程和数据库管理中,遇到错误代码是常有的事,其中错误代码1303在不同数据库系统中可能代表不同的含义
|
2月前
|
SQL 安全 关系型数据库
SQL错误代码1303解析与解决方案:深入理解并应对权限问题
在数据库管理和开发过程中,遇到错误代码是常见的事情,每个错误代码都代表着一种特定的问题
|
3月前
|
SQL 人工智能 机器人
遇到的代码部份解析
/ 模拟后端返回的数据
19 0
|
23天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
61 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
72 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0

推荐镜像

更多