当前位置: 首页 > news >正文

UCOS-II 自学笔记

摘抄于大学期间记录在QQ空间的一篇自学笔记,当前清理空间,本来想直接删除掉的,但是感觉有些舍不得,因此先搬移过来。

一、UC/OS_II体系结构
 

二、UC/OS_II中的任务

1、任务的基本概念

       在UCOS-II中,通常把一个大型任务分解成多个小任务,小任务对应的程序实体就叫做“任务”(实际上是一个线程),UCOS-II就是一个能对这些小任务的运行进行管理和调度的多任务操作系统。

       从任务的存储结构来看,UCOS-II由三个组成部分:任务程序代码(任务的执行部分)、任务堆栈(用来保存任务工作环境)、任务控制块(用来保存任务属性)。

       

       UCOS-II的任务分为用户任务(由应用程序设计者为了解决应用问题而编写)和系统任务(由系统提供为应用程序来提供某种服务)。为了管理上的方便,UCOS把每一个任务都作为一个节点,然后把它们连接成一个任务链表。目前UCOS-II最多可以对64个任务进行管理。

2、任务的状态

       嵌入式系统中只有一个CPU,因此一个具体时刻只能允许一个任务占用CPU,根据任务是否占用CPU,任务在UCOS-II中可能处于下列五种状态之一,且可以在不同状态之间的转换。

3、用户任务代码结构

备注:main函数中首先初始化ucos-ii,在创建3个任务,每一个任务为一个函数,其格式如上:可以被中断的用户代码、关闭中断、不可中断的代码、开启中断、可以被中断的代码。

4、两个系统任务

       Ucos-ii预定义了两个为应用程序服务的系统任务:空闲任务和统计任务,其中空闲任务是每个应用程序必须使用,而统计任务是应用程序可以根据实际需要来选择使用。

1)空闲任务

系统经常会在某个时间内无用户任务可运行而处于空闲状态,为了使cpu没有用户任务执行时有事可做,特提供了一个空闲任务OSTaskIdle()的系统任务:

系统任务只有一行代码pdata=pdata;因此什么都没有做,但是软件不可栓出这个任务。

2)统计任务

Ucos-ii提供了统计任务OSTaskStart(),此任务每秒计算一次cpu在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUUsage中,以便应用程序通过访问它来了解cpu的利用率。

如果用户程序要使用这个统计任务,者必须把定义在系统头文件OS_CFG .H中的系统配置常数OS_TASK_STAT_EN设置为1,并且必须在创建统计任务之前调用函数OSStatInit()对统计任务进行初始化。

5、任务的优先级

              Ucos-ii的每个任务都必须具有一个唯一的优先级别,把任务的优先权分为64个优先级别,每一个优先级别用一个数字来表示,数字0表示任务的优先级别最高,数字越大表示任务的优先级越低。

              用户程序可以在文件OS_CFG .H中通过给表示最低优先级别的常数OS_LOWEST_PRIO赋值的方法来说明应用程序优先级的数目,该常数一旦被定义,意味着系统可以供使用的优先级为0、1、2直到OS_LOWEST_PRIO,共OS_LOWEST_PRIO+1个任务,同时系统把最低优先级OS_LOWEST_PRIO自动赋值给空闲任务,如果应用程序还使用了统计任务,者系统会把OS_LOWEST_PRIO-1自动赋值给统计任务,因此用户任务可以使用的优先级别为0、1、2到OS_LOWEST_PRIO-2。

6、任务堆栈

       为了满足任务切换和响应中断时保存cpu寄存器中的内容及存储任务私用数据的需要每个任务都应该配有自己的堆栈。

1)任务堆栈的定义

为了定义任务堆栈,在文件OS_CPU .H中专门定义了一个数据类型OS_STK:

Typedef   unsigned  int   OS_STK;

这样在应用程序中定义任务堆栈的栈区即定义一个OS_STK类型的数组即可如下:

#define    TASK_STK_SIZE  512         //定义堆栈的长度(1024字节)
#OS_STK       TaskStk[TASK_STK_SIZE];        //定义数组作为任务堆栈

调用OSTaskCreate()来创建一个任务,把数组指针作为此函数参数,完成任务和任务堆栈的关联,如下:

#define    MyTaskStkN   64
OS_STK  MyTaskStk[MyTaskStkN];           
Void  main(void) {//……………OSTaskCreate(yTask, //指向任务的指针void (       * task) (void   * pd)&MyTaskAgu,//传递任务的参数void        *pdata,   &MyTaskStk[MyTaskStkN-1],//任务堆栈栈顶OS_STK *ptos,20       //指定任务优先级INT8U prio);//…………….
}

              注意:堆栈增长方向随系统使用处理器不同而不同,有的处理器是增长方向向上,有的处理器增长方向向下,如图:

              增长方向向下:

OSTaskCreate(MyTask,&MyTaskAgu,&MyTaskStk[MyTaskStkN-1],20);

增长方向向上:

