首页 > 编程语言 >UcOs-III 源码阅读: os_tick.c

UcOs-III 源码阅读: os_tick.c

时间:2024-10-31 10:45:23浏览次数:1  
标签:UcOs 0u III 滴答 源码 TCB TICK OS tcb

对os_tick.c进行源码注释与阅读

//作用:实现系统滴答定时器的功能,包括滴答列表的更新、滴答步长的动态调整等。用于管理自身主动延迟或在内核对象上被超时挂起的任务;


/*
*********************************************************************************************************
*                                              uC/OS-III
*                                        The Real-Time Kernel
*
*                    Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
*
*                                 SPDX-License-Identifier: APACHE-2.0
*
*               This software is subject to an open source license and is distributed by
*                Silicon Laboratories Inc. pursuant to the terms of the Apache License,
*                    Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                            TICK MANAGEMENT
*
* File    : os_tick.c
* Version : V3.08.02
*********************************************************************************************************
*/

#define  MICRIUM_SOURCE
#include "os.h"

#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
const  CPU_CHAR  *os_tick__c = "$Id: $";
#endif

#if (OS_CFG_TICK_EN > 0u)
/*
************************************************************************************************************************
*                                                 FUNCTION PROTOTYPES
************************************************************************************************************************
*/

static  void  OS_TickListUpdate (OS_TICK  ticks);


/*
************************************************************************************************************************
*                                                      TICK INIT
*
* Description: This function initializes the variables related to the tick handler.
*              The function is internal to uC/OS-III.
*
* Arguments  : p_err          is a pointer to a variable that will contain an error code returned by this function.
*              -----
*                                 OS_ERR_NONE           the tick variables were initialized successfully
*
* Returns    : none
*
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/

/**
 * @brief 初始化操作系统滴答定时器
 *
 * 该函数用于初始化操作系统滴答定时器的相关参数,包括滴答计数器、滴答步长、以及滴答列表等。
 *
 * @param p_err 指向错误代码的指针,用于返回函数执行后的错误状态。
 */
void  OS_TickInit (OS_ERR  *p_err)
{
    // 初始化错误代码为无错误
    *p_err                = OS_ERR_NONE;

    // 清除滴答计数器
    OSTickCtr             = 0u;                               /* Clear the tick counter                               */

    // 如果启用了动态滴答功能,则初始化滴答步长为0
    #if (OS_CFG_DYN_TICK_EN > 0u)
    OSTickCtrStep         = 0u;
    #endif

    // 初始化滴答列表的TCB指针为NULL
    OSTickList.TCB_Ptr    = (OS_TCB *)0;

    // 如果启用了调试功能,则初始化滴答列表的条目数和更新数为0
    #if (OS_CFG_DBG_EN > 0u)
    OSTickList.NbrEntries = 0u;
    OSTickList.NbrUpdated = 0u;
    #endif
}

