UCOS-II的基本概念

2023-05-16

UCOS—II

一、实时操作系统的概念

1.1 操作系统

​ 操作系统是一种系统软件,他在计算机硬件与计算机应用程序之间,通过提供程序接口,屏蔽了计算机硬件工作的一些细节,从提高了应用程序的开发效率。

应用在嵌入式系统中的操作系统称为嵌入式操作系统

1.2 前后台系统

​ 不复杂的小系统一般设计成前后台系统(也称超循环系统)。应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台系统。中断服务程序处理异步事件,这部分可以看成前台系统。后台也可以叫任务级,前台也可以叫中断级。时间相关很强的关键操作一定是靠中断服务来保证的,因为中断服务提供的信息一定要等到后台程序走到该处理信息这一步时才能得到处理,因此这种系统在处理信息的及时性上,比实际可以做到的要差。这个指标称作任务的相应时间,最坏情况下的任务级相应时间取决于整个循环的执行时间。因为循环的执行时间不是常数,程序经过某一特定的部分的准确时间也是不能确定的。

​ 很多基于微处理器的产品处采用前后台系统设计,如微波炉、玩具、电话机等。

图片1(前后台系统)

1.3 实时操作系统

​ 如果操作系统能使计算机系统及时响应外部事件的请求,并能及时控制所有实时设备与实时系统协调运行,且能在一个规定的时间内完成对时间的处理,那么这种操作系统就是一个实时操作系统。

实时系统的两个基本要求

  1. 实时系统的计算必须产生正确的结果,称为逻辑或功能正确
  2. 实时系统的计算必须在预定的时间内完成,称为时间正确

按时间正确的程度来分,实时操作系统又分为硬实时操作系统和软实时操作系统两种。

**硬实时操作系统:**要求系统必须在极严格的时间内完成实时任务

**软实时操作系统:**系统完成实时任务的截止时间要求不是十分严格

实时操作系统需要满足的条件

  1. 实时操作系统必须是多任务系统
  2. 任务的切换时间应与系统中的任务数无关
  3. 中断延时时间可预知并尽可能短

UCOS—II是一个嵌入式多任务试试操作系统。

二、任务的相关概念

​ 多任务操作系统在设计较为复杂的应用程序时,通常把大型任务分解成多个小任务,然后再计算机中通过运行这些小任务,最终达到完成大任务的目的。这种方法可以使任务并发的运行多个任务,从而提高处理器的利用率,加快程序的执行速度。

​ UCOS-II就是一个能对这些小任务的运行进行管理和调度的多任务系统。