OSTaskCreate(MyTask,&MyTaskAgu,&MyTaskStk[0],20);

             

2)  任务堆栈的初始化:

任务堆栈的初始化由UC/OS-II在创建任务函数OSTaskCreate()中通过调用任务堆栈初始化函数OSTaskStkInit()来完成任务堆栈初始化工作,其原型如下:

      

OS_STK *OSTaskStkInit(            //前三个参数跟创建任务函数参数一样

                            void (* task)(void *pd),

                            void  *pdato,

                            OS_STK *ptos,

                            INT16U  opt

);

7、任务控制块:

       任务控制块负责把任务代码和任务堆栈进行关联,使任务控制块、任务代码、任务堆栈成为一个整体,并系统要通过这个任务控制块来感知和管理一个任务,UCOS-II把系统所有任务的控制块链接为两条链表,通过对这两条链表管理各任务控制块。

1)  任务控制块的结构:

任务控制块是一个结构类型数据,当用户调用OSTaskCreate()创建一个用户任务时,此函数会对任务控制块中所有成员赋予与该任务相关的数据,并驻留在RAM中。

任务控制块结构定义如下:

/*其中成员OSCBStat用来存放任务的当前状态,该成员变量可能值:

        OS_STAT_RDY            表示任务处于就绪状态

        OS_STAT_SEM            表示任务处于等待信号量状态

        OS_STAT_MBOX         表示任务处于等待消息邮箱状态

        OS_STAT_Q                 表示任务处于等待消息队列状态

        OS_STAT_SUSPEND    表示任务处于被挂起状态

        OS_STAT_MUTEX       表示任务处于等待互斥信号量状态

*/

2)  任务控制块链表:

UCOS-II用两条链表来管理任务控制块,一条是空任务块链表OSTCBFreeList(其中所有任务控制块还没有分配给任务,应用程序调用OSInit()系统初始化时创建),另一条是任务块链表OSTCBList(其中所有任务控制块已经分配给任务,应用程序调用OSTaskCreate()创建任务时创建)。

系统调用函数OSInit()对系统进行初始化时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBTbl[],这样每个数组元素就是一个任务控制块,然后把这些控制块连接成如下一个链表:

UC/OS-II初始化时建立的空任务链表的元素个数:

OS_MAX_TASKS(用户任务的最大数目)+OS_N_SYS_TASKS(系统任务数目,其值为1或者2,为2时表示一个空闲任务一个统计任务)

              应用程序调用系统函数OSTaskCreate()或OSTaskCreateExt()创建一个任务时,系统就会将空任务控制块链表头指针OSTCBFreeList指向任务控制块分配给该任务,在给任务控制块中各成员赋值后,就按任务控制块链表的头指针OSTCBList将其加入到任务控制块链表中。如下图,创建了两个用户任务并使用了两个系统任务:

3)  任务控制块初始化:

当用户程序调用函数OSTaskCreate()创建一个任务时,这个函数会调用系统函数OSTCBInit()来为任务控制块进行初始化。这个函数首先为被创建任务从任务控制块链表获取一个任务控制块,然后用任务的属性对任务控制块各成员赋值,最后把这个任务控制块链入到任务控制块链表的头部。

初始化任务控制块函数OSTCBInit()原型:

       INT8U OSTCBInit(

                      INT8U    prio,              //任务优先级,保存在OSTCBPrio

                      OS_STK *ptos,      //任务堆栈栈顶指针,保存在OSTCBStkPtr

                      OS_STK *pbos,     //任务堆栈栈底指针,保存在OSTCBStkBottom

                      INT16U  id,          //任务的标识符,保存在OSTCBId

                      INT16U  stk_size,  //任务堆栈的长度,保存在OSTCBStkSize

                      void *pext,            //任务控制块的扩展指针,保存在OSTCBExtPtr

                      INT16U opt           //任务控制块的选择项,保存在OSTCBOpt

)

4)  任务控制块的删除

UC/OS-II允许用函数OSTaskDel()删除一个任务(实质上把该任务从任务控制块链表中删掉,并把它归于这个空任务控制块链表)。

           Uc/os-ii还定义了一个OS_TCB * OSTCBCur,专门存放当前正在运行的任务的任务控制块指针。

8、任务就绪表:

       多任务操作系统的核心就是任务调度(调度就是通过一个算法在多个任务中来确定哪个任务来运行),这项工作的函数就叫在调度器。UCOS-II任务调度器思想是每时每刻总让优先级最高的就绪任务处于运行状态,为了保证这一点,它在系统或用户任务调用昔日函数及执行中断服务程序结束时总是调用调度器来确定应该运行的任务并运行它。

1)  任务就绪表的结构:

系统总是从处于就绪状态的任务中来选择一个任务运行,为了使系统直到任务就绪情况,UC/OS-II在RAM中设立了一个记录表,系统中的每个任务都在这个表中占据一个位置,并用这个位置的状态(1或者0)来表示任务是否处于就绪状态。