/*
************************************************************************************************************************
*                                                      TICK UPDATE
*
* Description: This function updates the list of task either delayed pending with timeout.
*              The function is internal to uC/OS-III.
*
* Arguments  : ticks          the number of ticks which have elapsed
*              -----
*
* Returns    : none
*
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/

// 更新系统滴答计数和相关时间戳
void  OS_TickUpdate (OS_TICK  ticks)
{
#if (OS_CFG_TS_EN > 0u)
    CPU_TS  ts_start;
#endif
    //保存SR寄存器状态
    CPU_SR_ALLOC();

    //进入临界区
    CPU_CRITICAL_ENTER();

    // 累加滴答计数,用于跟踪系统时间
    OSTickCtr += ticks;

    // 跟踪滴答增量,用于调试和分析
    OS_TRACE_TICK_INCREMENT(OSTickCtr);

#if (OS_CFG_TS_EN > 0u)
    // 获取开始时间戳,用于计算滴答处理时间
    ts_start   = OS_TS_GET();
    // 更新滴答列表,管理周期性任务
    OS_TickListUpdate(ticks);
    // 计算并更新滴答时间
    OSTickTime = OS_TS_GET() - ts_start;
    // 更新最大滴答时间,用于监控系统性能
    if (OSTickTimeMax < OSTickTime) {
        OSTickTimeMax = OSTickTime;
    }
#else
    // 更新滴答列表,即使没有时间戳功能也需管理周期性任务
    OS_TickListUpdate(ticks);
#endif

#if (OS_CFG_DYN_TICK_EN > 0u)
    // 动态滴答功能:根据当前任务调整滴答间隔
    if (OSTickList.TCB_Ptr != (OS_TCB *)0) {
        OSTickCtrStep = OSTickList.TCB_Ptr->TickRemain;
    } else {
        OSTickCtrStep = 0u;
    }

    // 设置动态滴答间隔
    OS_DynTickSet(OSTickCtrStep);
#endif
    // 退出临界区
    CPU_CRITICAL_EXIT();
}

/*
************************************************************************************************************************
*                                                      INSERT
*
* Description: This task is internal to uC/OS-III and allows the insertion of a task in a tick list.
*
* Arguments  : p_tcb       is a pointer to the TCB to insert in the list
*
*              elapsed     is the number of elapsed ticks since the last tick interrupt
*
*              tick_base   is value of OSTickCtr from which time is offset
*
*              time        is the amount of time remaining (in ticks) for the task to become ready
*
* Returns    : OS_TRUE     if time is valid for the given tick base
*
*              OS_FALSE    if time is invalid (i.e. zero delay)
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
*
*              2) This function supports both Periodic Tick Mode (PTM) and Dynamic Tick Mode (DTM).
*
*              3) PTM should always call this function with elapsed == 0u.
************************************************************************************************************************
*/

/**
 * @brief 插入任务控制块到滴答列表中
 *
 * 本函数负责将任务控制块(TCB)根据指定的时间插入到滴答列表中,用于任务的延迟调度
 * 它计算任务到期所需的滴答数,并根据当前列表状态,将任务插入到正确的位置
 *
 * @param p_tcb 任务控制块指针,代表需要插入的任务
 * @param elapsed 任务自上次调度以来经过的滴答数
 * @param tick_base 任务开始延迟时的基准滴答数
 * @param time 任务延迟的总时间
 * @return CPU_BOOLEAN 插入结果,OS_TRUE表示成功插入,OS_FALSE表示立即到期(无需插入)
 */