​ UCOS-II的任务由三个部分所组成:任务程序代码(函数)、任务堆栈和任务控制块。其中,任务控制块就是关联了任务代码的程序控制块,它记录了任务的各个属性;任务堆栈则用来保存任务的工作环境;任务程序代码就是任务的执行部分。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bbAEtnok-1631626214977)(https://i.loli.net/2021/08/04/GHsovt5CqTWgfJl.png)]

根据任务是否具有自己的私有运行空间,可以把任务分成”线程“或”进程“。具体来说,具有私有空间的任务叫做进程,没有私有空间的任务叫做线程。

从任务的组成上来看,UCOS-II没有给任务定义私有空间,因此UCOS-II中所有的任务都属于线程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xfTyPRJX-1631626214978)(https://i.loli.net/2021/08/04/w49AecBNh5rWFJy.png)]

UCOS-II的任务由两种:用户任务和系统任务,由应用程序设计者编写的任务,叫做用户任务;由系统提供的任务叫做系统任务;系统任务是胃应用程序提供某种服务或为系统本身服务的服务的,在UCOS-II中,最多可包含64个任务(包括用户任务和系统任务)。

64个任务中,保留了4个最高优先级和4个最低优先级任务供UCOS-II自己使用,所以用户可以使用的只有56个任务。任务的优先级越高,反映的优先级的值则越低。

​ 一个任务,也称作一个线程,是一个简单的程序,该程序可以认为CPU完全只属于该程序自己。试试应用程序的设计过程,包括如何吧问题分割成多个任务,每个任务都是整个应用的某一部分,每个任务都被赋予一定的优先级,有自己的一套CPU寄存器和直接的栈空间。

图片2(任务概念)

​ UCOS-II是按照系统中只有一个CPU来设计的,在这种系统中,一个时刻只会有一个任务占用CPU处在运行状态,而其他任务只能处在其他状态。

任务的状态说明
休眠态任务只是以代码的形式驻留在程序空间(ROM或RAM),还没有交给操作系统管理,当并不被多任务内核所调度
就绪态意味着任务具备了运行的充分条件,可以运行了,但是由于任务的优先级比正在运行的任务的优先级低,因此暂时还不能运行
运行态指任务掌握了CPU的控制权,正在运行中,任何时刻只能有一个任务处于运行状态。
挂起态也叫做等待事件态,指任务在等待某一时间的发生(例如等待某外设的I/O操作,等待某共享资源由暂不能使用变成能使用状态,等待定时脉冲的到来或等待超时信号的到来以结束目前的等待,等待)。
中断态一个正在运行的任务一旦响应中断申请就会在中断运行而去执行中断服务程序,这时候任务的状态叫做中断服务态。

​ 在系统任务的管理下,一个任务可以在5个不同对的状态自己发生转换。其转换关系如下图所示。

图片3(任务的5种状态)

三、任务调度的相关概念

用户任务代码的结构

任务的执行代码通常是一个无线循环的结构,并且在这个循环中可以响应中断,这种结构也叫做超循环结构

void Task1(void *pdata)
{
    while(1)
    {
        可以被中断的用户代码;
        OS_ENTHER_CRITICAL();  //进入临界端(关中断)
        不可以被中断的用户代码;
         OS_EXIT_CRITICAL();  //退出临界段(开中断)
        可以被中断的用户代码;
    }
}

一个UCOS-II任务的代码就是一个C语言函数,为了可以传递各种不同类型的数据甚至是函数,所以UCOS-II把任务的参数定义成一个void类型的指针。

用户应用程序的结构

​ 用户的任务就是一个C语言函数,当时这个函数不是由主函数main()调用的函数,在系统中他与主函数main()处于平等的地位,他们何时被运行以及何时被终止都是由操作系统来调度的。

​ main()是一个应用程序的主函数,是程序运行的入口点,所以虽然它不调用任务,但是负责任务的创建并将他们交给系统,至于何时运行,则与主函数无关。

void main()
{
	......
	OSInit();  //初始化UCOS-II
	......
	OSTaskCreate(Task1,......);  //创建用户任务1
	OSTaskCreate(Task2,......);  //创建用户任务2
	......
	OSStart();  //启动UCOS-II
	......
}

void Task1(void *pdata)  //定义用户任务1
{
    while(1)
    {
        ......
    }
}
void Task2(void *pdata)  //定义用户任务2
{
    while(1)
    {
        ......
    }
}

OSTaskCreate()是UCOS-II提供的用来创建任务的函数;

OSStart()启动UCOS-III的函数。系统被启动后,任务就由操作系统来管理和调度了。

系统任务

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

空闲任务

在系统运行的过程中,极有可能会在某个时间内无用户任务可运行而处于所谓的空闲状态。为了使CPU在没有用户任务可执行时有事可做,UCOS-II提供了一个叫做空闲任务OSTaskIdle()的系统任务。其代码如下

void OStaskIdle(void *pdate)
{
# if OS_CRITICAL_METHOD == 3
	OS_CPU_SR cpu_sr;
#endif

	padta = pdata;     //防止某些编译器报错
	while(1)
	{
		OS_ENTER_CRITICAL();  //关闭中断
			OSdleCtr++;    //计数
		OS_EXIT_CRITICAL(); //开放中断
	}
}

空闲任务几乎不做什么东西,只是对系统定义的一个空闲任务次数运行次数计数器OSdleCtr进行加1操作。UCOS-II规定,一个用户应用程序必须使用这个空闲任务,而且这个任务不能通过程序来删除。

​ 至于代码中的“Pdata = pdata;"是为了防止编译器报错而使用的一个程序设计技巧,因为空闲任务没有用参数pdata,而某些C编译器会对这种情况报错(说定义了参数却没有使用),有了这行代码,编译器就不会报错了。

统计任务

​ UCOS-II提供的另一个系统任务就是统计任务()。该任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCOUsage中,以便其他应用程序来了解CPU的利用率。

​ 系统是否使用统计任务,用户可以根据应用程序的实际需求来进行选择。如果用户应用程序决定要使用统计任务,则必须把定义在系统头文件OS_CFG.H中的系统配置常数OS_TASH_STAT_EN设置为1,并且在程序中要调用函数OSStatInit()对统计任务进行初始化。

任务的优先权级优先级别

​ UCOS-II中创建追到64个任务(0-63)。数字越小,优先级别越高。

​ UCOS-II在系统配置文件OS_CFG.H中定义了一个用来表示最低优先级别的参数OS_LOWEST_PRIO,如果用户为其赋了值,那么就以为着系统可用的优先级有OS_LOWEST_PRIO+1个(0到OS_LOWEST_PRIO)。

​ 另外,系统会把最低优先级别OS_LOWEST_PRIO自动赋值给统计任务,如果应用程序使用了统计任务,则系统还会把优先级别OS_LOWEST_PRIO-1自动赋值给统计任务。

任务堆栈

任务堆栈是任务的重要的组成部分

堆栈就是在存储器中按“后进先出(LIFO)”的原则组织的连续存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其他函数时的需要,每个任务都应该配有自己的堆栈。所有UCOS-II任务的任务控制块中都含有一个指向该任务堆栈的指针。

四、中断的相关概念

​ 任务在运行过程中,应内部或外部异步事件的请求中止当前任务,而去处理异步事件所要求的过程叫做中断。应中断请求而运行的程序叫做中断服务子程序(ISR),中断服务子程序的入口地址叫做中断向量。

4.1.1 UCOS-II的中断过程

​ UCOS-II系统响应中断的过程是:系统接收到中断请求后,如果这时CPU出于中断允许状态,系统就会中止正在运行的当前任务,而按照中断向量的指向转而去运行中断服务子程序;当终端服务子程序的运行结束后,系统将会根据返回情况返回到被中止的任务继续运行,或者转向运行另一个具有更高优先级别的就绪任务。

​ 对于可剥夺型UCOS-II内核,中断服务子程序运行结束之后,系统将会根据情况进行一次任务调度去运行优先级别最高的就绪任务,而并不一定要接着运行被中断的任务。

​ UCOS-II系统允许中断嵌套,即高优先级别的中断源的中断请求可以中断低优先级别的中断服务程序的运行。为了记录中断嵌套的层数,UCOS-II定义了一个全局变量OSIntNesting。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJOIlmwK-1631626214981)(https://i.loli.net/2021/08/04/bHtewxyfhqs6EWN.png)]

​ 编写UCOS-II的中断服务程序时,要用到两个重要的函数:OSIntEnter()OSIntExit()

函数OSIntEnter()的作用就是把全局变量OS_IntNesting加1,从而用它来记录中断嵌套的层数。

函数OSIntEnter()的调用通常发生在中断服务程序保护了被中断任务的断点数据之后运行用户中断服务代码之前,所以称之为进入中断服务函数。

另一个在中断服务程序中要调用的函数叫做退出中断服务函数OSIntExit()。调用该函数中断嵌套层数计数器减1.

函数OSIntExit()的流程图为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogsioMAL-1631626214983)(https://i.loli.net/2021/08/04/hks7AJVtR2jquZE.png)]

​ 从图中可以看出,函数在中断嵌套层数计数器为0、调度器未被锁定且从任务就绪表中查找到的最高级的就绪任务不是被中断的任务的条件下将要进行任务切换,否则就返回被中断的服务子程序。

​ 中断服务子程序流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4sX0iFCa-1631626214984)(https://i.loli.net/2021/08/04/iqBUjX9Vr4ZDGKI.png)]

UCOS-II中,通常用一个任务来表示异步事件的处理,而在中断服务程序中通过向任务发消息的方法去激活这个任务

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

4.1.3应用程序中的临界段

在UCOS-II中,不希望被中断的代码段叫做临界段。从代码上来看,处在关中断和开中断之间的代码段就是临界段。

在UCOS-II中,不要在临界段中调用UCOS-II提供的功能函数,以免系统崩溃。

OS_ENTER_CRITICAL():封装了相关关中断指令的宏

OS_EXIT_CRITICAL():封装了相关开中断指令的宏

4.2 时钟

​ 任何操作系统都要提供一个周期性的信号源,以供系统处理诸如延时、超时等与时间有关的事件,这个周期性的信号源叫做时钟。

​ UCOS-II用硬件定时器产生一个周期为毫秒(ms)级的周期性中断来实现系统时钟。最小的时钟单位就是两次中断之间相隔的时间,这个最小时钟单位叫做时钟拍(Time Tick)。

​ 硬件定时器以时钟节拍为周期定时地产生中断,该中断的中断服务程序叫做OSTickISR(),中断服务程序通过调用函数OSTimeTick()来完成系统系统在每个时钟节拍时需要做的工作。

​ UCOS-II每次响应定时中断时调用OSTimeTick()做了两件事情:一是给计数器OSTime加1;二是遍历任务控制块链表中的所有任务控制块,把各个任务控制块中用来存放任务延时时限的OSTCBDly变量减1,并使该项为0,同时又不使被挂起的任务进入就绪状态。

​ 简单地说,函数OSTimeTick()的任务就是在每个时钟节拍了解任务的延时状态,了解每个任务的延时状态,使其中一家到了延时时间的非挂起任务进入就绪状态。

4.3 时间管理

4.3.1任务的延时

​ 因为嵌入式系统的任务是一个无限循环,并且UCOS-II是一个抢占式内核。UCOS-II规定,出空闲任务之外的所有任务必须在合适的位置调用系统提供的函数OSTimeDly(),使当前任务的运行延时(暂停)一段时间并进行一次任务调度,让出CPU的使用权。

OSTimeDly(INT16U ticks)中的函数参数ticks是以时钟节拍数为单位的延时时间

OSTimeDlyHMSM()shi 是UCOS-II提供的另一个可以用时、分、秒、毫秒为参数的任务的延时函数。该函数与函数OSTimeDly()一样也要引发一次调度。

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

4.3.2 取消任务的延时

延时的任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态。如果任务比正在运行的任务优先级别高,则立即引发一次任务调度。

OSTimeDlyResume(INT8U prio)中的prio为被取消延时任务的优先级别。、

4.3.2 获取和设置系统时间

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

​ 在应用程序中调用函数OSTimeGet()可获取OSTime的值。

​ 在应用程序中调用函数OSTimeSet(),可设置OSTime的值。函数 OSTimeSet( INT32U ticks)中的参数ticks为OSTime的设定值(节拍数)。

+++

+++

+++

OS_TICKS_PER_SEC :一秒有多少个系统TICK(时钟节拍)

如(#define OS_TICKS_PER_SEC 100)则一秒有100个TICK

reload:系统频率的8分频 (MHz)

1MHz=1000 000Hz

Hz:每秒钟变化几次 例如2Hz则是每秒变化2次

(reload*1000 000)/OS_TICKS_PER_SEC:每个时间节拍需要变化多少次

OSTaskCreate();

第一个参数一个指针,也就是用户代码的首地址

第二个参数是指向数据初始化的指针

第三个参数是指向任务堆栈栈顶的指针

第四个参数是任务的优先级

void OSSemPend ( OS_EVNNT *pevent, INT16U timeout, int8u *err );

pevent 是指向信号量的指针。该指针的值在建立该信号量时可以得到。

err 是指向包含错误码的变量的指针,返回的错误码可能为下述几种:

​ * OS_NO_ERR :信号量不为零。
​ * OS_TIMEOUT :信号量没有在指定数目的时钟周期内被设置。
​ * OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断调用该函数,但μC/OS-Ⅱ仍然包含了检测这种情况的功能。
​ * OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针。

INT8U OSTaskResume (INT8U prio)

任务控制块:用来记录任务的堆栈、任务的当前状态、任务的优先级、等一些与任务管理有关属性的表叫做任务控制快

五、进程通信

5.1 任务的同步和事件

5.1.1 任务间的同步

为了防止任务之间起冲突,各个任务之间必须建立一些制约关系

制约关系有:直接制约关系、间接制约关系

直接制约关系源于任务之间的合作

间接制约关系源于对资源的共享

任务之间的制约性的合作运行机制叫做任务间的同步

5.1.2 事件

​ UCOS-II使用信号量、邮箱(消息邮箱)和消息队列这些中间环节来实现任务之间的通信,这些中间环节被统一称作“事件”。

5.1.2.1 信号量

每当有任务申请信号量时,如果信号量计数器OSEventCnt的值大于0,则把OSEventCnt减1并使任务继续进行;如果OSEventCnt的值为0,则会将任务列入任务等待列表,使任务处于等待状态。如果有正在使用信号量的任务释放了该信号量,则会在任务等待表中找出优先级别最高的等待任务,并在使它就绪后调用调度器引发一次调度;如果任务等待表中已经没有等待任务,则信号量计数器就只是简单的加1。

信号量的操作

/*定义信号量*/
OS_EVENT *sem;

int main(void)
{
	......
	sem=OSSemCreate(0); //创建一个信号量
}
//任务1
void taks1(void *pdata)
{
	while(1)
	{
		......
		OSSemPost(sem);       //发送信号量	
	}
}
//任务2
void taks2(void *pdata)
{
	while(1)
	{
		OSSemPend(sem,0,&err);       //请求信号量
	}
}

创建:OSSemCreate(cnt):cnt为信号量计数器初值

请求:OSSempend(pevent,timeout,err):pevent为信号量的指针,timeout为等待时限,err为错误信息

发送:OSSemPost(pevent)

5.1.2.2 互斥型信号量

​ 互斥型信号量是一个二值信号,他可以使任务以独占方式使用共享资源。

​ 两个任务在使用互斥信号量进行通信,可使这两个信号量无冲突的访问一个共享资源,当任务1发现信号量标志位为1时,它一方面把信号量的标志值由“1”改为“0”,另一方面进行共享资源的访问。如果任务2在任务一已经获得信号之后来请求信号量,由于任务2获得的标志值为0,所以任务2只能等待二不能访问共享资源。直到任务1使用完共享资源后,由任务1向信号量发信号使信号量标志的值由“0”再变为“1”时,任务2才能访问共享资源。

​ 在使用互斥信号量时,在访问完共享资源后,一定要把信号量标志的值由“1”变为“0”。

任务优先级的反转现象:在可剥夺型内核中,当任务以独占方式使用共享资源时,会出现低优先级任务先于高优先级任务而被运行的现象,这就是所谓的任务优先级反转。

一般来说,在实时操作系统中不允许出现这种现象,因为它破坏了任务执行的预期顺序,可能会导致严重的后果,因此应该杜绝任务优先级反转现象的发生。

任务优先级的反转的原因:之所以出现任务优先级反转现象,是因为一个优先级别较低的任务在获得了信号量使用共享资源期间,被具有较高优先级别的任务所打断而不能示范信号量,从而使正在等待这一信号量的更高级别的任务因得不到信号量而被迫处于等待状态,在这个等待期间,就让优先级别低于它而高于占据 信号量的任务先运行了

**任务优先级的反转的解决办法之一:**是获得信号量任务的优先级别在使用共享资源期间展示提升到所有任务最高优先级别的一个级别上,从而使该任务不被其他任务所打断,从而尽快的使用完共享资源并释放信号量,然后再释放信号量之后,再恢复该任务原来的优先级别。

互斥信号量的操作

OS_EVENT *UartSend; //定义一个互斥型信号量
int main(void)
{
	......
	UartSend = OSMutexCreate(0, &err);//创建互斥信号量
}
//任务1
void taks1(void *pdata)
{
	while(1)
	{
		......
		OSMutexPend(UartSend, 0, &err);       //请求互斥信号量
		......
		OSMutexPost(UartSend);             //释放互斥信号量
	}
}
//任务2
void taks2(void *pdata)
{
	while(1)
	{
		......
		OSMutexPend(UartSend, 0, &err);       //请求互斥信号量
		......
		OSMutexPost(UartSend);             //释放互斥信号量
	}
}

创建:OSMutexCreate( 优先级别,错误信息)

请求:OSMutexPend(互斥型信号量指针,等待时限,错误信息)

释放:OSMutexPost(互斥型信号量指针)

获取互斥信号量当前状态:OSMutexQuery(互斥型信号量指针,存放互斥型信号量状态的结构)

删除:OSMutexDel(互斥型信号量指针,删除方式选项,错误信息)

5.1.2.3 消息邮箱

多任务操作系统中,任务与任务之间可以通过一个数据的方式来进行传递,这种数据叫做“消息“。可以在内存中创建一个存储空间作为该数据的缓冲区,该缓冲区叫做消息缓冲区,在任务间传递数据(消息)的一个最简单的方法就是传递消息缓冲区的指针。

用来传递消息缓冲区指针的数据结构叫做消息邮箱

消息邮箱的操作

OS_EVENT *Str_Box; //定义一个邮箱

int main(void)
{
	......
	Str_Box = OSMboxCreate ((void*)0);//创建消息邮箱
}

//任务1
void taks1(void *pdata)
{
	U8 num=0while(1)
	{
		......
		OSMboxPost(Str_Box,&EXTI_num);    //发送一个消息到邮箱中
	}
}
//任务2
void taks2(void *pdata)
{
	INT8U err;       //错误信息
	u8 *result;      //存放接收到的消息邮箱指针
	u8 result_num;    //存放接收到的消息邮箱的数据
	result = OSMboxPend(Str_Box,0,&err);//请求消息邮箱
	while(1)
	{
		result_num = *result;
		......
	}
}

创建OSMboxCreate(msg) :msg为消息的指针,函数的返回值为消息邮箱的指针;

发送OSMboxPost(pevent, msg):pevent为消息邮箱指针,msg为消息指针;

以广播形式发送:OSMboxPostOpt(pevent, msg,opt):opt为广播选项,该值为OS_POST_OPT_BROADCAST时向所有等待任务广播;若为OS_POST_OPT_NONE,则只把消息向任务级别最高的等待任务发送。

阻塞请求OSMboxPend(pevent,timeout,*err):timeout为等待时限

*err为错误信息。作用是查看邮箱指针OSEventPtr是否为NULL,若不是NULL则把邮箱中的消息指针返回给调用函数的任务,当参数err为OS_NO_ERR时,表示任务获取消息成功;若邮箱指针OSEventPtr,则任务进入等待状态,并引发一次任务调度

非阻塞请求OSMboxAccept(pevent):该函数与OSMboxPend()的区别在于,调用函数时候,若请求失败,则不等待而继续运行。如果邮箱中有消息,就把邮箱清空,而邮箱中原来指向消息的指针被返回给OSMboxAccept()的调用函数。

查询状态:OSMboxQuery(pevent,*pdata):pdata为存放邮箱信息的结构

删除:OSMboxDel(*pevent, opt, *err):opt为删除选项

5.1.2.4 消息队列

​ 消息队列可在任务之间传递多条消息,消息队列由三部分组成:事件控制块、消息队列和消息

​ 消息队列相当于一个共用一个任务等待列表的消息邮箱数据,也可以理解成是一个消息的阵列

消息队列的操作

/*定义一个队列*/
OS_EVENT  *str_Q;
#define Messages_Size  128
void  *MsgGrp[Messages_Size];     //定义消息指针数

void main(void)
{
	......
    str_Q = OSQCreate(&MsgGrp[0],Messages_Size);//创建消息队列
}
//任务1
void taks1(void *pdata)
{
	u8 *result;
	while(1)
	{
		OSQPost (str_Q, &result_num);  //向消息队列中发送消息
	}
}

//任务2
void taks2(void *pdata)
{
    uint8_t err;
	u8 Num=0;
    u8 *ss;       //存放接收到的消息队列指针
	while(1)
	{
		 ss = OSQPend(str_Q,0,&err);      //从消息队列中取消息
        Num = *ss;
	}
}

创建:OSQCreate(start,size):start为指针数组地址,size为数组长度

请求:OSQPend(pevent,timeout,err)

发送:OSQPost(pevent,msg)

广播发送:OSQPostOpt(pevent,msg,opt)

清空:OSQFlush(pevent)

删除:OSQDel(pevent)

查询:OSQQuery(pevent,pdata)

六、内存管理

UCOS-II改进了ANSI C用来分配和释放内存的函数malloc()和free(),使他们可以对大小固定的内存进行操作,从而使函数malloc()和free()的执行时间成为可确定的。

6.1 内存控制块

​ 为了便于内存的管理,在µC/OS-II中使用内存控制块(memory control blocks)的数据结构来跟踪每一个内存分区,系统中的每个内存分区都有它自己的内存控制块。

内存块:UCOS-II以内存为单位向应用程序提供动态内存。内存块的大小可由用户指定

内存分区:大小相等的内存块可以组成一个内存分区。内存分区是系统对内存进行管理的基本单位

OS_MEM *CommTxBuffer; //定义内存分区指针

INT8U CommTxPart[50][64]; //定义分区和内存块

创建动态内存分区:OS_MEM *OSMemCreate(void *addr,INIT32U nblks,INIT32U blksize,INIT8U *err)

addr为内存分区的起始地址;nblks为分区中内存块的数目;blksize为每个内存块的字节数;err为错误信息

程序清单 L7.1 内存控制块的数据结构
typedef struct {
void *OSMemAddr;
void *OSMemFreeList;
INT32U OSMemBlkSize;
INT32U OSMemNBlks;
INT32U OSMemNFree;
} OS_MEM;

OSMemAddr是指向内存分区起始地址的指针。它在建立内存分区[见7.1节,建立一个内存分区,OSMemCreate()]时被初始化,在此之后就不能更改了。

OSMemFreeList是指向下一个空闲内存控制块或者下一个空闲的内存块的指针,具体含义要根据该内存分区是否已经建立来决定[见7.1节]。

OSMemBlkSize是内存分区中内存块的大小,是用户建立该内存分区时指定的[见7.1节]。

OSMemNBlks是内存分区中总的内存块数量,也是用户建立该内存分区时指定的[见7.1节]。

OSMemNFree是内存分区中当前可以得空闲内存块数量。

如果要在µC/OS-II中使用内存管理,需要在OS_CFG.H文件中将开关量OS_MEM_EN设置为1。这样µC/OS-II 在启动时就会对内存管理器进行初始化[由OSInit()调用OSMemInit()实现]。该初始化主要建立一个图 F7.3所示的内存控制块链表,其中的常数OS_MAX_MEM_PART(见文件OS_CFG.H)定义了最大的内存分区数,该常数值至少应为2。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UCOS-II的基本概念 的相关文章

  • 大数据时代的图表可视化利器——highcharts,D3和百度的echarts

    还记得阿里巴巴那个令人澎湃激情的双十一吗 xff1f 还记得淘宝生动形象地把你的的消费历程一一地展示给你看吗 xff1f 还记得那些酷炫拽的it报告图表吗 xff1f 在这个大数据越来越盛行的年代 xff0c 怎样去表达一些用户的关系 xf
  • 对三层和MVC的认识过程

    三层架构就是 MVC xff01 起初老师总说三层 MVC xff0c MVC 三层架构 所以开始的时候脑子就一个概念 xff1a 三层就是 MVC xff0c MVC 就是三层架构 而且想想也合理啊 xff0c 都是 三 MVC 是三个字
  • ROS雷达包出现:ERROR: cannot launch node of type: rplidar_ros

    ROS雷达包出现 xff1a ERROR cannot launch node of type rplidar ros 问题分析详情 问题分析 仅安装了基础ROS xff0c rplidar ros包没有安装 详情 下载包并解压缩 1 使用
  • nvidia-smi出现的比较慢

    一个比较老的问题 xff0c 一般四卡以上的机器可能会出现 以前我都是 nvidia span class hljs attribute smi span span class hljs attribute pm span span cla
  • 【tensorflow】tensorflow的安装及应用

    安装tensorflow的三种方法 1 在cmd命令行中输入pip install tensorflow xff0c 默认安装最新版 2 其他旧版本的安装 xff0c 去pypi org官网 可以点击release history选择想要的
  • 汇编:stmdb和ldmia指令

    参考了网上一些文章 xff0c 简单说一下stmdb和ldmia指令的作用 xff0c 如有错误欢迎指正 首先一句话说一下stmdb和ldmia指令 的作用 xff1a stmdb和ldmia指令一般配对使用 xff0c stmdb用于将寄
  • ARM 内联汇编 加速 算法

    首推移动端arm cpu优化学习笔记第4弹 内联汇编入门 xff0c 但是其只给出了代码 xff0c 很多人还不知道怎么在手机上跑起来 xff0c 其实只需要一个CMakeLists txt就可以了 cmake minimum requir
  • centos7.3环境编译安装pktgen-dpdk,dpdk工具

    概述编译环境编译DPDK编译Pktgen dpdkDebug 概述 DPDK xff08 Date Plane Development Kit xff09 主要基于Linux系统运行 xff0c 用于快速数据包处理的函数库与驱动集合 xff
  • 捷联惯导算法心得

    1 四个概念 xff1a 地理 坐标系 机体 坐标系 他们之间换算公式 换算公式用的系数 地理坐标系 xff1a 东 北 天 xff0c 以下简称 地理 在这个坐标系里有重力永远是 xff08 0 0 1g xff09 xff0c 地磁永远
  • Java中的域,静态域,实例域

    域 所谓的域 xff0c 是field的翻译 xff0c 也就是我们常说的字段 xff0c 或者属性 比如类的字段 xff08 属性 xff09 xff0c 局部的 xff0c 全局的 静态域 也就是静态属性 xff0c 我们可以单独为它设
  • 【线程篇】线程间同步之信号量、互斥锁

    线程 xff1a 进程内部的一条执行路径 xff08 序列 xff09 什么是线程什么是进程 xff0c 进程和线程的区别 xff1f 进程是一个正在运行的程序 xff0c 是系统进程资源分配的基本单位 线程是进程内部的一条执行路径 xff
  • PL/SQL报错:无法解析指定的连接标识符

    在安装oracle的时候PL SQL报错 xff1a ORA 12154 TNS 无法解析指定的连接标识符 xff0c 在网上找了很多资料 xff0c 然后问题解决 其中下面的文章分析的过程很值得学习 xff0c 特地转载过来时刻告诫自己全
  • 【idm】idm突破cookie封锁 (解决http:1.1 403 forbidden)(附charles使用教程)

    文章目录 一 问题二 解决方法 xff08 1 xff09 在chrome中获得cookies xff08 2 xff09 安装配置charles 三 另外的方法参考 idm的使用教程参考 xff1a 一 问题 使用idm下载文件出现如下问
  • 四旋翼飞行器数学建模+轨迹跟踪控制

    数学模型 xff08 状态空间方程 xff09 xff1a 控制算法 有限时间 xff08 finite time control xff09 控制 xff0c 文献 1 xff1b 比例 微分 xff08 PD xff09 控制 xff0
  • 卡尔曼滤波算法总结

    自己学习整理卡尔曼滤波算法 xff0c 从放弃到精通 kaerman 滤波算法 卡尔曼滤波是非常经典的预测追踪算法 xff0c 是结合线性系统动态方程的维纳滤波 xff0c 其实质是线性最小均方差估计器 xff0c 能够在系统存在噪声和干扰
  • 做嵌入式驱动的前途何在

    做嵌入式驱动的前途何在 做嵌入式linux驱动的前途何在 xff1f 或者说 xff0c 怎么才能做好这一行 xff1f 我做嵌入式驱动开发已经一年多了 xff0c 感觉没学到多少东西 从网络驱动到CAN驱动 从dataflash驱动到NA
  • 串口通信的调试01

    在开发中 xff0c 我们经常遇到这种情况 xff0c 供应商给了一台仪器 xff0c 然后仪器配套有软件 我们通过点击按钮往仪器发送命令 xff0c 仪器返回数据 有些时候 xff0c 我们希望可以通过自己编写的软件来操作仪器 xff0c
  • Linux驱动程序开发之三----按键驱动(Tiny6410)

    在Linux驱动程序开发之三 按键驱动 xff08 Tiny6410 xff09 博文中讨论了使用中断来实现按键驱动 xff0c 毫无疑问 xff0c 中断方式效率相当高 xff0c 但是在此之前 xff0c CPU要想获知按键的状态都是通
  • 飞控信号SBUS信号解析为PWM信号输出

    飞控信号SBUS信号解析为PWM信号输出 1 修改STM32时钟频率 xff1a static void SetSysClockTo72 void IO uint32 t StartUpCounter 61 0 HSEStatus 61 0
  • GTSAM 的使用

    GTSAM 的使用 GTSAM 是一个在机器人领域和计算机视觉领域用于平滑 xff08 smoothing xff09 和建图 xff08 mapping xff09 的C 43 43 库 它与 g 2 o 不同的是 xff0c g 2 o

随机推荐

  • ROS智能车实现darknet_ros检测物体

    文章目录 一 搭建智能车环境1 下载包以及编译1 1 下载源码包1 2 编译1 3 错误解决 xff08 1 xff09 controllers相关 xff08 2 xff09 driver base相关 xff08 3 xff09 ack
  • 使用Vant完成DatetimePicker 日期的选择器

    效果展示 xff1a 代码展示 xff1a lt template gt lt div id 61 34 date time picker 34 gt lt van button plain type 61 34 primary 34 64
  • 拜访谭浩强老先生

    本月 22日 邀请各大高校计算机专业的院长 教授 xff08 谭浩强 王移芝 陈明 杨小平 王立柱 郑莉 等等 xff09 前来我校参观指导 xff0c 尤其是对我们的 信息技术提高班 进行深入的了解 得知前几天中国计算机界泰斗级人物谭浩强
  • 使用Vant完成各种Toast提示框

    效果展示 xff1a xff08 1 xff09 使用前的需要安装Vant奥 参考博客 xff08 2 xff09 在main js里面引入Toast import Toast from 39 vant 39 Vue use Toast x
  • 使用Vant完成底部弹出框 ActionSheet 上拉菜单

    效果图 xff1a 代码展示 xff1a xff08 ActionSheet 上拉菜单 xff09 lt template gt lt ActionSheet 上拉菜单 gt lt div id 61 34 action sheet 34
  • vue项目总结,项目期间遇到的问题、难点等。【暂停更新】

    近期一直在做一个xxx中心的项目 xff0c 先来吐槽下内心的想法 xff0c 要开发的项目需求很不明确 xff0c 需求两周两周的更改 xff0c 感觉每天并没有特别多实际的产出 xff0c 总是感觉有点儿浪费时间 虽然这样 xff0c
  • http请求 状态码204

    今天在调试接口的时候遇到个问题 xff1a 一个请求走了两次 xff0c 一次204 xff0c 一次200 且 xff0c 请求204的 Request Method 是 OPTIONS 在网上查看资料后得知 xff0c 是因为跨域而引起
  • vue项目中,使用echarts完成 折线+多柱状图 (附完整代码)

    结果展示 xff1a 分析 xff1a xff08 1 xff09 在echarts里面的 series里面写三种柱状 43 一种折线图 xff08 2 xff09 该图谱也实现了自适应大小 xff0c 缩小放大浏览器界面 xff0c 柱状
  • vue 前端实现pdf下载.npm install html2canvas jspdf --save

    npm install html2canvas jspdf save 页面使用 lt div id 61 39 pdfDom 39 gt lt div gt lt el button 64 click 61 34 getPdf 39 pdf
  • vue 项目实现水印效果

    目录 xff08 1 xff09 新建 waterMark js文件 xff08 2 xff09 页面使用 xff08 1 xff09 新建引入 waterMark js文件 39 use strict 39 let watermark 6
  • 角度单位deg、grad、turn、rad

    xff08 1 xff09 deg属性 xff1a 度 xff1a deg xff08 全称 xff1a degress xff09 一个圆有360度 90deg 61 100grad 61 0 25turn 1 5707963267948
  • vscode 中的git的提交、合并、解决冲突

    xff08 1 xff09 如果本地文件有修改 xff0c 那么这里就会显示有几个文件被修改 xff0c 且修改的具体内容也是对比着显示 xff1a xff08 2 xff09 点击 相当于 git add 将文件放入暂存区 xff08 3
  • 解决【display:flex布局】遇上 【position: absolute / fixed 】的失效问题

    问题描述 xff1a 有个这样的页面 xff0c 页面是通过flex布局的 xff0c 现在想将头部 我的订单栏 固定 xff0c 那么我们第一反应就是添加定位呀 xff0c position fixed 但是问题来了 xff0c posi
  • 年度回忆录(2011.07----2011.12)

    日月穿梭 xff0c 时光荏苒 xff08 其实挺不想用这两个词开头的 xff0c 太土了 无奈词穷 xff0c 凑合着看吧 D xff09 上次总结的时候正是七月份 xff0c 半年过去了 xff0c 经历了很多 xff0c 学到了很多
  • 从零开始的树莓派生活(树莓派4B的组装与系统安装)

    一 组装 从X宝等平台购买的树莓派除了主板外一般带有散热片 电源 风扇 外壳等配件 xff0c 不同店家不同型号的套装稍有不同 xff0c 以我自己购买的树莓派4B为例 xff0c 组装步骤大致分为 xff1a 1 安装散热片 2 安装亚克
  • 五大适合STM32的嵌入式操作系统

    基于STM平台且满足实时控制要求操作系统 xff0c 有以下5种可供移植选择 分别为 Clinux C xff0f OS II eCos FreeRTOS和都江堰操作系统 djyos 下面分别介绍这五种嵌入式操作系统的特点及不足 1 Cli
  • [docker] Get https://registry-1.docker.io/v2/ 错误的解决方案

    出现此问题一般是因为镜像源在国外 网络问题导致 今天安装laradock的时候出现了 记录处理方法 把镜像源改为国内的即可 1编辑deamon文件 centOS 默认有此文件 Ubuntu下是没有的 创建即可 sudo vim etc do
  • 高通SDM845平台Sensor学习——3.SLPI(Physical Sensor)

    三 xff1a Sensor SLPI层代码分析 在学习SLPI侧代码前我们先了解下SEE的registry amp config registry 放在 persist sensors registry registry中 xff0c 它
  • PID算法原理 一简单的认识一下PID的三个参数的作用

    PID算法原理 一简单的认识一下PID的三个参数的作用 以下的内容是我通过查阅了资料和加上我对PID的理解的总结 xff0c 如果遇到有不对的地方 xff0c 还望指出 先上一张图PID控制的结构图 关于PID控制 xff0c 我相信很多小
  • UCOS-II的基本概念

    UCOS II 一 实时操作系统的概念 1 1 操作系统 操作系统是一种系统软件 xff0c 他在计算机硬件与计算机应用程序之间 xff0c 通过提供程序接口 xff0c 屏蔽了计算机硬件工作的一些细节 xff0c 从提高了应用程序的开发效