UC/OS-II用数组INT8U  OSRdyTbl[]来充当这个任务就绪表,在这个任务就绪表中以任务优先级别高低顺序,为每个任务安排了一个二进制位,并规定该位值为1表示对应的任务处于就绪状态,否则非就绪状态。

由于每个任务的就绪状态只占一位,因此OSRdyTbl[]数组的一个元素可表达8个任务的就绪状态,即一个数组元素描述了8个任务的就绪状态,把这个8个任务看出一个任务组,如果OSRdyTbl[]数组有8个元素者可表示64个任务状态,UC/OS-II又定义变量INT8U  OSRdyCrp使该变量的每一个位都对应OSRdyTbl[]的一个任务组,并规定如果某任务组中有任务就绪,者变量OSRdyCrp把该任务组对应的位置为1,否则为0。

例如; OSRdyGrp=11100101,那么OSRdyTbl[0]OSRdyTbl[2]OSRdyTbl[5]OSRdyTbl[6]OSRdyTbl[7]任务组中有任务就绪。

任务就绪表如下INT8U  OSRdyTbl[]:

任务组如下INTU8  OSRdyGrp:

2)  任务就绪表的操作:

任务优先级、任务组和任务就绪表的关系如下图:

把优先级为prio的任务置为就绪状态:

OSRdyGrp | =OSMapTbl[prio>>3];     //提取三四五位得到是哪一个任务组

OSRdyTbl[prio>>3] | =OSMapTbl[prio&0x07];//提取任务在数组元素中对应位置

        其中OSMapTbl[]UC/OS-II为加快运算速度定义的一个数组,它各元素值为:

        OSMapTbl[0]=00000001B                  OSMapTbl[4]=00010000B

        OSMapTbl[1]=00000010B                  OSMapTbl[5]=00100000B

        OSMapTbl[2]=00000100B                  OSMapTbl[6]=01000000B

        OSMapTbl[3]=00001000B                  OSMapTbl[7]=10000000B

              如果要使一个优先级为prio的任务脱离就绪状态:

                     if((OSRdyTbl[prio>>3]&=-OSMapTbl[prio&0x07])==0)

                            OSRdyGrp&=-OSMapTbl[prio>>3];

              从任务就绪表中获取优先级别最高的就绪任务:

                     y=OSUnMapTal[OSRdyGrp];       //获取优先级别的D5D4D3

                     x=OSUnMapTal[OSRdyTbl[y]];   //获取优先级别的D2D1D0

                     prio=(y<<3)+x;                           //获得就绪任务的优先级别

              或

                     y=OSUnMapTbl[OSRdyGrp];

                     prio=(INT8U)((y<<3)+OSUnMapTbl[OSRdyTbl[y]]);

                     其中OSUnMapTbl[]是用来提高查找速度的数组。

9、任务的调度:

       任务调度器的主要工作有两项:一是在任务就绪表中查找具有最高优先级的就绪任务,二是实现任务的切换。UC/OS-II有两种调度器:一种是任务级的调度器(由OSSched()函数实现调度),另一种是中断级的调度器(由OSIntExt()来实现调度)。任务调度器把任务切换的工作分为两个步骤:第一步获得待运行任务的TCB指针,第二步是进行断点数据的切换。

       1)获得待运行就绪任务控制块的指针:

              因为被中止任务的任务控制块指针存放在全局变量OSTCBCur中,所以调度器这部分的工作主要是获得待运行任务的任务控制块指针。

              任务调度器OSSched()源代码如下:

              调度器OSSched()源码解析:

              UC/OS-II允许应用程序通过调用函数OSSchedLock()OSSchedUnlock()给调度器上锁和解锁。调度器每被上锁一次,变量OSLockNesting就加1,调度器每被解锁一次,变量OSLockNesting,就减1。调度器OSSched()在确认未被上锁并且不是中断服务程序调用调度器的情况下,首先任务就绪表中查得的最高优先级别就绪任务的优先级别OSPrioHighRdy,然后确认这个就绪任务不是当前正在运行的任务(OSPrioCur是存放正在运行任务的优先级变量)的条件下,用数组OSTCBPrioTble[OSPrioHighRdy]的值(即待运行就绪任务的任务控制块指针)赋给指针变量OSTCBHighRdy

于是下面可以根据OSTCBHighRdyOSTCBCur这两个指针分别指向待运行任务控制块和当前任务控制块的指针在宏OS_TASK_SW()中实施任务切换。

       2)任务切换宏OS_TASK_SW():

10、任务的创建:

       1)OSTaskCreate()创建任务:

              OSTaskCreate()函数对待创建任务的优先级进行一系列判断,确认该优先级合法未被使用之后,调用函数OSTaskStkInit()OSTCBInit()对任务堆栈和任务控制块进行初始化。初始化成功后把任务计数器加1,判断UC/OS-II的核是否在运行状态,如果OSRunning的值为1,者调用OSSched()进行任务调度。

         

2)OSTaskCreateExt()创建任务其原型:

1)  创建任务一般方法:

Void main(void)

{

       ……

       OSInit();              //对UC/OS-II进行初始化

       …….

       OSTaskCreate(TaskStart,….);           //创建起始任务TaskStart

       OSStart();     //开启多任务调度

}

                   Void TaskStart(void   *pdata)

                   {

                            …….                            //此处安装并启动UC/OS-II时钟

                            OSStatInit();      //初始化统计任务

                            ……..                  //此处创建其他任务

                            for(;;)       

                            {

                                     起始任务TaskStart代码

}

}

注意:UC/OS-II不允许在中断服务程序中创建任务。

11、任务管理函数:

       所谓挂起一个任务就是停止这个任务的运行。用户任务可通过调用系统提供的函数OSTaskSuspend()来挂起自身或者除空闲任务之外的其他任务,且只能在其他任务中通过调用恢复函数OSTaskReume()使其恢复为就绪状态。

1)  挂起任务:

INT8U     OSTaskSuspend(INT8U  prio);

参数prio:为带挂起任务的优先级别,若要挂起自身,参数为OS_PRIO_SELF

返回值:成功返回OS_NO_ERR,否则返回错误具体情况

功能描述:一系列判断待挂起的任务是这个函数的任务本身,如果是本身必须删除该任务在任务就绪表中的就绪标识,并在任务控制块成员OSTCBStart中做了挂起记录之后引发一次任务调度,如果带挂起任务不是调用函数的任务本身,那么只需要删除任务就绪表中被挂起任务的就绪标志,并在任务控制块成员OSTCBStart做了挂起记录即可。

2)  恢复任务:

INT8U     OSTaskResume(INT8U  prio);

参数prio:为带挂起任务的优先级别

返回值:成功返回OS_NO_ERR,否则返回错误具体情况

功能描述:判断任务确实是已存在的挂起任务,同时又不是一个等待任务(任务控制块成员OSTCBDly=0)时,就清除任务控制块成员OSTCBStat中的挂起记录并使任务就绪,最后调用调度器OSSched()进行任务调度。

3)  任务优先级别的修改:

INT8U     OSTaskChangePrio(

INT8U  oldprio,           //任务现在的优先级别

INT8U  newprio           //需要修改的优先级别

);

返回值:成功返回OS_NO_ERR,否则返回错误具体情况

4)  任务的删除

所谓删除一个任务就是把该任务置于睡眠状态,即先把任务控制块从任务控制块链表中删除,并归还给空任务控制块链表,然后再任务就绪表中把该任务的就绪状态置0.

INT8U    OSTaskDel(INT8U  prio);

参数:要删除任务的优先级别,若要删除自身,参数为OS_PRIO_SELF

5)  请求删除任务函数:

通常为了防止删除占用资源的任务,UC/OS-II提供了一个信号OSTCBDelReq:请求删除任务函数OSTaskDelReq(),这样提出删除任务请求的任务和被删除任务的双方都使用该函数来访问OSTCBDelReq这个信号,从而根据这个信号的状态来决定各自的行为。

INT8U    OSTaskDelReq(INT8U  prio);

参数:提出删除任务请求的任务在调用此函数时参数为待删除任务的优先级,被删除任务在调用此函数时参数为OS_PRIO_SELF

功能描述:删除任务请求方调用此函数目的是查看被删除的任务控制块是否还在,如果不在认为被删除任务已经被删除,否则令被删除任务的任务控制块成员OSTCBDelReq的值为OS_TASK_DEL_REQ表示该任务在合适的时候删除自己。

例如:

被删除任务调用此函数时,判断参数为OS_PRIO_SELF时,就会返回自己任务控制块成员OSTCBDelReq的值,若该值为OS_TASK_DEL_REQ,意味有其他任务发来栓出自己的请求,那么就应该在适当的时候调用OSTaskDel(OS_PRIO_SELF)来删除自己。

例如:

6)  查询任务信息函数:

INT8U     OSTaskQuery(

                                    INT8U    prio,              //待查询任务的优先级别

                                    OS_TCB        *pdata     //存储任务信息的结构

);

              返回值:成功将返回OS_NO_ERR并把查询得到的任务信息存放在结构OS_TCB类型变量中。

12、UC/OS-II的初始化和任务启动:

1)UC/OS-II的初始化:

       在使用uc/os-ii的所有服务之前,必须调用OSInit()函数对自身的运行环境进行初始化。

       OSInit()对UC/OS-II的所有全局变量和数据结构进行初始化,同时创建空闲任务OSTaskIdlc或者统计任务,其对数据结构进行初始化,主要是创建包括空任务控制块链表在内的5个空数据缓冲区,同时为了快速的查询任务控制块链表中的各个元素,OSInit()还得创建数组OSTCBPrioTbl[OS_LOWEST_PRIO+1]。经过初始化后,系统数据结构如下:

2)UC/OS-II的启动:

       UC/OS-II进行任务的管理是从调用启动函数OSStart()开始的,当然前提条件是调用之前至少创建了一个用户。