CPU_BOOLEAN  OS_TickListInsert (OS_TCB   *p_tcb,
                                OS_TICK   elapsed,
                                OS_TICK   tick_base,
                                OS_TICK   time)
{
    OS_TCB        *p_tcb1;
    OS_TCB        *p_tcb2;
    OS_TICK_LIST  *p_list;
    OS_TICK        delta;
    OS_TICK        remain;

    // 计算任务到期还需多少滴答?
    delta = (time + tick_base) - (OSTickCtr + elapsed);

    // 如果任务立即到期,设置剩余滴答为0,并返回OS_FALSE
    if (delta == 0u) {
        p_tcb->TickRemain = 0u;
        return (OS_FALSE);
    }

    // 跟踪任务延迟
    OS_TRACE_TASK_DLY(delta);

    // 获取滴答列表指针
    p_list = &OSTickList;
    // 如果列表为空,将任务直接插入
    if (p_list->TCB_Ptr == (OS_TCB *)0) {
        p_tcb->TickRemain   = delta; // 存储到期时间到TCB
        p_tcb->TickNextPtr  = (OS_TCB *)0;
        p_tcb->TickPrevPtr  = (OS_TCB *)0;
        p_list->TCB_Ptr     = p_tcb; // 列表指向新插入的任务TCB
#if (OS_CFG_DYN_TICK_EN > 0u)
        // 如果elapsed不为0,更新OSTickCtr
        if (elapsed != 0u) {
            OSTickCtr      += elapsed;
            OS_TRACE_TICK_INCREMENT(OSTickCtr);
        }

        // 设置新的滴答步长并更新动态滴答
        OSTickCtrStep       = delta;
        OS_DynTickSet(OSTickCtrStep);
#endif
#if (OS_CFG_DBG_EN > 0u)
        // 调试时更新列表条目数
        p_list->NbrEntries  = 1u;
#endif
        return (OS_TRUE);
    }

#if (OS_CFG_DBG_EN > 0u)
    // 调试时增加列表条目计数
    p_list->NbrEntries++;
#endif

    // 从列表头开始遍历
    p_tcb2 = p_list->TCB_Ptr;
    remain = p_tcb2->TickRemain - elapsed; // 计算列表头任务剩余时间

    // 如果当前任务应插入为新的列表头
    if ((delta < remain) && (p_tcb2->TickPrevPtr == (OS_TCB *)0)) {
        p_tcb->TickRemain    = delta; // 设置当前任务的剩余时间为delta
        p_tcb2->TickRemain   = remain - delta; // 更新原列表头任务的剩余时间

        p_tcb->TickPrevPtr   = (OS_TCB *)0;
        p_tcb->TickNextPtr   = p_tcb2;
        p_tcb2->TickPrevPtr  = p_tcb;
        p_list->TCB_Ptr      = p_tcb;
#if (OS_CFG_DYN_TICK_EN > 0u)
        // 更新OSTickCtr并设置新的滴答步长
        if (elapsed != 0u) {
            OSTickCtr       += elapsed;
            OS_TRACE_TICK_INCREMENT(OSTickCtr);
        }
        OSTickCtrStep        = delta;
        OS_DynTickSet(OSTickCtrStep);
#endif
        return (OS_TRUE);
    }

    // 当前任务不在列表头插入,更新delta为相对于列表头的时间
    delta  -= remain;
    p_tcb1  = p_tcb2;
    p_tcb2  = p_tcb1->TickNextPtr;

    // 寻找合适的插入位置
    while ((p_tcb2 != (OS_TCB *)0) && (delta >= p_tcb2->TickRemain)) {
        delta  -= p_tcb2->TickRemain;
        p_tcb1  = p_tcb2;
        p_tcb2  = p_tcb2->TickNextPtr;
    }

    // 插入任务到列表中适当位置
    if (p_tcb2 != (OS_TCB *)0) {
        p_tcb1               = p_tcb2->TickPrevPtr;
        p_tcb->TickRemain    = delta;
        p_tcb->TickPrevPtr   = p_tcb1;
        p_tcb->TickNextPtr   = p_tcb2;
        p_tcb2->TickRemain  -= delta;
        p_tcb2->TickPrevPtr  = p_tcb;
        p_tcb1->TickNextPtr  = p_tcb;

    } else {
        // 如果任务插入到列表末尾
        p_tcb->TickRemain    = delta;
        p_tcb->TickPrevPtr   = p_tcb1;
        p_tcb->TickNextPtr   = (OS_TCB *)0;
        p_tcb1->TickNextPtr  = p_tcb;
    }

    return (OS_TRUE);
}

/*
************************************************************************************************************************
*                                            ADD DELAYED TASK TO TICK LIST
*
* Description: This function is called to place a task in a list of task waiting for time to expire
*
* Arguments  : p_tcb          is a pointer to the OS_TCB of the task to add to the tick list
*              -----
*
*              time           represents either the 'match' value of OSTickCtr or a relative time from the current
*                             system time as specified by the 'opt' argument..
*
*                             relative when 'opt' is set to OS_OPT_TIME_DLY
*                             relative when 'opt' is set to OS_OPT_TIME_TIMEOUT
*                             match    when 'opt' is set to OS_OPT_TIME_MATCH
*                             periodic when 'opt' is set to OS_OPT_TIME_PERIODIC
*
*              opt            is an option specifying how to calculate time.  The valid values are:
*              ---
*                                 OS_OPT_TIME_DLY
*                                 OS_OPT_TIME_TIMEOUT
*                                 OS_OPT_TIME_PERIODIC
*                                 OS_OPT_TIME_MATCH
*
*              p_err          is a pointer to a variable that will contain an error code returned by this function.
*              -----
*                                 OS_ERR_NONE           the call was successful and the time delay was scheduled.
*                                 OS_ERR_TIME_ZERO_DLY  if the effective delay is zero
*
* Returns    : None
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
*
*              2) This function is assumed to be called with interrupts disabled.
************************************************************************************************************************
*/

