嵌入式实时系统FreeRTOS课件.pptx
《嵌入式实时系统FreeRTOS课件.pptx》由会员分享,可在线阅读,更多相关《嵌入式实时系统FreeRTOS课件.pptx(152页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、1、FreeRTOS简介 FreeRTOS是一个嵌入式系统使用的开源实时系统。FreeRTOS小巧,简单,易用。能支持许多不同硬件 架构以及交叉编译器。此系统可以免费进行商业应用,被大量公司与科研公司用于嵌入式产品的开发。支持的处理器架构:ARM7,ARM9,COLTEX-m3、AVR、PIC等。第1页/共152页1、FreeRTOS简介嵌入式系统:一个专门设计用来做一些简单事情的计算机系统,如电视遥控器,车载GPS,电子手表,或者起搏器这类。嵌入式系统比通用计算机系统更小更慢,通常也更便宜。如:低端:一个运行速度为25MHz的8位CPU,几KB的内存。高端:一个运行速度为750MHz的32位
2、 CPU,一个GB左右的内存,和几个GB的闪存。第2页/共152页1、FreeRTOS简介实时(RT)软实时:按照任务的优先级,尽可能快地完成操作即可。硬实时:硬实时要求在规定的时间内必须完成操作。第3页/共152页1、FreeRTOS简介系统基本架构其代码可以分解为三个主要区块:任务通讯硬件接口任务:大约50%的FreeRTOS的核心代码第4页/共152页1、FreeRTOS简介通讯:大约40%的FreeRTOS核心代码是用来处理通讯的。任务和中断使用队列互相发送数据,并且使用信号灯和互斥来发送临界资源的使用情况。硬件接口:大约有6%的FreeRTOS的核心代码,在硬件无关的FreeRTOS
3、内核与硬件相关的代码间扮演着垫片的角色。第5页/共152页2、任务简介2.1任务函数 任务是由C语言函数实现的。任务函数其必须返回void,而且带有一个void指针参数。其函数原型参见程序清单1。void ATaskFunction(void*pvParameters);程序清单1 任务函数原型第6页/共152页2.1任务函数注意事项:FreeRTOS 任务不允许以任何方式从实现函数中返回它们绝不能有一条”return”语句,也不能执行到函数末尾。如果一个任务不再需要,可以显式地将其删除(void vTaskDelete(xTaskHandlepxTaskToDelete);)。第7页/共15
4、2页2.1任务函数创建任务:创建任务使用FreeRTOS的API函数xTaskCreate()。程序清单2第8页/共152页2.1任务函数参数介绍:pvTaskCode 一个指向任务的实现函数的指针(效果上仅仅是函数名)。pcName 具有描述性的任务名。这个参数不会被FreeRTOS使用。其只是单纯地用于辅助调试。usStackDepth 当任务创建时,内核会分为每个任务分配属于任务自己的唯一状态。usStackDepth值用于告诉内核为它分配多大的栈空间。这个值指定的是栈空间可以保存多少个字(word),而不是多少个字节(byte)。比如说,如果是32位宽的栈空间,传入的usStackDe
5、pth值为100,则将会分配400字节的栈空间(100*4bytes)。第9页/共152页参数:pvParameters 任务函数接受一个指向void的指针(void*)。pvParameters的值即是传递到任务中的值。uxPriority 指定任务执行的优先级。优先级的取值范围可以从最低优先级0到最高优先级(configMAX_PRIORITIES 1)。configMAX_PRIORITIES 是一个由用户定义的常量。pxCreatedTask 用于传出任务的句柄。这个句柄将在API调用中对该创建出来的任务进行引用,比如改变任务优先级,或者删除任务。如果应用程序中不会用到这个任务的句柄,
6、则pxCreatedTask可以被设为NULL第10页/共152页返回值 有两个可能的返回值:1.pdTRUE 表明任务创建成功。2.errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 由于内存堆空间不足,FreeRTOS无法分配足够的空间来保存任务结构数据和任务栈,因此无法创建任务。第五章将提供更多有关内存管理方面的信息。第11页/共152页2.1任务函数例1.创建任务本例演示了创建并启动两个任务的必要步骤。两个任务内容:周期性地打印输出字符串。两者在创建时指定了相同的优先级。第12页/共152页任务一:周期性输出:Task 1 is runningrn第13页/共1
7、52页任务二:周期性输出:Task 2 is runningrn第14页/共152页main()函数:简单地创建这两个任务,然后启动调度器第15页/共152页运行结果:图一 第16页/共152页2.1任务函数任务分配分析:图2中看到两个任务在同时运行,事实上这两个任务由于优先级相同,而且在一个处理器上运行,其实是在交替运行。真实的执行流程所图3所示第17页/共152页 2.1任务函数 图二第18页/共152页2.1任务函数 上例中main()函数在启动调度器之前先完成两个任务 的创建。当然也可以从一个任务中创建另一个任务。我们可以先在main()中创建任务1,然后在任务1中创建任务2这样需要在
8、任务一中添加以下语句:xTaskCreate(vTask2,Task 2,1000,NULL,1,NULL);第19页/共152页2.1任务函数关于使用xTaskCreate()时任务函数的参数问题例1中的两个任务几乎完全相同,唯一的区别就是打印输出的字符串。这种重复性可以通过创建同一个任务代码的两个实例来去除。这时任务参数就可以用来传递各自打印输出的字符串。第20页/共152页我们仍然调用两次xTaskCreate(),但其pvParameters(第四个)参数变为了两个不同的指针,两个指针分别指向各自需要打印输出的文本。第21页/共152页2.2任务调度任务的调度方法:通过对任务设置优先级
9、进行优先级抢占式调度。每个任务都赋予了一个优先级。每个任务都可以存在于一个或多个状态。在任何时候都只有一个任务可以处于运行状态。调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行。第22页/共152页2.2任务调度优先级:xTaskCreate()API函数的参数uxPriority(即第五个参数)为创建的任务赋予了一个初始优先级。常量configMAX_PRIORITIES在(FreeRTOSConfig.h文件中)的值,即是系统最多可具有的优先级数目。0到(configMAX_PRIORITES 1)函数优先级可以调用vTaskPrioritySet()API函数进行修改。第
10、23页/共152页2.2任务调度关于优先级为零的任务介绍:当创建的任务都处于阻塞态时(很多时候都会有这种情况出现),这种状态下所有的任务都不可运行,但处理器总是需要代码来执行所以至少要有一个任务处于运行态。为了保证这一点,当调用vTaskStartScheduler()时,调度器会自动创建一个空闲任务(非常短小的循环)。空闲任务拥有最低优先级(优先级0),这样不会妨碍具有更高优先级的应用任务进入运行态。第24页/共152页2.2任务调度图中任务一(Task1)任务二(Task2)都设置有定时阻塞,任务二的优先级高于任务一的优先级,在两个任务都被阻塞的时候,空闲任务(idle)开始执行。图三第2
11、5页/共152页2.2任务调度空闲任务钩子函数:通过空闲任务钩子函数(或称回调,hook,or call-back),可以直接在空闲任务中添加应用程序相关的功能。空闲任务钩子函数会被空闲任务每循环一次就自动调用一次。空闲任务钩子函数有很多用途,如在没有任何应用功能需要处理的时候,将系统配置到省电模式。第26页/共152页2.2任务调度定义一个空闲任务钩子函数:void vApplicationIdleHook(void);FreeRTOSConfig.h中的配置常configUSE_IDLE_HOOK必须定义为1,这样空闲任务钩子函数才会被调用。第27页/共152页2.2任务调度空闲任务钩子函
12、数必须遵从以下规则:1.绝不能阻塞或挂起。空闲任务的目的就是希望在所有任务阻塞时仍能有任务运行,一旦钩子函数阻塞或挂起,将不再有任务运行。2.如果应用程序用到了vTaskDelete()函数,则空闲钩子函数必须能够尽快返回。因为在任务被删除后(vTaskDelete()),空闲任务负责回收内核资源。如果空闲任务一直运行在钩子函数中,则无法进行回收工作。第28页/共152页2.2任务调度任务优先级的改变 API函数vTaskPriofitySet()可以用于在调度器启动后改变任何任务的优先级。void vTaskPrioritySet(xTaskHandle pxTask,unsigned po
13、rtBASE_TYPE uxNewPriority);参数:pxTask 被修改优先级的任务句柄(即目标任务)uxNewPriority 目标任务将被设置到哪个优先级上。如果设置的值超过了最大可用优先级(configMAX_PRIORITIES 1),则会被自动封顶为最大值。第29页/共152页2.2任务调度根据优先级的具体调度方法:调度器保证总是在所有可运行的任务中选择具有最高优先级的任务,并使其进入运行态。如果被选中的优先级上具有不止一个任务,调度器会让这些任务轮流执行(如图二)。第30页/共152页2.2任务调度时间片的概念 图二中的两个任务优先级相同,所以每个任务都执行一个”时间片”,
14、任务在时间片起始时刻进入运行态,在时间片结束时刻又退出运行态。图2中t1与t2之间的时段就等于一个时间片。要能够选择下一个运行的任务,调度器需要在每个时间片的结束时刻运行自己本身。一个称为心跳(tick)中断的周期性中断用于此目的。时间片的长度是可以设定的。第31页/共152页2.2任务调度此图中的任务一与任务二与图2中的是一样的,此图中标出了调度器在时间片之间的调度过程。图4第32页/共152页2.2任务调度任务状态在简要介绍了优先级调度后,我们需要了解与调度相关的各种任务的状态。1、运行态.运行中的任务状态。2、阻塞状态如果一个任务正在等待某个事件,则称这个任务处于”阻塞态(blocked
15、)”。挂起状态。3、“挂起(suspended)”处于挂起状态的任务对调度器而言是不可见的。让一个任务进入挂起状态的唯一办法就是调用vTaskSuspend()API函数。4、就绪状态如果任务处于非运行状态,但既没有阻塞也没有挂起,则这个任务处于就绪(ready,准备或就绪)状态。第33页/共152页2.2任务调度完整的状态转移图 图5第34页/共152页3、队列 独立的任务之间很可能会通过相互通信以提供有用的系统功能。FreeRTOS中所有的通信与同步机制都是基于队列实现的。特性:1、数据存储2、队列可以保存有限个具有确定长度的数据单元3、可被多任务存取4、队列是具有自己独立权限的内核对象,
16、并不属于或赋予任何任务。所有任务都可以向同一队列写入和读出。第35页/共152页3、队列5、读队列时阻塞 当某个任务试图读一个队列时,其可以指定一个阻塞超时时间。在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。6、写队列时阻塞 同读队列一样,任务也可以在写队列时指定一个阻塞超时时间。这个时间是当被写队列已满时,任务进入阻塞态以等待队列空间有效的最长时间。第36页/共152页3、队列创建队列:xQueueHandle xQueueCreate(unsigned portBASE_TYPE uxQueueLength,unsigned portBASE_TYPE uxItemS
17、ize);参数:uxQueueLength 队列能够存储的最大单元数目,即队列深度。uxItemSize 队列中数据单元的长度,以字节为单位。返回值:NULL表示没有足够的堆空间分配给队列而导致创建失败。非NULL值表示队列创建成功。此返回值应当保存下来,以作为操作此队列的句柄。第37页/共152页3、队列向列中写数据xQueueSendToBack()与xQueueSendToFront()API函数portBASE_TYPE xQueueSendToFront(xQueueHandle xQueue,const void*pvItemToQueue,portTickType xTicksT
18、oWait);/将数据发送到队列尾部第38页/共152页3、队列参数说明xQueue 目标队列的句柄。这个句柄即是调用xQueueCreate()创建该队列时的返回值。pvItemToQueue 发送数据的指针。其指向将要复制到目标队列中的数据单元。xTicksToWait 阻塞超时时间。如果在发送时队列已满,这个时间即是任务处于阻塞态等待队列空间有效的最长等待时间。第39页/共152页3、队列返回值 有两个可能的返回值:1.pdPASS 数据被成功发送到队列中。2.errQUEUE_FULL 如果由于队列已满而无法将数据写入,则将返回。第40页/共152页3、队列ortBASE _TYPE
19、xQueueSendToBack(xQueueHandle xQueue,const void*pvItemToQueue,portTickType xTicksToWait);/将数据发送到队列首部其参数和返回值与前者相似,这里不再介绍。第41页/共152页3、队列xQueueReceive()与xQueuePeek()API函数xQueueReceive()用于从队列中接收(读取)数据单元。接收到的单元同时会从队列中删除。xQueuePeek()也是从从队列中接收数据单元,不同的是并不从队列中删出接收到的单元。第42页/共152页3、队列portBASE_TYPE xQueueReceiv
20、e(xQueueHandle xQueue,const void*pvBuffer,portTickType xTicksToWait);参数:第43页/共152页xQueue 被读队列的句柄。这个句柄即是调用xQueueCreate()创建该队列时的返回值。pvBuffer 接收缓存指针。其指向一段内存区域,用于接收从队列中拷贝来的数据。xTicksToWait 阻塞超时时间。如果在接收时队列为空,则这个时间是任务处于阻塞状态以等待队列数据有效的最长等待时间。把它设为0,并且队列为空,则xQueueRecieve()与xQueuePeek()均会立即返回。如果把xTicksToWait 设置
21、为portMAX_DELAY,并且在FreeRTOSConig.h中设定INCLUDE_vTaskSuspend 为1,那么阻塞等待将没有超时限制。第44页/共152页3、队列返回值有两个可能的返回值:1.pdPASS 只有一种情况会返回pdPASS,那就是成功地从队列中读到数据。2.errQUEUE_FULL 如果在读取时由于队列已空而没有读到任何数据,则将返回errQUEUE_FULL。如果设定了阻塞超时时间(xTicksToWait非0),在函数返回之前任务将被转移到阻塞态以等待队列数据有效。但直到超时也没有其它任务或是中断服务例程往队列中写入数据,函数则会返回errQUEUE_FULL
22、。xQueuePeek()的参数与返回值与xQueueReceive()类似,这里不再重复。第45页/共152页3、队列uxQueueMessagesWaiting()用于查询队列中当前有效数据单元个数函数原型:unsigned portBASE_TYPE uxQueueMessagesWaiting(xQueueHandle xQueue);参数 xQueue 被查询队列的句柄。这个句柄即是调用xQueueCreate()创建该队列时的返回值。返回值 当前队列中保存的数据单元个数。返回0表明队列为空。第46页/共152页3、队列 以上五个函数均不能在中断服务中使用,系统会提供以上函数专门的中
23、断版本(后面将会讲到)。第47页/共152页3、队列队列使用例程例2:本例示范创建一个队列,由多个任务往队列中写数据,以及从队列中把数据读出。其中往队列中写数据的任务没有设定阻塞超时时间,而读队列的任务设定了超时时间。第48页/共152页3、队列写队列任务函数。主函数将调用此函数分别写入100、200.第49页/共152页3、队列写队列任务在每次循环中都调用taskYIELD()。taskYIELD()通知调度器立即进行任务切换,而不必等到当前任务的时间片耗尽。第50页/共152页3、队列读队列任务函数,函数中设置了延迟时间。第51页/共152页3、队列第52页/共152页3、队列main函数
24、:其在启动调度器之前创建了一个队列和三个任务。尽管对任务的优先级的设计使得队列实际上在任何时候都不可能多于一个数据单元,本例代码还是创建了一个可以保存最多5个long 型值的队列。第53页/共152页3、队列第54页/共152页3、队列 写队列任务在每次循环中都调用taskYIELD()。taskYIELD()通知调度器立即进行任务切换,而不必等到当前任务的时间片耗尽。本例中两个写队列任务(写入100和200)是具有相同的任务优先级(均为1),所以一旦其中一个任务调用了taskYIELD(),另一个任务将会得到执行。反映到输出上就是两个人物交替输出。图6第55页/共152页3、队列调用过程如下
25、 图7 第56页/共152页3、队列使用队列传递复合数据类型 第57页/共152页3、队列对大型数据单元的传递 第58页/共152页4、中断 4.1延迟中断处理 当中断发生时,程序将进入中断服务程序中行,如果中断服务程序运行时间很长,甚至包括迟将大大降低系统的实时性。这时,我们可以将中断服务程序作为触发者,触发其他函数来执行需要执行的任务。这样中断服务程序可以很简短,大大增强了实时性。而真正需要做的事情则放在被触发的函数中执行。我们可以使用二值信号量完成中断服务程序与被触发函数的这种触发关系。第59页/共152页4.1延迟中断处理延迟中断处理如下图所示:图8第60页/共152页4.1延迟中断处
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 实时 系统 FreeRTOS 课件
限制150内