void  OSStart (void)

{

    if (O       SRunning == OS_FALSE)   //若OS是未处于运行状态

{

        OS_SchedNew();                //查找最高优先级

        OSPrioCur     = OSPrioHighRdy;

        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

 /* Point to highest priority task ready to run    */

        OSTCBCur      = OSTCBHighRdy;

        OSStartHighRdy();       

                    /* Execute target specific code to start task     */

    }

}

OSStartHighRdy()在多任务系统启动函数OSStart()中调用,实现的功能是,设置系统运行标位OSRunning=TRUE,将就绪表中最高优先级任务的栈指针加载到SP中,并强制中断返回,这样就绪的最高优先级任务就如同从中断里返回到运行态一样,使得整个系统得以运作。

三、UC/OS_II的中断和时钟:

1、UC/OS-II的中断:

       UC/OS-II系统响应中断的过程是:系统接收到中断请求后,如果此时CPU处于中断允许状态,系统就会中止当前任务,按照中断向量转而运行中断服务子程序,当中断服务子程序运行结束后,系统就会根据情况返回到被中止的任务继续运行或者进行一次调度运行到另一个更高优先级的就绪任务。中断可嵌套,UCOS-II定义了一个全局变量OSIntNesting来记录中断嵌套的层数。

       在编写中断服务程序时要用到两个重要的函数OSIntEnter()OSIntExit()。一个中断服务子程序的流程图如下:

                            

1)  进入中断服务函数OSIntEnter:

void  OSIntEnter (void)

{

    if (OSRunning == OS_TRUE) {

        if (OSIntNesting < 255u) {

            OSIntNesting++;                 //中断嵌套层数计数器加1

        }}}

说明:此函数经常在中断服务程序被中断任务的断点数据之后,运行用户中断服务代码之前调用,统计嵌套层数,因此叫做进入中断服务函数。

2)  退出中断服务函数OSIntExit:

说明:此函数判断中断嵌套层数为0,调度器未被锁定且从任务就绪表中查找到得最高优先级就绪任务又不是被中断的任务的条件下调用OSIntCtxSw进行任务切换,否则返回被中断的服务子程序。

3)  中断级任务切换函数OSIntCtxSw:

中断级任务切换函数OSIntCtxSw()与任务级切换函数OSCtxSw()的一样,通常由汇编代码编写,如下:

 

 

 

OSCtxSw ;任务级切换函数    

    LDR     R0, =NVIC_INT_CTRL 

    LDR     R1, =NVIC_PENDSVSET

    STR     R1, [R0]  ;设置ICSR寄存器,产生pendSV异常

    BX      LR

 

OSIntCtxSw ;中断级任务调用

    LDR     R0, =NVIC_INT_CTRL 

    LDR     R1, =NVIC_PENDSVSET

    STR     R1, [R0]

    BX      LR

4)  临界段:

CPU只有在中断开放期间才能响应中断请求,而在其他时间不能响应中断请求。为增加代码移植性,UCOS-II用OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()两个宏来实现中断的开放和关闭,而把与系统硬件相关的关中断和开中断指令分别封装在这两个宏中。

2、UC/OS-II的时钟:

       用硬件定时器产生一个周期为ms级的周期性中断来实现系统时钟,最小的时钟单位就是两次中断之间的时间间隔,这个最小时钟单位叫做时钟节拍(Time Tick)。硬件定时器以时钟节拍为周期定时的产生中断,该中断服务程序叫做OSTickISR()如下:

       Void        OSTickISR(void)

       {

              ………;                 //保存CPU寄存器;

              OSIntEnter();        //进入中断服务函数

              If(OSIntNesting==1)

              {

                     OSTCBCur->OSTCBStkPtr=SP;   //保存堆栈指针

}

OSTimeTick();     //调用节拍处理函数

………;                 //此处清除中断

………;                 //此处开中断

OSIntExit();          //退出中断服务函数

………;                 //恢复CPU寄存器,中断返回

}

1)  时钟节拍服务函数OSTimeTick:

时钟中断服务程序中调用了OSTimeTick(),此函数做了两件事情:一是给计数器OSTime加1,二是遍历任务控制块链表中的所有任务控制块,把各个任务控制块中用来存放任务延时时限成员变量OSTCBDly减1,并使该项为0同时又不被挂起的任务进入就绪状态(即在每个时钟节拍了解每个任务的延时状态,使其中已经到了延时时限的非挂起任务进入就绪状态)。其源码如下:

2)  时钟节拍钩子函数OSTimeTickHook:

OSTimeTick()是系统调用的函数,为了方便应用程序设计人员在系统调用的函数中插入一些自己的工作,UC/OS-II提供了时钟节拍服务函数的钩子函数OSTimeTickHook().

3)  获取和设置系统时钟:

系统定义了一个INT32U类型的全局变量OSTime来记录系统发生的时钟节拍数,OSTime在应用程序调用OSStart()时被初始化为0,以后每发生1个时钟节拍其值就被1。应用程序调用OSTimeGet()可获取OSTime的值,调用OSTimeSet可设置OSTime

        Void  OSTimeGet(void);      //返回值为OSTime

        Void   OSTimeSet(INT32U  ticks);    //参数为OSTime的设置值

4)  任务的延时:

为使高优先级的任务不至于独占CPU,UC/OS-II规定除了空闲任务之外的所有任务必须在任务中合适的位置调用系统提供的函数OSTimeDly(),使当前任务的运行延时一段时间并进行一次任务调度,以让出CPU使用权。

调用了函数OSTimeDly()或OSTimeDlyHMSM()的任务,当规定的延时时间期满,或有其他任务通过调用函数OSTimeDlyResume()取消延时是,它会立即进入就绪状态。

 

相关文章:

UCOS-II 自学笔记

摘抄于大学期间记录在QQ空间的一篇自学笔记&#xff0c;当前清理空间&#xff0c;本来想直接删除掉的&#xff0c;但是感觉有些舍不得&#xff0c;因此先搬移过来。 一、UC/OS_II体系结构 二、UC/OS_II中的任务 1、任务的基本概念 在UCOS-II中&#xff0c;通常把一个大型任…...

C++ - 二叉搜索树讲解

二叉搜索树概念和定义 二叉搜索树是一个二叉树&#xff0c;其中每个节点的值都满足以下条件&#xff1a; 节点的左子树只包含小于当前节点值的节点。节点的右子树只包含大于当前节点值的节点。左右子树也必须是二叉搜索树。 二叉树搜索树性质 从上面的二叉搜索树定义中可以了…...

基于开源云原生数据仓库 ByConity 体验多种数据分析场景

基于开源云原生数据仓库 ByConity 体验多种数据分析场景 业务背景什么是 ByConity上手实测环境要求测试操作远程登录 ECS 服务器windows10 自带连接工具 执行查询 ByConity 相对于 ELT 能力的优化提升并行度任务级重试并行写入简化数据链路 业务背景 大家都知道&#xff0c;在…...

RabbitMQ 消息确认机制

RabbitMQ 消息确认机制 本文总结了RabbitMQ消息发送过程中的一些代码片段&#xff0c;详细分析了回调函数和发布确认机制的实现&#xff0c;以提高消息传递的可靠性。 返回回调机制的代码分析 主要用途 这个代码主要用于设置RabbitMQ消息发送过程中的回调函数&#xff0c;即…...

Node.js:开发和生产之间的区别

Node.js 中的开发和生产没有区别&#xff0c;即&#xff0c;你无需应用任何特定设置即可使 Node.js 在生产配置中工作。但是&#xff0c;npm 注册表中的一些库会识别使用 NODE_ENV 变量并将其默认为 development 设置。始终在设置了 NODE_ENVproduction 的情况下运行 Node.js。…...

【QT】背景,安装和介绍

TOC 目录 背景 GUI技术 QT的安装 使用流程 QT程序介绍 main.cpp​编辑 Wiget.h Widget.cpp form file .pro文件 临时文件 C作为一门比较古老的语言&#xff0c;在人们的认知里始终是以底层&#xff0c;复杂和高性能著称&#xff0c;所以在很多高性能需求的场景之下…...

从0到1搭建webpack

好&#xff0c;上一篇文章我们说了一下在react中怎么弄这个webpack&#xff0c;那么现在在说一下不用react我们又该怎么配置&#xff0c;这些呢也都是我自己通弄过看视频自己总结的&#xff0c;拿来给大家分享一下。 前期准备条件 1、nvm&#xff08;可以快速切换node版本&am…...

针对解决conda环境BUG的个人笔记

1-conda学习&安装 安装视频&#xff1a; 零基础教程&#xff1a;基于Anaconda和PyCharm配置Pytorch环境_哔哩哔哩_bilibili 安装过程&#xff1a; MX250笔记本安装Pytorch、CUDA和cuDNN-CSDN博客 Win10MX250CUDA10.1cuDNNPytorch1.4安装测试全过程(吐血)_nvidia geforc…...

读《Effective Java》笔记 - 条目13

条目13&#xff1a;谨慎重写clone方法 浅拷贝和深拷贝 浅拷贝&#xff08;Shallow Copy&#xff09; 浅拷贝 只复制对象本身&#xff0c;而不复制对象引用的成员。 对于引用类型的字段&#xff0c;浅拷贝会将原对象的引用复制到新对象中&#xff0c;而不会创建新对象实例。因…...

SQL 之连接查询

SQL 连接查询&#xff1a;深入理解 JOIN 操作 在数据库管理中&#xff0c;连接查询&#xff08;JOIN&#xff09;是一种基本而强大的操作&#xff0c;它允许我们从两个或多个表中检索数据。SQL 中的 JOIN 操作使得数据整合变得简单&#xff0c;这对于数据分析和报告至关重要。…...

vscode切换anaconda虚拟环境解释器不成功