/**
 * @brief 插入任务到滴答列表中
 *
 * 本函数根据指定的时间和选项将任务控制块(p_tcb)插入到系统滴答列表中。
 * 它处理绝对时间、周期性和相对时间延迟的选项,并更新任务的相应状态。
 *
 * @param p_tcb 指向任务控制块的指针,表示要插入列表的任务
 * @param time 延迟的时间或周期时间
 * @param opt 时间选项,决定时间计算的方式
 * @param p_err 指向错误代码的指针,返回函数执行后的错误状态
 */
void  OS_TickListInsertDly (OS_TCB   *p_tcb,
                            OS_TICK   time,
                            OS_OPT    opt,
                            OS_ERR   *p_err)
{
    OS_TICK      elapsed;
    OS_TICK      tick_base;
    OS_TICK      base_offset;
    CPU_BOOLEAN  valid_dly;

    // 根据是否启用动态滴答配置,获取当前动态滴答数或初始化为0
    #if (OS_CFG_DYN_TICK_EN > 0u)
    elapsed  = OS_DynTickGet();
    #else
    elapsed  = 0u;
    #endif

    // 根据不同的时间选项处理任务的滴答基础值
    if (opt == OS_OPT_TIME_MATCH) {                             /* MATCH to absolute tick ctr value mode                */
        tick_base = 0u;                                         /* tick_base + time == time                             */

    } else if (opt == OS_OPT_TIME_PERIODIC) {                   /* PERIODIC mode.                                       */
        if (time == 0u) {
           *p_err = OS_ERR_TIME_ZERO_DLY;                       /* Infinite frequency is invalid.                       */
            return;
        }

        tick_base = p_tcb->TickCtrPrev;

        // 计算滴答基础值与当前系统时间的偏移量
        #if (OS_CFG_DYN_TICK_EN > 0u)
        base_offset = OSTickCtr + elapsed - tick_base;
        #else
        base_offset = OSTickCtr - tick_base;
        #endif

        // 如果任务错过了上一个周期,调整滴答基础值到下一个周期
        if (base_offset >= time) {
            tick_base += time * (base_offset / time);
            if ((base_offset % time) != 0u) {
                tick_base += time;
            }

            p_tcb->TickCtrPrev = tick_base;
        }

        p_tcb->TickCtrPrev += time;

    } else {                                                    /* RELATIVE time delay mode                             */
        // 根据当前系统时间计算滴答基础值
        #if (OS_CFG_DYN_TICK_EN > 0u)
        tick_base = OSTickCtr + elapsed;
        #else
        tick_base = OSTickCtr;
        #endif
    }

    // 将任务插入到滴答列表中,并检查插入是否有效
    valid_dly = OS_TickListInsert(p_tcb, elapsed, tick_base, time);

    // 根据插入结果更新任务状态和错误代码
    if (valid_dly == OS_TRUE) {
        p_tcb->TaskState = OS_TASK_STATE_DLY;
       *p_err            = OS_ERR_NONE;
    } else {
       *p_err = OS_ERR_TIME_ZERO_DLY;
    }
}

/*
************************************************************************************************************************
*                                         REMOVE A TASK FROM THE TICK LIST
*
* Description: This function is called to remove a task from the tick list
*
* Arguments  : p_tcb          Is a pointer to the OS_TCB to remove.
*              -----
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
*
*              2) This function is assumed to be called with interrupts disabled.
************************************************************************************************************************
*/

/**
 * 函数名称: OS_TickListRemove
 * 功能描述: 从系统滴答列表中移除指定的任务控制块 (TCB)
 * 参数:
 * - p_tcb: 指向要移除的 TCB 的指针
 */
