栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【Ucos-III源码分析】——软件定时器

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Ucos-III源码分析】——软件定时器

目录

一、软件定时器创建的时候都做了些什么

二、软件定时器在调用启用定时器的时候做了啥

1、OS_TmrUnlink(p_tmr);  

2、OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); 


一、软件定时器创建的时候都做了些什么
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              
        *p_err = OS_ERR_TMR_ISR;
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (p_tmr == (OS_TMR *)0) {                             
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }

    switch (opt) {
        case OS_OPT_TMR_PERIODIC:
             if (period == (OS_TICK)0) {
                 *p_err = OS_ERR_TMR_INVALID_PERIOD;
                 return;
             }
             break;

        case OS_OPT_TMR_ONE_SHOT:
             if (dly == (OS_TICK)0) {
                 *p_err = OS_ERR_TMR_INVALID_DLY;
                 return;
             }
             break;

        default:
             *p_err = OS_ERR_OPT_INVALID;
             return;
    }

第一步还是照旧,根据你传递进来的参数和设置的宏,来判断你的参数是否合理,如果不合理直接返回。

CPU_CRITICAL_ENTER();
    p_tmr->State          = (OS_STATE           )OS_TMR_STATE_STOPPED;     
    p_tmr->Type           = (OS_OBJ_TYPE        )OS_OBJ_TYPE_TMR;
    p_tmr->NamePtr        = (CPU_CHAR          *)p_name;
    p_tmr->Dly            = (OS_TICK            )dly;
    p_tmr->Match          = (OS_TICK            )0;
    p_tmr->Remain         = (OS_TICK            )0;
    p_tmr->Period         = (OS_TICK            )period;
    p_tmr->Opt            = (OS_OPT             )opt;
    p_tmr->CallbackPtr    = (OS_TMR_CALLBACK_PTR)p_callback;
    p_tmr->CallbackPtrArg = (void              *)p_callback_arg;
    p_tmr->NextPtr        = (OS_TMR            *)0;
    p_tmr->PrevPtr        = (OS_TMR            *)0;

#if OS_CFG_DBG_EN > 0u
    OS_TmrDbgListAdd(p_tmr);
#endif
    OSTmrQty++;                                             

    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_NONE;

第二步,禁用中断的前提下去给你创建的这个软件定时器来赋值,然后给一个变量去自增,在开启中断。这样基本就完成了一个软件定时器。这里创建好的一个软件定时器是一个停止状态。需要调用start去启用定时器才行。


二、软件定时器在调用启用定时器的时候做了啥
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (DEF_FALSE);
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              
        *p_err = OS_ERR_TMR_ISR;
        return (DEF_FALSE);
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (p_tmr == (OS_TMR *)0) {
        *p_err = OS_ERR_TMR_INVALID;
        return (DEF_FALSE);
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u
    if (p_tmr->Type != OS_OBJ_TYPE_TMR) {                   
        *p_err = OS_ERR_OBJ_TYPE;
        return (DEF_FALSE);
    }
#endif

第一步永久不变,永远是参数检查。不合理直接返回

 OSSchedLock(&err);
    switch (p_tmr->State) {
        case OS_TMR_STATE_RUNNING:                          
             OS_TmrUnlink(p_tmr);                           
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);            
             OSSchedUnlock(&err);
             *p_err = OS_ERR_NONE;
             return (DEF_TRUE);

        case OS_TMR_STATE_STOPPED:                          
        case OS_TMR_STATE_COMPLETED:
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);            
             OSSchedUnlock(&err);
             *p_err = OS_ERR_NONE;
             return (DEF_TRUE);

        case OS_TMR_STATE_UNUSED:                           
             OSSchedUnlock(&err);
             *p_err = OS_ERR_TMR_INACTIVE;
             return (DEF_FALSE);

        default:
             OSSchedUnlock(&err);
             *p_err = OS_ERR_TMR_INVALID_STATE;
             return (DEF_FALSE);
    }

这里就是软件定时器在启用的时候进行的判断分为(没有错误)

  1. 定时器正在运行当中调用start:那么此时会将定时器从这个timlist中移除之后再重新加入进来,相当于给定时器进行了一次重启
  2. 定时器处于停止状态调用start:那么这时候就会直接将这个软件定时器加入到一个timlist当中去。

这里很关键的就是这两个函数

  1.  OS_TmrUnlink(p_tmr);   
  2. OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); 