问题&#xff1a; 切换解释器之后运行代码还是使用的原来的解释器 可以看到&#xff0c;我已经切换了“nlp”解释器&#xff0c;我的nltk包只在“nlp”环境下安装了&#xff0c;但是运行代码依然是"torch"解释器&#xff0c;所以找不到“nltk”包。 在网上找了各种…...

一个实用的 Maven localRepository 工具

目录 1 现状2 当前解决3 更好的解决3.1 下载 Maven localRepository 工具包3.2 上传本地 localRepository 包3.3 清理 localRepository 中指定后缀的文件 1 现状 在使用 Maven 时&#xff0c;我们可能会经常与本地仓库和私服仓库打交道。 例如对于本地仓库&#xff0c;因为某…...

目标检测,图像分割,超分辨率重建

目标检测和图像分割 目标检测和图像分割是计算机视觉中的两个不同任务&#xff0c;它们的输出形式也有所不同。下面我将分别介绍这两个任务的输出。图像分割又可以分为&#xff1a;语义分割、实例分割、全景分割。 语义分割&#xff08;Semantic Segmentation&#xff09;&…...

微信小程序 城市点击后跳转 并首页显示被点击城市

在微信小程序中&#xff0c;渲染出城市列表后&#xff0c;如何点击城市&#xff0c;就跳转回到首页&#xff0c;并在首页显示所点击的城市呢&#xff1f; 目录 一、定义点击城市的事件 二、首页的处理 首页&#xff1a;点击成都市会跳转到城市列表 城市列表&#xff1a;点击…...

Linux - nfs服务器

五、nfs服务器 1、基础 NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文件系统中&#xff0c;而在本地端的系统 中看来&#xff0c;那个远程主机的目录就好像是自己的一个磁盘分区一样。 由于NFS支持的功能比较多&#xff0c;而不同的功能都会使用不同的程…...

uniapp图片上传预览uni.chooseImage、uni.previewImage

文章目录 1.上传图片2.预览图片 1.上传图片 uni.chooseImage(OBJECT) 从本地相册选择图片或使用相机拍照。 App端如需要更丰富的相机拍照API&#xff08;如直接调用前置摄像头&#xff09;&#xff0c;参考plus.camera 微信小程序从基础库 2.21.0 开始&#xff0c; wx.choos…...

C++ 字符串中数字识别

【问题描述】 输入一个字符串&#xff0c;含有数字和非数字字符&#xff0c;如“sumabc234;while(abc700)tab{ass346;bssabc267;}”&#xff0c;将其中连续的数字作为一个整数&#xff0c;依次存放到一个数组nums中。例如&#xff0c;234放在nums[0]&#xff0c;700放在nums[1…...

学术中常见理论归纳总结-不定期更新

1.信息传播类 1.1 扩散创新理论 创新扩散理论是传播效果研究的经典理论之一,是由美国学者埃弗雷特罗杰斯(E.M.Rogers)于20世纪60年代提出的一个关于通过媒介劝服人们接受新观念、新事物、新产品的理论,侧重大众传播对社会和文化的影响。 1927-1941年进行的“艾奥瓦杂交玉…...

ModelSim怎么修改字体及大小

点击TOOLS 选择PERFERENCES选择下一级菜单的TEXTFONT/CHOOSE/选择字体和大小最后不要忘记点apply再退出...

图片预处理技术介绍4——降噪

图片预处理 大家好&#xff0c;我是阿赵。   这一篇将两种基础的降噪算法。   之前介绍过均值模糊和高斯模糊。如果从降噪的角度来说&#xff0c;模糊算法也算是降噪的一类&#xff0c;所以之前介绍的两种模糊可以称呼为均值降噪和高斯降噪。不过模糊算法对原来的图像特征的…...

Scrapy管道设置和数据保存

1.1 介绍部分&#xff1a; 文字提到常用的Web框架有Django和Flask&#xff0c;接下来将学习一个全球范围内流行的爬虫框架Scrapy。 1.2 内容部分&#xff1a; Scrapy的概念、作用和工作流程 Scrapy的入门使用 Scrapy构造并发送请求 Scrapy模拟登陆 Scrapy管道的使用 Scrapy中…...

D84【python 接口自动化学习】- pytest基础用法

day84 pytest常用断言类型 学习日期&#xff1a;20241130 学习目标&#xff1a;pytest基础用法 -- pytest常用断言类型 学习笔记&#xff1a; 常用断言类型 代码实践 def test_assert():assert 11assert 1!2assert 1<2assert 2>1assert 1>1assert 1<1assert a…...

如何正确书写sh文件/sh任务?bash任务

正确书写xx.sh文件的方式为&#xff1a; source /usr/local/miniconda3/bin/activate condaEnv export CUDA_VISIBLE_DEVICES0 cd /hy-tmp/test export PYTHONPATH"xxx:$PYTHONPATH" python AAA.py python BBB.py python CCC.py 直接运行&#xff1a; bash xx.sh 即可…...

