Z-Stack中OSAL定时器事件触发流程分析

2023-11-22 22:48

本文主要是介绍Z-Stack中OSAL定时器事件触发流程分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面:之所以会注意到定时器事件是因为在做断点调试的时候会进入osal_start_timerEx这个函数,而且这个函数之后还会涉及到hal_uartpoll有关DMA之类的函数,于是发现了这篇文章,写得很详细。

     我们先看一下osal_start_timerEx()函数,是怎么调用到最后的osal_set_event()函数,触发事件处理的。下面是osal_start_timerEx()函数的源代码,从中间我们并没有看到有关osal_set_events()函数的相关信息。当然这个函数中没有直接的调用该函数,那osal_set_events()函数,是怎么和我们的osal_start_timerEx()函数联系起来的呢?我们应该先从系统中的主循环开始查找其中的奥妙。 
byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )
{
halIntState_t intState;
  osalTimerRec_t *newTimer;
 
  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
 
  // Add timer
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
  if ( newTimer )
  {
#ifdef POWER_SAVING
    // Update timer registers
    osal_retune_timers();
    (void)timerActive;
#endif
    // Does the timer need to be started?
    if ( timerActive == FALSE )
    {
      osal_timer_activate( TRUE );
    }
  }
   先在osal_start_system( void )函数开始时调用Hal_ProcessPoll();因为Hal_ProcessPoll()函数是在一个死循环中,所以每过一定的时间就会执行到。在Z-Stack OSAL中这个时种节奏定义是1ms,由8bits HW_TIMER4来控制,这些都可以有程序员进行修改,我们先看一下Hal_ProcessPoll()函数。
void Hal_ProcessPoll ()
{
 
 
  HalTimerTick();
 
 
#if (defined HAL_UART) && (HAL_UART == TRUE)
  HalUARTPoll();
#endif
 
}
   在这是就会有一个疑问是在什么时候溢出呢?我们知道每个系统都会有一个节拍,也就是系统的时钟,在OSAL中也不例外,这个时钟就是由Timer4提供的计时的。
在void InitBoard(byte level)函数中调用下面这个函数,进行了配置
HalTimerConfig (OSAL_TIMER,                     // 8bit timer2
                  HAL_TIMER_MODE_CTC,         // Clear Timer on Compare
                  HAL_TIMER_CHANNEL_SINGLE,    // Channel 1 - default
                  HAL_TIMER_CH_MODE_OUTPUT_COMPARE,   // Output Compare mode
                  OnboardTimerIntEnable,           // Use interrupt
                  Onboard_TimerCallBack);         // Channel Mode
 
      OSAL的Timer定义好之后,就要启动Timer,在网络层初始化函数nwk_init(taskID++)执行完后,Timer启动了,也就是说在网络层的初始化函数中启动了Timer,网络层的代码是不开源的,所以也就无法看到其真正的启动代码。
   每当1ms心跳来临时,Timer4的中断标志置位,这样在OSAL的死循环中,通过一开始的Hal_ProcessPoll()函数检测到这中断标志位,在Hal_ProcessPoll ()函数中调用了  HalTimerTick();函数,这个函数是专门用来检测是否有硬件定时器溢出的。如果定时器有溢出的话,就要调用halProcessTimerX ();(X表示 1 3 4).这里假设是HalProcessTimer4(),在HalProcessTimer4()中,通过下面的一句话,调用了函数
halTimerSendCallBack (HAL_TIMER_2, 
HAL_TIMER_CHANNEL_B,
HAL_TIMER_CH_MODE_OUTPUT_COMPARE);
在halTimerSendCallBack中调用了真正的回调函数,
if (halTimerRecord[hwtimerid].callBackFunc)
    (halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
这个回调函数通过
uint8 HalTimerConfig (uint8 timerId, uint8 opMode, uint8 channel, uint8 channelMode,bool intEnable, halTimerCBack_t cBack)
   也就是前面的那个函数。进行的配置。在InitBoard()函数中调用了函数HalTimerConfig()。
   也就是调用了Onboard_TimerCallBack()函数,在这个函数中调用了osal_update_timers();函数,这个函数又调用了osalTimerUpdate( tmr_decr_time );这个函数中又调用了osal_set_events()函数。
osalTimerUpdate( tmr_decr_time )函数会去轮询Timer事件链表,Timer事件链表是下面这样一个数据结构,next指向下一个Timer事件,timerout值表明本Timer事件还需要timerout个心跳才需要被处理,因为些处的心跳是1ms,所以也就是说还需要timerout个ms才处理。也就是检测timeout是否小于1ms,如果小于1ms,则发出event_flag这个消息到消息队列,这个消息隶属于task_id这个任务,如果不大于1ms,说明该Timer事件还不到处理的时间,则Timeout= Timeout-1,然后继续等待下一次心跳,Timer事件链表的维护是通过osal_start_timerEx()这个函数来实现的。这样就把前面的osalTimerUpdate( tmr_decr_time )函数和我们应用程序中经常调用的osal_start_timerEx()函数联系在了一起,
typedef struct
{
  void *next;
  UINT16 timeout;
  UINT16 event_flag;
  byte task_id;
} osalTimerRec_t;
   如果到达定时器的定时值,也就是说Timeout< 1ms后,就会发送一个event_flag这个消息给消息队列,这样在主循环中就可以检测到这个消息,并且检测到这个消息是属于那个任务的,然后,调用相应的消息处理函数。

这篇关于Z-Stack中OSAL定时器事件触发流程分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/413466

相关文章

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

将Java项目提交到云服务器的流程步骤

《将Java项目提交到云服务器的流程步骤》所谓将项目提交到云服务器即将你的项目打成一个jar包然后提交到云服务器即可,因此我们需要准备服务器环境为:Linux+JDK+MariDB(MySQL)+Gi... 目录1. 安装 jdk1.1 查看 jdk 版本1.2 下载 jdk2. 安装 mariadb(my

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序