1、OS_TmrUnlink(p_tmr);  
void  OS_TmrUnlink (OS_TMR *p_tmr)
{
    OS_TMR_SPOKE    *p_spoke;
    OS_TMR          *p_tmr1;
    OS_TMR          *p_tmr2;
    OS_TMR_SPOKE_IX  spoke;



    spoke   = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
    p_spoke = &OSCfg_TmrWheel[spoke];

    if (p_spoke->FirstPtr == p_tmr) {                       
        p_tmr1            = (OS_TMR *)p_tmr->NextPtr;
        p_spoke->FirstPtr = (OS_TMR *)p_tmr1;
        if (p_tmr1 != (OS_TMR *)0) {
            p_tmr1->PrevPtr = (OS_TMR *)0;
        }
    } else {
        p_tmr1          = (OS_TMR *)p_tmr->PrevPtr;         
        p_tmr2          = (OS_TMR *)p_tmr->NextPtr;
        p_tmr1->NextPtr = p_tmr2;
        if (p_tmr2 != (OS_TMR *)0) {
            p_tmr2->PrevPtr = (OS_TMR *)p_tmr1;
        }
    }
    p_tmr->State   = OS_TMR_STATE_STOPPED;
    p_tmr->NextPtr = (OS_TMR *)0;
    p_tmr->PrevPtr = (OS_TMR *)0;
    p_spoke->NbrEntries--;
}

这里简单概述一下这里的结构

 这里的话就是我们所有的软件定时器都会被一个哈希链表管理,利用定时的时间长短来算出一个哈希值作为数组下标,但是其实这个数组元素也是一个双向链表,然后找到这个软件定时器在双向链表中存储的地方,然后再把它从双向链表中移除出来,最后把软件定时器设置成停滞状态。

2、OS_TmrLink(p_tmr, OS_OPT_LINK_DLY); 
OS_TMR_SPOKE     *p_spoke;
    OS_TMR           *p_tmr0;
    OS_TMR           *p_tmr1;
    OS_TMR_SPOKE_IX   spoke;



    p_tmr->State = OS_TMR_STATE_RUNNING;
    if (opt == OS_OPT_LINK_PERIODIC) {                      
        p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
    } else {
        if (p_tmr->Dly == (OS_TICK)0) {
            p_tmr->Match = p_tmr->Period + OSTmrTickCtr;
        } else {
            p_tmr->Match = p_tmr->Dly    + OSTmrTickCtr;
        }
    }
    spoke  = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize);
    p_spoke = &OSCfg_TmrWheel[spoke];

    if (p_spoke->FirstPtr ==  (OS_TMR *)0) {                
        p_tmr->NextPtr      = (OS_TMR *)0;
        p_tmr->PrevPtr      = (OS_TMR *)0;
        p_spoke->FirstPtr   = p_tmr;
        p_spoke->NbrEntries = 1u;
    } else {
        p_tmr->Remain  = p_tmr->Match                       
                       - OSTmrTickCtr;
        p_tmr1         = p_spoke->FirstPtr;                 
        while (p_tmr1 != (OS_TMR *)0) {
            p_tmr1->Remain = p_tmr1->Match                  
                           - OSTmrTickCtr;
            if (p_tmr->Remain > p_tmr1->Remain) {           
                if (p_tmr1->NextPtr  != (OS_TMR *)0) {      
                    p_tmr1            = p_tmr1->NextPtr;    
                } else {
                    p_tmr->NextPtr    = (OS_TMR *)0;
                    p_tmr->PrevPtr    =  p_tmr1;
                    p_tmr1->NextPtr   =  p_tmr;             
                    p_tmr1            = (OS_TMR *)0;        
                }
            } else {                                        
                if (p_tmr1->PrevPtr == (OS_TMR *)0) {       
                    p_tmr->PrevPtr    = (OS_TMR *)0;
                    p_tmr->NextPtr    = p_tmr1;
                    p_tmr1->PrevPtr   = p_tmr;
                    p_spoke->FirstPtr = p_tmr;
                } else {                                    
                    p_tmr0            = p_tmr1->PrevPtr;
                    p_tmr->PrevPtr    = p_tmr0;
                    p_tmr->NextPtr    = p_tmr1;
                    p_tmr0->NextPtr   = p_tmr;
                    p_tmr1->PrevPtr   = p_tmr;
                }
                p_tmr1 = (OS_TMR *)0;                       
            }
        }
        p_spoke->NbrEntries++;
    }
    if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) {     
        p_spoke->NbrEntriesMax = p_spoke->NbrEntries;
    }

简单来说你创建的软件定时器,如果需要开始使用那么就会调用这个函数,这个函数主体功能就是把你创建的软件定时器,去找一个合适的地方去插入一个双向链表中,有很多个双向链表都被一个数组存着,你需要利用哈希算法来算出一个数组下标,那么这个双向就是你需要插入的双向链表,具体你要插入到双向链表的头还是尾还是中间,这就要看你的定时时间的长短来算,不断地比较你和某一个节点的定时时间长短,然后找到一个最合适的地方去插入,最后再把你定时器的状态设置程p_tmr->State   = OS_TMR_STATE_STOPPED;。这最后还一步会存一个最大的存储值。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1002028.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号