多线程篇-5--线程分类(线程类型,springboot中常见线程类型,异步任务线程)

常见的线程类型包括用户线程&#xff08;User Threads&#xff09;、守护线程&#xff08;Daemon Threads&#xff09;、主线程&#xff08;Main Thread&#xff09;、工作线程&#xff08;Worker Threads&#xff09;和线程池中的线程。 一、用户线程&#xff08;User Thread…...

docker快速部署gitlab

文章目录 场景部署步骤默认账号密码效果 场景 新增了一台机器, 在初始化本地开发环境&#xff0c;docker快速部署gitlab 部署步骤 编写dockerfile version: 3.7services:gitlab:image: gitlab/gitlab-ce:latestcontainer_name: gitlabrestart: alwayshostname: gitlabenviron…...

C# 数据类型详解:掌握数据类型及操作为高效编码奠定基础

本文将带你深入了解C#中各种数据类型的特点、用途和最佳实践&#xff0c;让你不仅能熟练运用基本类型&#xff0c;还能掌握如何在实际项目中做出最合适的选择。 目录 C#基本语法 C#数据类型 C#类型转换 C#变量常量 C#基本语法 在学习C#之前我们要先知道C#的基础构建是由哪些…...

burp2

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…...

[ACTF2020 新生赛]BackupFile--详细解析

信息搜集 让我们寻找源文件&#xff0c;目录扫描&#xff1a; 找到了/index.php.bak文件&#xff0c;也就是index.php的备份文件。 后缀名是.bak的文件是备份文件&#xff0c;是文件格式的扩展名。 我们访问这个路径&#xff0c;就会直接下载该备份文件。 我们把.bak后缀删掉…...

循环神经网络(RNN)简述

RNN及其变体 1、概述 (一)、概念 RNN(Recurrent Neural Network), 中文称作循环神经网络, 它一般以序列数据为输入, 通过网络内部的结构设计有效捕捉序列之间的关系特征, 一般也是以序列形式进行输出。 RNN的循环机制使模型隐层**上一时间步产生的结果, 能够作为当下时间步…...

九、Ubuntu Linux操作系统

一、Ubuntu简介 Ubuntu Linux是由南非人马克沙特尔沃思(Mark Shutteworth)创办的基于Debian Linux的操作系统&#xff0c;于2004年10月公布Ubuntu是一个以桌面应用为主的Linux发行版操作系统Ubuntu拥有庞大的社区力量&#xff0c;用户可以方便地从社区获得帮助其官方网站:http…...

网络公司网站建设/昆明百度推广开户费用

中科院外籍院士姚期智&#xff1a;科学家与科学之路 ■姚期智我从事科学工作几十年&#xff0c;也认识了很多杰出的科学家。我自己觉得科学家的生涯很有收获&#xff0c;当科学家是一个非常好的体验&#xff0c;从中可以品尝到巨大的乐趣。首先&#xff0c;我要谈一谈什么是科…...

wordpress建官网怎样/哪有培训seo

日志报警&#xff1a;$ORACLE_BASE/diag/rdbms/jrdb/trace/alert_jrdb.log出现这个报警的时间点正好是在12:06-12:18这段时间内&#xff0c;IDC生产环境&#xff0c;网络出现故障&#xff0c;造成域名解析发生错误.**********************************************************…...

开发公司组织架构及岗位职责/宁波seo咨询

一、对MySQL的锁的了解当数据库有并发事务的时候&#xff0c;可能会产生数据的不一致&#xff0c;这时候需要一些机制来保证访问的次序&#xff0c;锁机制就是这样的一个机制。就像酒店的房间&#xff0c;如果大家随意进出&#xff0c;就会出现多人抢夺同一个房间的情况&#x…...

网站没有设置关键词/google推广技巧

在模拟和数字PCB设计中&#xff0c;旁路或去耦电容(0.1uF)应尽量靠近器件放置。供电电源去耦电容(10uF)应放置在电路板的电源线入口处。所有情况下&#xff0c;这些电容的引脚都应较短。 在模拟布线设计中&#xff0c;旁路电容通常用于旁路电源上的高频信号&#xff0c;如果不加…...

删掉cache wordpress/万网域名查询官网

原文 对于我们CSS开发者来说经常听到一些关于LESS和SASS的信息,但是我们并不知道这都是什么意思,这篇文章就是为我们而准备的.在调查这些语言后,我已经发现它们都是一些js文件,运行后会产生相应CSS文件给我们.为什么我们要使用LESS和SASS它们呢,因为我们可以避免CSS中需要的重复…...

成都医院手机网站建设/兰州seo优化公司

无意间发现之前搭建MySQL的时候&#xff0c;有将操作过程记录下来&#xff0c;涉及主机系统配置修改&#xff0c;MySQL用户和目录创建&#xff0c;初始化等操作。未免日后遗忘&#xff0c;特保存在这里。有些步骤可能会有错&#xff0c;需要甄别。注&#xff1a;mysql-5.7.91、…...