void  OS_TickListRemove (OS_TCB  *p_tcb)
{
    OS_TCB        *p_tcb1;
    OS_TCB        *p_tcb2;
    OS_TICK_LIST  *p_list;
#if (OS_CFG_DYN_TICK_EN > 0u)
    OS_TICK        elapsed;
#endif

#if (OS_CFG_DYN_TICK_EN > 0u)
    // 获取动态滴答计数
    elapsed = OS_DynTickGet();
#endif

    // 获取当前 TCB 的前一个和后一个 TCB 指针
    p_tcb1 = p_tcb->TickPrevPtr;
    p_tcb2 = p_tcb->TickNextPtr;
    p_list = &OSTickList;

    // 检查当前 TCB 是否是列表中的唯一条目
    if (p_tcb1 == (OS_TCB *)0) {
        if (p_tcb2 == (OS_TCB *)0) {  // 列表中只有一个条目
            p_list->TCB_Ptr = (OS_TCB *)0;
#if (OS_CFG_DBG_EN > 0u)
            p_list->NbrEntries = 0u;
#endif
            p_tcb->TickRemain = 0u;
#if (OS_CFG_DYN_TICK_EN > 0u)
            // 更新滴答计数器
            if (elapsed != 0u) {
                OSTickCtr += elapsed;
                OS_TRACE_TICK_INCREMENT(OSTickCtr);
            }
            OSTickCtrStep = 0u;
            OS_DynTickSet(OSTickCtrStep);
#endif
        } else {  // 列表中有多个条目,当前 TCB 是第一个
            p_tcb2->TickPrevPtr = (OS_TCB *)0;
            p_tcb2->TickRemain += p_tcb->TickRemain;  // 将当前 TCB 的剩余滴答数加到下一个 TCB
            p_list->TCB_Ptr = p_tcb2;
#if (OS_CFG_DBG_EN > 0u)
            p_list->NbrEntries--;
#endif

#if (OS_CFG_DYN_TICK_EN > 0u)
            // 更新滴答计数器
            if (p_tcb2->TickRemain != p_tcb->TickRemain) {
                if (elapsed != 0u) {
                    OSTickCtr += elapsed;
                    OS_TRACE_TICK_INCREMENT(OSTickCtr);
                    p_tcb2->TickRemain -= elapsed;
                }
                OSTickCtrStep = p_tcb2->TickRemain;
                OS_DynTickSet(OSTickCtrStep);
            }
#endif
            p_tcb->TickNextPtr = (OS_TCB *)0;
            p_tcb->TickRemain = 0u;
        }
    } else {  // 当前 TCB 不是第一个
        p_tcb1->TickNextPtr = p_tcb2;
        if (p_tcb2 != (OS_TCB *)0) {
            p_tcb2->TickPrevPtr = p_tcb1;
            p_tcb2->TickRemain += p_tcb->TickRemain;  // 将当前 TCB 的剩余滴答数加到下一个 TCB
        }
        p_tcb->TickPrevPtr = (OS_TCB *)0;
#if (OS_CFG_DBG_EN > 0u)
        p_list->NbrEntries--;
#endif
        p_tcb->TickNextPtr = (OS_TCB *)0;
        p_tcb->TickRemain = 0u;
    }
}

/*
************************************************************************************************************************
*                                 UPDATE THE LIST OF TASKS DELAYED OR PENDING WITH TIMEOUT
*
* Description: This function updates the delta list which contains tasks that are delayed or pending with a timeout.
*
* Arguments  : ticks          the number of ticks which have elapsed.
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

/**
 * 更新系统滴答列表,减少列表中每个任务的剩余滴答数。
 *
 * @param ticks 需要减少的滴答数
 */
static void OS_TickListUpdate(OS_TICK ticks)
{
    OS_TCB *p_tcb;
    OS_TICK_LIST *p_list;
#if (OS_CFG_DBG_EN > 0u)
    OS_OBJ_QTY nbr_updated;
#endif
#if (OS_CFG_MUTEX_EN > 0u)
    OS_TCB *p_tcb_owner;
    OS_PRIO prio_new;
#endif

#if (OS_CFG_DBG_EN > 0u)
    nbr_updated = 0u;  // 初始化更新的任务数量计数器
#endif

    p_list = &OSTickList;  // 获取滴答列表指针
    p_tcb = p_list->TCB_Ptr;  // 获取当前任务控制块指针

    if (p_tcb != (OS_TCB *)0) {
        if (p_tcb->TickRemain <= ticks) {
            ticks = ticks - p_tcb->TickRemain;
            p_tcb->TickRemain = 0u;
        } else {
            p_tcb->TickRemain -= ticks;
        }

        while (p_tcb->TickRemain == 0u) {
#if (OS_CFG_DBG_EN > 0u)
            nbr_updated++;  // 增加更新的任务数量计数器
#endif

            switch (p_tcb->TaskState) {
                case OS_TASK_STATE_DLY:
                    p_tcb->TaskState = OS_TASK_STATE_RDY;
                    OS_RdyListInsert(p_tcb);  // 将任务插入就绪列表
                    break;

                case OS_TASK_STATE_DLY_SUSPENDED:
                    p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
                    break;

                default:
#if (OS_CFG_MUTEX_EN > 0u)
                    p_tcb_owner = (OS_TCB *)0;
                    if (p_tcb->PendOn == OS_TASK_PEND_ON_MUTEX) {
                        p_tcb_owner = (OS_TCB *)((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr;
                    }
#endif

#if (OS_MSG_EN > 0u)
                    p_tcb->MsgPtr = (void *)0;
                    p_tcb->MsgSize = 0u;
#endif
#if (OS_CFG_TS_EN > 0u)
                    p_tcb->TS = OS_TS_GET();
#endif
                    OS_PendListRemove(p_tcb);  // 从挂起列表中移除任务

                    switch (p_tcb->TaskState) {
                        case OS_TASK_STATE_PEND_TIMEOUT:
                            OS_RdyListInsert(p_tcb);  // 将任务插入就绪列表
                            p_tcb->TaskState = OS_TASK_STATE_RDY;
                            break;

                        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                            p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
                            break;

                        default:
                            break;
                    }
                    p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT;  // 标记挂起超时
                    p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;  // 标记不再挂起

#if (OS_CFG_MUTEX_EN > 0u)
                    if (p_tcb_owner != (OS_TCB *)0) {
                        if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) &&
                            (p_tcb_owner->Prio == p_tcb->Prio)) {  // 检查所有者是否继承了优先级
                            prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner);
                            prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new;
                            if (prio_new != p_tcb_owner->Prio) {
                                OS_TaskChangePrio(p_tcb_owner, prio_new);
                                OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio);
                            }
                        }
                    }
#endif
                    break;
            }

            p_list->TCB_Ptr = p_tcb->TickNextPtr;  // 获取下一个任务控制块指针
            p_tcb = p_list->TCB_Ptr;  // 重新获取 p_tcb 以继续循环
            if (p_tcb == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN > 0u)
                p_list->NbrEntries = 0u;  // 更新列表中的任务数量
#endif
                break;
            } else {
#if (OS_CFG_DBG_EN > 0u)
                p_list->NbrEntries--;  // 减少列表中的任务数量
#endif
                p_tcb->TickPrevPtr = (OS_TCB *)0;
                if (p_tcb->TickRemain <= ticks) {
                    ticks = ticks - p_tcb->TickRemain;
                    p_tcb->TickRemain = 0u;
                } else {
                    p_tcb->TickRemain -= ticks;
                }
            }
        }
    }
#if (OS_CFG_DBG_EN > 0u)
    p_list->NbrUpdated = nbr_updated;  // 更新已处理的任务数量
#endif
}

#endif                                                                   /* #if OS_CFG_TICK_EN                                   */

标签:UcOs,0u,III,滴答,源码,TCB,TICK,OS,tcb
From: https://www.cnblogs.com/lanlincmos/p/18517216

相关文章