南昌大学FreeRTOS实验5-8知识点
干货FreeRTOS学习笔记——实验:串口后台打印

干货FreeRTOS学习笔记——实验:串口后台打印EEWorld电子资讯犀利解读技术干货每日更新现在来探讨一下如何利用FreeRTOS 的服务来为单片机程序设计提供方便,也感受下引入FreeRTOS 后系统处理效率的变化。
我想了个简单的常用需求:串口的“后台”打印输出(单片机开发时常用于调试信息输出),来进行实验。
串口(异步串行通讯口的简称, UART)相对于 CPU 是一个低速的设备,一般较高通信速率为115200bit/s,在此速率下输出一个8-bit 字符(假设用1个起始位,1个停止位,无校验)用的时间为87us. CPU 将字符写入串口的发送数据寄存器需要的时间可以忽略,但是由于串口硬件FIFO很小,务必要等待发送数据寄存器允许写入时才可以进行写操作。
于是,简单的程序设计中就不断查询标志位,等待寄存器可以写了就写一个字符,直到要发送的字符串写完。
要照顾执行效率的时候一定不能这么做,特别是在多任务环境下,因为这种循环重复查询标志位的做法让其它任务也只能等待,没有利用CPU处理能力。
于是我们需要一种“后台”输出的方法,让当前任务将要从串口输出的字符串提交到系统之后,程序往下执行,不用等待字符串从串口发送完;或者是当前任务等待字符串发送完,但是其它任务可以执行。
以下我的实验代码在ST Nucleo-L4R5ZI 板子上运行,也很容易改动一下以在其它 STM32 上运行(不过 STM32L4R5 的SRAM大,方便挥霍)。
在这块开发板上,USB串口连接到了STM32L4R5 的LPUART1, 我就编写一个 uart_puts(char *) 函数来从 LPUART1 输出字符串。
LPUART1 的TDR 寄存器时候用来写要发送的数据的,发送完成等状态可以从ISR 寄存器获取。
当然为了实现后台工作,中断是需要用到的了。
1简单直接的办法——字符队列不能反复查询,那么就让 LPUART1 的 TDR 寄存器可以写的时候,产生一个中断来告诉CPU,该写字符了。
STM32-FreeRTOS快速学习之总结1

STM32-FreeRTOS快速学习之总结11. 基础知识注意:在RTOS中是优先值越⾼则优先级越⾼(和ucos/linux的相反)在移植的时候,主要裁剪FreeRTOS/Source/portable⽂件夹,该⽂件夹⽤来针对不同MCU做的⼀些处理,如下图所⽰,我们只需要使⽤:1.1配置⼯程时,选择memMang时,⼀般使⽤heap_4.cheap_4: 优点在于可以有效的利⽤内存碎⽚来合并为⼀个⼤内存.缺点在于只能⽤来⼀个ram⾥.heap_5: ⼀般针对有外部RAM才⽤到,优点在于可以同时利⽤内部ram和外部ram来进⾏内存碎⽚合并.最终添加的库⽂件有:然后我们在分配释放内存的时候,就尽量使⽤RTOS带的函数来实现,分配/释放函数如下所⽰:void *pvPortMalloc( size_t xWantedSize );void vPortFree( void *pv );1.2 添加头⽂件路径添加FreeRTOS\include添加FreeRTOS\portable\RVDS\ARM_CM3并将原⼦中的FreeRTOSConfig.h也复制到我们项⽬的FreeRTOS\include中(⽤来配置RTOS系统)2. FreeRTOSConfig.h配置介绍⼀般会写configXXXXX或者INCLUDE_XXXX类似的宏,这两个宏区别在于:configXXXXX⽤来实现不同功能,⽐如定义configUSE_COUNTING_SEMAPHORES为1时,表⽰使⽤计数信号量INCLUDE_XXXX⽤来是否将某个API函数编译进程序中.⽐如定义INCLUDE_xTaskGetSchedulerState为1 时,则将会编译xTaskGetSchedulerState()函数,如下图所⽰:3. FreeRTOS任务状态3.1 运⾏态指当前任务正在运⾏.3.2 就绪态指当前任务正在等待调度,因为有个⾼优先级/同优先级的任务正在运⾏中3.3 阻塞态当前任务处于等待外部事件通知或通过vTaskDelay()函数进⼊休眠了,外部事件通知常见有信号量、等待队列、事件标志组、任务通知.3.4 挂起态类似于暂停,表⽰不会再参与任务调度了,通过vTaskSuspend()实现,重新恢复调度则使⽤xTaskResume()4. FreeRTOS中断配置4.1 回忆stm32 NVIC中断Stm32可以设置NVIC中断组数为0~4,其中0~4区别在于如下图所⽰:、⽐如我们设置为NVIC_PriorityGroup_4时:表⽰抢占优先级为4bit(即为2^4,为0~15个抢占优先级),副优先级为0bit(表⽰没有).4.2 抢占优先级和副优先级的区别:1. 抢占优先级和副优先级的值越低,则优先级越⾼2.⾼的抢占优先级的中断可以直接打断低的抢占优先级的中断3.⾼的副优先级的中断不可以打断低的副优先级的中断(只是两个相同抢占优先级的中断同时来的时候,只会优先选择⾼的副优先级)4.3 FreeRTOS中断配置宏configKERNEL_INTERRUPT_PRIORITY⽤来配置中断最低抢占优先级,也就是可以FreeRTOS可以管理的最⼩抢占优先级,所以使⽤FreeRTOS时,我们尽量设置stm32为NVIC_PriorityGroup_4,这样就可以管理16个优先级了.configMAX_SYSCALL_INTERRUPT_PRIORITY⽤来配置FreeRTOS能够安全管理的的最⾼优先级.⽐如原⼦的FreeRTOSConfig.h⾥就设置为5,⽽0~4的优先级中断就不会被FreeRTOS因为开关中断⽽禁⽌掉(⼀直都会有),并且不能调⽤RTOS中的”FromISR”结尾的API函数.⽐如喂看门狗中断函数就需要设置为0~4如下图所⽰(来⾃原⼦⼿册):4.3 FreeRTOS中断开关函数portENABLE_INTERRUPTS();//开中断,将configMAX_SYSCALL_INTERRUPT_PRIORITY⾄ configKERNEL_INTERRUPT_PRIORITY之间的优先级中断打开portDISABLE_INTERRUPTS();//关中断,将configMAX_SYSCALL_INTERRUPT_PRIORITY⾄ configKERNEL_INTERRUPT_PRIORITY之间的优先级中断禁⽌掉5.任务常⽤API函数5.1 xTaskCreate创建任务函数定义如下:xTaskCreate( TaskFunction_t pxTaskCode, //任务函数,⽤来供给函数指针调⽤的const char * const pcName, //任务的字符串别名const uint16_t usStackDepth, //任务堆栈深度,实际申请到的堆栈是该参数的4倍void * const pvParameters, //函数参数,⽤来供给指针调⽤的UBaseType_t uxPriority, //优先级,越⾼优先级⾼,范围为0~configMAX_PRIORITIES-1 //注意优先级0会创建为空闲任务, 优先级configMAX_PRIORITIES-1会创建⼀个软件定时器服务任务(管理定时器的) TaskHandle_t * const pxCreatedTask ); //任务句柄,该句柄可以⽤于挂起/恢复/删除对应的任务//返回值 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(-1):表⽰创建任务堆空间不⾜pdPASS(1):创建成功5.2 taskENTER_CRITICAL()和taskEXIT_CRITICAL()⽤于任务中进⼊/退出临界区,调⽤taskENTER_CRITICAL()主要会关闭其他任务调度.⽽taskEXIT_CRITICAL()则会恢复任务调度,⼀般⽤于初始化外设等.5.3 taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()⽤于在中断函数中进⼊/退出临界区,作⽤和上⾯⼀样5.4 挂起/恢复/删除任务函数void vTaskSuspend( TaskHandle_t xTaskToSuspend ); //挂起⼀个任务,参数为挂起任务的句柄,如果为NULL则表⽰挂起⾃⾝任务void vTaskResume( TaskHandle_t xTaskToResume ); //恢复⼀个任务BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume);//从中断函数中恢复⼀个任务,返回1表⽰恢复成功void vTaskDelete( TaskHandle_t xTaskToDelete ); //删除⼀个任务,如果从任务函数中退出的话,则需要调⽤vTaskDelete(NULL)来删除⾃⾝任务5.5 vTaskDelay()延时函数void vTaskDelay( const TickType_t xTicksToDelay ); //参数表⽰延时的系统滴答数⽐如延时500ms可以写为: vTaskDelay( 500/portTICK_RATE_MS );portTICK_RATE_MS是个宏,表⽰当前系统的1个滴答需要多少ms,⽽500/portTICK_RATE_MS则表⽰当前500ms需要多少个系统滴答数.6. 队列6.1简介队列⽤于任务与任务或者任务与中断之间的通信.⽐如key任务检测到按键按下时,则可以通过队列向lcd显⽰任务发送信息,使得lcd切换界⾯.队列采⽤先进先出存储机制.队列发送数据可以有两种⽅式:浅拷贝、深拷贝.数据量不⼤的情况下,都使⽤深拷贝(会分配新的空间,并进⾏数据拷贝,缺点在于耗时)数据量⼤的情况下,都使⽤浅拷贝(通过指针⽅式,前提是要发送的数据必须不会被释放的)6.2队列的优点队列可以通过任何任务或者中断进⾏访问,可以随时存取数据消息.并且出⼊队的时候可以进⾏任务阻塞,⽐如某个任务进⾏读消息出队时,如果没有消息,则可以实现进⼊休眠状态,直到有消息才唤醒任务.6.3队列创建删除相关APIQueueHandle_t xQueueCreate( uxQueueLength, uxItemSize );//动态创建队列,内存会交给RTOS⾃动分配// uxQueueLength:队列长度(表⽰队列中最⼤多少条消息),uxItemSize:每个队列消息的长度(以字节为单位)//返回值: NULL(0, 表⽰分配失败),⾮0(表⽰返回该队列分配好的地址)//注意:使⽤⾃动分配时,需要配置configSUPPORT_DYNAMIC_ALLOCATION宏为1,否则只能由⽤户来分配.QueueHandle_t xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer );//静态创建队列,内存需要由⽤户事先分配好// uxQueueLength:队列长度(表⽰队列中最⼤多少条消息),uxItemSize:每个队列消息的长度(以字节为单位)// pucQueueStorage:指向⽤户事先分配好的存储区内存(必须为uint8_t型)// pxQueueBuffer:指向队列结构体,⽤来提供给RTOS初始化.然后给⽤户使⽤//返回值: NULL(0, 表⽰分配失败),⾮0(表⽰返回该队列分配好的地址)vQueueDelete( QueueHandle_t xQueue );//删除队列,并释放空间xQueueReset( xQueue );//将队列⾥的消息清空⼀次,也就是恢复初始状态6.4队列出⼊队相关APIxQueueSend( xQueue, pvItemToQueue, xTicksToWait );//插⼊队尾,和xQueueSendToBack函数效果⼀致// xQueue:队列句柄//PvItemToQueue:消息数据,会通过数据拷贝到队列中,如果想使⽤浅拷贝,则可以发送⼀个变量来存储要真正发送的缓冲区地址即可.// xTicksToWait:阻塞时间,单位为RTOS时钟滴答值,如果configTICK_RATE_HZ是1000,则填⼊的值表⽰阻塞的是多少ms,否则的话需要通过X/portTICK_RATE_MS来转换⼀下,才能实现阻塞Xms. //xTicksToWait==0:表⽰⼊队满了,则直接退出该函数// xTicksToWait==portMAX_DELAY:表⽰⼀直阻塞,直到队列有空位为⽌.//注意: INCLUDE_vTaskSuspend宏必须为1,否则任务⽆法进⼊休眠状态实现阻塞效果.//返回值: errQUEUE_FULL(队列已满) pdPASS(通过)xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait );//插⼊队头,参数和上⾯描述⼀致xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait );//插⼊队尾,参数和上⾯描述⼀致xQueueOverwrite( xQueue, pvItemToQueue );//将之前未出队的旧数据全部清空,然后再⼊队,该函数适⽤于长度为1的队列xQueueReceive( xQueue, pvBuffer, xTicksToWait );//从队列头部读出⼀个消息,并且这个消息会出队(删除掉)xQueuePeek( xQueue, pvBuffer, xTicksToWait );//从队列头部读出⼀个消息,但是这个消息不会出队(不会删除)PS:这些API函数只能⽤于任务⾥调⽤,如果要在中断服务函数中调⽤,则在函数名后添加FromQueue即可,⽐如xQueueSendFromQueue()函数6.5 中断发送/读取消息队列时,要注意的事情使⽤中断相关的读写队列相关的API时,第3个参数是不⼀样的,⽐如xQueueSendFromISR():PxHigherPriorityTaskWoken⽤来标记退出该函数后是否需要进⾏任务切换,因为我们发送队列时,有可能会将某个阻塞任务退出阻塞态,⽽此时⼜在中断中,所以当PxHigherPriorityTaskWoken为pdTRUE时,我们则必须进⾏⼀次任务切换.可以通过portYIELD_FROM_ISR()来进⾏任务切换,并且我们不需要去判断PxHigherPriorityTaskWoken是否为pdTRUE,因为该函数内部有判断的,如下图所⽰:来个中断函数发送队列⽰例:extern QueueHandle_t Message_Queue; //信息队列句柄void USART1_IRQHandler(void) //串⼝1中断服务程序{BaseType_t xHigherPriorityTaskWoken; //定义任务切换标志位if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){//处理中断接收数据}if (Message_Queue!=NULL) //判断Message_Queue是否已创建{xQueueSendFromISR(Message_Queue, RX_BUF,&xHigherPriorityTaskWoken);//向队列Message_Queue中发送RX_BUFportYIELD_FROM_ISR(xHigherPriorityTaskWoken);//通过portYIELD_FROM_ISR()判断是否需要切换任务}}PS:尽量将portYIELD_FROM_ISR()写在中断函数末尾处6.6⽰例-任务之间的伪代码按键任务向打印任务发送按键消息队列,代码如下:QueueHandle_t Key_Queue; //按键值消息队列句柄int main(){//...省略N⾏代码Key_Queue=xQueueCreate(1,sizeof(u8)); //创建消息Key_Queue,长度为1//创建两个任务:key_task()、print_task()//...省略N⾏代码}key_task() //获取按键值{ while(1) { key=KEY_Scan(0); //扫描按键 if((Key_Queue!=NULL)&&(key)) //消息队列Key_Queue创建成功,并且按键被按下 { err=xQueueSend(Key_Queue,&key,10); if(err==errQUEUE_FULL) //发送按键值 { printf("队列Key_Queue已满,数据发送失败!\r\n"); } } vTaskDelay(10); //延时10个时钟节拍 }}print_task() //打印按键值{ u8 key; while(1) { if(Key_Queue!=NULL) { if(xQueueReceive(Key_Queue,&key,portMAX_DELAY))//请求消息Key_Queue { printf("key=%d\r\n",key); } } vTaskDelay(10); //延时10个时钟节拍 }}7. RTOS软件定时器7.1简介在之前的任务创建的时候有讲到过,RTOS会⾃动创建⼀个优先级configMAX_PRIORITIES-1的软件定时器服务任务(管理定时器的).所以我们写⼀个定时器回调函数时,则会被该定时器服务任务调⽤,所以在我们软件定时器函数中不能使⽤vTaskDelay()阻塞之类的API函数,否则会将系统中的定时器服务函数给阻塞掉.7.2 FreeRTOSConfig.h相关的定时器配置#define configUSE_TIMERS 1 //为1时启⽤软件定时器#define configTIMER_TASK_PRIORITY 31 //设置软件定时器优先级可设置的值范围为0~31#define configTIMER_QUEUE_LENGTH 5 //软件定时器队列长度#define configTIMER_TASK_STACK_DEPTH 200 //设置每个软件定时器任务堆栈⼤⼩7.3定时创建相关APITimerHandle_t xTimerCreateStatic(const char * const pcTimerName, //定时器字符串别名 const TickType_t xTimerPeriodInTicks, //需要定时的周期值,⽐如通过200/ portTICK_RATE_MS来转换实现定时200毫秒 const UBaseType_t uxAutoReload, //是否重载(周期性/单次性),若为pdTRUE(1)表⽰为周期性,为pdFALSE(0)表⽰为单次 void * const pvTimerID, //定时器ID号,⼀般⽤于多个定时器共⽤⼀个定时器回调函数,否则填0即可 TimerCallbackFunction_t pxCallbackFunction);//定时器回调函数xTimerDelete( xTimer, xTicksToWait );//删除定时器//xTicksToWait:指定该定时器在多少时钟节拍数之前删除掉,为0则⽴即删除,⼀般设为100(如果设为0,则如果在该操作之前还有其它设置定时器操作的话,则不会进⾏阻塞等待,从⽽返回false)7.4 定时器其它常⽤APIxTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait );//修改定时器周期,在中断中则使⽤xTimerChangePeriodFromISR()// xNewPeriod:要修改的周期值//xTicksToWait:指定该定时器在多少时钟节拍数之前修改好,为0则⽴即删除//xTimerReset( xTimer, xTicksToWait );//复位定时器,让定时器重新计数,在中断中则使⽤xTimerResetFromISR()// xTicksToWait:和上⾯内容类似xTimerStart( xTimer, xTicksToWait );//启动定时器,如果定时器正在运⾏的话调⽤该函数的结果和xTimerReset()⼀样, 在中断中则使⽤xTimerResetFromISR ()xTimerStop( xTimer, xTicksToWait );//停⽌定时器, 在中断中则使⽤xTimerStopFromISR ()PS:在中断中使⽤定时器API时,同样和队列⼀样,也需要在函数末尾通过portYIELD_FROM_ISR()进⾏⼀次任务切换判断8. 信号量在项⽬中我们⼀般⽤⼆值信号量,⽤来同步数据的.⽐如任务A要向任务B发送⼀个很⼤的数据buf,⽽⽤队列的话会进⾏复制拷贝,从⽽占⽤⼤量时间.此时我们不妨定义⼀个全局数据buf,任务A修改这个buf,发送⼀个信号量给任务B,任务B就去读取这个全局数据buf即可.从⽽省去了队列复制拷贝的时间. 8.1定义信号量举例SemaphoreHandle_t BinarySemaphore; //⼆值信号量句柄BinarySemaphore=xSemaphoreCreateBinary(); //创建⼆值信号量8.2在中断中发送信号量过程BaseType_t xHigherPriorityTaskWoken;xSemaphoreGiveFromISR(BinarySemaphore,&xHigherPriorityTaskWoken);//发送⼆值信号量portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进⾏⼀次任务切换8.3在任务中发送信号量过程xSemaphoreGive(BinarySemaphore);//返回值: pdPASS(0, 表⽰发送成功,如果信号量⼀直未处理,则会返回值失败FULL)8.4 在任务中接收信号量过程err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //获取信号量// portMAX_DELAY:进⼊阻塞态⼀直等待获取//返回值为pdTRUE(OK) pdFALSE(err)。
FreeRTOS原理与实现

嵌入式操作系统FreeRTOS的原理与实现在嵌入式领域中,嵌入式实时操作系统正得到越来越广泛的应用。
采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。
由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、Salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。
相对于μC/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。
1.FreeRTOS操作系统功能作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。
FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。
FreeRTOS内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
FreeRTOS的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。
当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。
2.FreeRTOS操作系统的原理与实现2. 1任务调度机制的实现任务调度机制是嵌入式实时操作系统的一个重要概念,也是其核心技术。
对于可剥夺型内核,优先级高的任务一旦就绪就能剥夺优先级较低任务的CPU使用权,提高了系统的实时响应能力。
(2024年)FreeRTOS从入门到精通1

现已成为最受欢迎的嵌入式实 时操作系统之一
广泛应用于各种行业,包括汽 车、医疗、工业控制等
不断更新迭代,加入新功能和 优化性能
2024/3/26
5
主要特点与优势
可靠性
经过严格测试和验 证,具有高度的稳 定性
开放性
源代码公开,易于 学习和定制
2024/3/26
实时性
提供可预测的响应 时间,适合对时间 要求严格的应用
安装必要的驱动程序和组件
如串口驱动、JTAG驱动等,确保电脑与开发板正常 通信。
15
第一个FreeRTOS程序示例
创建FreeRTOS工程
在IDE中创建一个新的FreeRTOS工程,并配置相关参数。
编写任务代码
创建多个任务,并编写相应的任务处理函数,实现任务间的切换和通信。
编译和下载程序
将编写好的代码编译成可执行文件,并下载到开发板中进行测试。
功耗管理策略
分享多种功耗管理策略,如动态调 整系统时钟、关闭未使用外设、使 用低功耗模式等,降低系统功耗。
2024/3/26
功耗管理API介绍
介绍FreeRTOS提供的功耗管理相 关API,如tickless模式、低功耗模 式切换等,方便开发者进行功耗优
化。
功耗管理实践案例
分享在FreeRTOS中进行功耗优化 的实践案例,包括硬件平台选择、 软件架构设计、功耗测试方法等,
2024/3/26
备份和恢复
设计备份和恢复机制,确保系统数据安全和 可恢复性。
31
企业级应用部署注意事项
硬件兼容性
确保FreeRTOS与目标硬件兼容,充分发挥 硬件性能。
可扩展性规划
考虑系统未来扩展需求,设计可扩展的架构 和接口。
深入理解FreeRTOS的任务机制和消息队列+附完整项目代码

}
listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB,&( pxReadyTasksLists[ uxTopReadyPriority ] ) ); // pxCurrentTCB指向最高优先级任务
//抢占同一优先级的下一个任务。
4.消息队列:
FreeRTOS中消息队列是任务间数据交换的常用手段(中断服务程序同样使用队列来通信与同步),消息队列是生产者消费者模型的重要组成部分
消息队列的数据结构如下:
typedef struct QueueDefinition
{
signed char *pcHead;//队头
signed char *pcTail;//队尾
任务一向消息队列填充数字,任务二从消息队列提取数据并发送到串口1,同时有LED灯跟随数据传送亮灭。
下载地址:
STM32搭载RTOS实现任务+消息队列+串口通信完整项目代码
主要讲讲任务和消息队列
1.任务控制模块(TCB被创建,并放入就绪列表。就绪列表是一个双向链表,在链表中每个任务按优先级排列,并且设置有记录相关信息的变量和进行各种操作的指针。
2.任务优先级
RTOS的基本工作单元是任务,所有任务都有一个用户优先级,如:从0到最高,如:0(最低),1,2,3 (最高) 在FreeRTOSConfig.h中设置优先级个数。
signed char *pcWriteTo;
signed char *pcReadFrom;
xList xTasksWaitingToSend;//等待发送的任务列表
xList xTasksWaitingToReceive;//等待接收的任务列表
freertos的课程设计

freertos的课程设计一、教学目标本课程旨在让学生了解和掌握FreeRTOS实时操作系统的基本原理和应用方法。
通过本课程的学习,学生将能够:1.理解实时操作系统的基本概念,包括任务、调度、同步等。
2.掌握FreeRTOS的关键特性,如多任务、抢占式调度、时间管理、内存管理等。
3.能够运用FreeRTOS进行嵌入式系统的开发,实现实时任务的管理和调度。
4.培养学生的动手实践能力和团队协作精神,提高他们解决实际问题的能力。
二、教学内容本课程的教学内容主要包括以下几个部分:1.实时操作系统基础:介绍实时操作系统的概念、特点和应用领域,让学生了解实时操作系统的基本原理。
2.FreeRTOS概述:讲解FreeRTOS的核心功能、架构和关键特性,使学生对FreeRTOS有一个整体的认识。
3.FreeRTOS编程:详细讲解FreeRTOS的编程接口,包括任务创建、任务调度、事件处理等,让学生能够熟练使用FreeRTOS进行编程。
4.嵌入式系统设计:介绍如何使用FreeRTOS设计嵌入式系统,包括硬件选择、系统架构设计、驱动开发等,帮助学生掌握嵌入式系统的设计方法。
5.实践项目:安排学生进行实践项目,让学生将所学知识应用到实际项目中,提高他们的动手实践能力。
三、教学方法为了提高教学效果,本课程将采用多种教学方法相结合的方式进行教学:1.讲授法:讲解实时操作系统和FreeRTOS的基本概念、原理和编程方法。
2.案例分析法:分析典型的嵌入式系统设计案例,让学生了解FreeRTOS在实际项目中的应用。
3.实验法:安排学生进行实验,让学生动手实践,加深对FreeRTOS的理解。
4.讨论法:学生进行课堂讨论,鼓励学生提问、发表见解,提高他们的思考和表达能力。
四、教学资源为了支持本课程的教学,我们将准备以下教学资源:1.教材:选用权威、实用的FreeRTOS教材,为学生提供系统的学习资料。
2.参考书:提供相关的嵌入式系统设计和实时操作系统方面的参考书,丰富学生的知识体系。
FreeRTOS详解

Selecting the API to Use∙Only those API functions specifically designated for use from within an ISR should be used from within an ISR.∙Tasks and co-routines use different API functions to access queues.A queue cannot be used to communicate between a task and a co-routineor visa versa.∙Intertask communication can be achieved using the full featured API functions, the alternative API functions, and the light weight API functions (those with "FromISR" in their name).∙Use of the light weight functions outside of an ISR requires special consideration, as described under the heading "Performance tips and tricks - using the light weight API".Task APIA task may call any API function listed in the menu frame on the left other than those under the co-routine specific section.Co-Routine APIIn addition to the API functions listed under the co-routine specific section, a co-routine may use the following API calls.∙taskYIELD() - will yield the task in which the co-routines are running.∙taskENTER_CRITICAL().∙taskEXIT_CRITICAL().∙vTaskStartScheduler() - this is still used to start the scheduler even if the application only includes co-routines and no tasks.∙vTaskSuspendAll() - can still be used to lock the scheduler.∙xTaskResumeAll()∙xTaskGetTickCount()∙uxTaskGetNumberOfTasks()Customisation[Configuration]A number of configurable parameters exist that allow the FreeRTOS kernel to be tailored to your particular application. These items are located in a file called FreeRTOSConfig.h. Each demo application included in the FreeRTOS source code download has its own FreeRTOSConfig.h file. Here is a typical example, followed by an explanation of each parameter:#ifndef FREERTOS_CONFIG_H#define FREERTOS_CONFIG_H/* Here is a good place to include header files that are required across your application. */#include "something.h"#define configUSE_PREEMPTION 1#define configUSE_IDLE_HOOK 0#define configUSE_TICK_HOOK 0#define configCPU_CLOCK_HZ 58982400#define configTICK_RATE_HZ 250#define configMAX_PRIORITIES 5#define configMINIMAL_STACK_SIZE 128#define configTOTAL_HEAP_SIZE 10240#define configMAX_TASK_NAME_LEN 16#define configUSE_TRACE_FACILITY 0#define configUSE_16_BIT_TICKS 0#define configIDLE_SHOULD_YIELD 1#define configUSE_MUTEXES 0#define INCLUDE_vTaskPrioritySet 1#define INCLUDE_uxTaskPriorityGet 1#define INCLUDE_vTaskDelete 1#define INCLUDE_vTaskCleanUpResources 0#define INCLUDE_vTaskSuspend 1#define INCLUDE_vResumeFromISR 1#define INCLUDE_vTaskDelayUntil 1#define INCLUDE_vTaskDelay 1#define INCLUDE_xTaskGetSchedulerState 1#define INCLUDE_xTaskGetCurrentTaskHandle 1#define configUSE_CO_ROUTINES 0#define configMAX_CO_ROUTINE_PRIORITIES 1#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] #endif /* FREERTOS_CONFIG_H */'config' ParametersconfigUSE_PREEMPTIONSet to 1 to use the preemptive kernel, or 0 to use the cooperative kernel.configUSE_IDLE_HOOKSet to 1 if you wish to use an idle hook, or 0 to omit an idle hook.configUSE_TICK_HOOKSet to 1 if you wish to use an tick hook, or 0 to omit an tick hook.configCPU_CLOCK_HZEnter the frequency in Hz at which the internal processor core will be executing. This value is required in order to correctly configure timer peripherals.configTICK_RATE_HZThe frequency of the RTOS tick interrupt.The tick interrupt is used to measure time. Therefore a higher tick frequency means time can be measured to a higher resolution. However, a high tick frequency also means that the kernel will use more CPU time so be less efficient. The RTOS demo applications all use a tick rate of 1000Hz. This is used to test the kernel and is higher than would normally be required.More than one task can share the same priority. The kernel will share processor time between tasks of the same priority by switching between the tasks during each RTOS tick. A high tick rate frequency will therefore also have the effect of reducing the 'time slice' given to each task.configMAX_PRIORITIESThe number of priorities available to the application tasks. Any number of tasks can share the same priority. Co-routines are prioritised separately - see configMAX_CO_ROUTINE_PRIORITIES.Each available priority consumes RAM within the kernel so this value should not be set any higher than actually required by your application. configMINIMAL_STACK_SIZEThe size of the stack used by the idle task. Generally this should not be reduced from the value set in the FreeRTOSConfig.h file provided with the demo application for the port you are using.configTOTAL_HEAP_SIZEThe total amount of RAM available to the kernel.This value will only be used if your application makes use of one of the sample memory allocation schemes provided in the FreeRTOS source code download. See the memory configuration section for further details.configMAX_TASK_NAME_LENThe maximum permissible length of the descriptive name given to a task when the task is created. The length is specified in the number of characters including the NULL termination byte.configUSE_TRACE_FACILITYSet to 1 if you wish the trace visualisation functionality to be available, or 0 if the trace functionality is not going to be used. If you use the trace functionality a trace buffer must also be provided.configUSE_16_BIT_TICKSTime is measured in 'ticks' - which is the number of times the tick interrupt has executed since the kernel was started. The tick count is held in a variable of type portTickType.Defining configUSE_16_BIT_TICKS as 1 causes portTickType to be defined (typedef'ed) as an unsigned 16bit type. Defining configUSE_16_BIT_TICKS as 0 causes portTickType to be defined (typedef'ed) as an unsigned 32bit type. Using a 16 bit type will greatly improve performance on 8 and 16 bit architectures, but limits the maximum specifiable time period to 65535 'ticks'. Therefore, assuming a tick frequency of 250Hz, the maximum time a task can delay or block when a 16bit counter is used is 262 seconds, compared to 17179869 seconds when using a 32bit counter.configIDLE_SHOULD_YIELDThis parameter controls the behaviour of tasks at the idle priority. It only has an effect if:1. The preemptive scheduler is being used.2. The users application creates tasks that run at the idle priority.T asks that share the same priority will time slice. Assuming none of the tasks get preempted, it might be assumed that each task of at a given priority will be allocated an equal amount of processing time - and if the shared priority is above the idle priority then this is indeed the case.When tasks share the idle priority the behaviour can be slightly different. When configIDLE_SHOULD_YIELD is set to 1 the idle task will yield immediately should any other task at the idle priority be ready to run. This ensures the minimum amount of time is spent in the idle task when application tasks are available for scheduling. This behaviour can however have undesirable effects (depending on the needs of your application) as depicted below:This diagram shows the execution pattern of four tasks at the idle priority. Tasks A, B and C are application tasks. Task I is the idle task. A context switch occurs with regular period at times T0, T1, ..., T6. When the idle task yields task A starts to execute - but the idle task has already taken up some of the current time slice. This results in task I and task A effectively sharing a time slice. The application tasks B and C therefore get more processing time than the application task A.This situation can be avoided by:∙If appropriate, using an idle hook in place of separate tasks at the idle priority.∙Creating all application tasks at a priority greater than the idle priority.∙Setting configIDLE_SHOULD_YIELD to 0.Setting configIDLE_SHOULD_YIELD prevents the idle task from yielding processing time until the end of its time slice. This ensure all tasks at the idle priority are allocated an equal amount of processing time - but at the cost of a greater proportion of the total processing time being allocated to the idle task.configUSE_USE_MUTEXESSet to 1 to include mutex functionality in the build, or 0 to omit mutex functionality from the build. Readers should familiarise themselves with the differences between mutexes and binary semaphores in relation to the functionality.configUSE_CO_ROUTINESSet to 1 to include co-routine functionality in the build, or 0 to omit co-routine functionality from the build. To include co-routines croutine.c must be included in the project.configMAX_CO_ROUTINE_PRIORITIESThe number of priorities available to the application co-routines. Any number of co-routines can share the same priority. T asks are prioritised separately - see configMAX_PRIORITIES.configKERNEL_INTERRUPT_PRIORITYCurrently only in Cortex-M3/IAR, PIC24 and dsPIC ports. Other ports will get upgraded shortly. This sets the interrupt priority used by the kernel. The kernel should use a low interrupt priority, allowing higher priority interrupts to be unaffected by the kernel entering critical sections. Instead of critical sections globally disabling interrupts, they only disable interrupts that are below the kernel interrupt priority.This permits very flexible interrupt handling:∙At the kernel priority level interrupt handling 'tasks' can be written and prioritised as per any other task in the system. These are tasks that are woken by aninterrupt. The interrupt service routine (ISR) itself should be written to be as short as it possibly can be - it just grabs the data then wakes the high priority handlertask. The ISR then returns directly into the woken handler task - so interruptprocessing is contiguous in time just as if it were all done in the ISR itself. Thebenefit of this is that all interrupts remain enabled while the handler task executes.∙ISR's running above the kernel priority are never masked out by the kernel itself, so their responsiveness is not effected by the kernel functionality. However, such ISR's cannot use the API functions.T o utilize this scheme your application design must adhere to the following rule: Any interrupt that uses the API must be set to the same priority as the kernel (as configured by the configKERNEL_INTERRUPT_PRIORITY macro).INCLUDE ParametersThe macros starting 'INCLUDE' allow those components of the real time kernel not utilized by your application to be excluded from your build. This ensures the RTOS does not use any more ROM or RAM than necessary for your particular embedded application.Each macro takes the form ...INCLUDE_FunctionName... where FunctionName indicates the API function (or set of functions) that can optionally be excluded. To include the API function set the macro to 1, to exclude the function set the macro to 0. For example, to include the vT askDelete() API function use:#define INCLUDE_vTaskDelete 1To exclude vTaskDelete() from your build use:#define INCLUDE_vTaskDelete 0Memory Management[Configuration]The RTOS kernel has to allocate RAM each time a task, queue or semaphore is created. The malloc() and free() functions can sometimes be used for this purpose, but ...1. they are not always available on embedded systems,2. take up valuable code space,3. are not thread safe, and4. are not deterministic (the amount of time taken to execute the function will differfrom call to call)... so more often than not an alternative scheme is required.One embedded / real time system can have very different RAM and timing requirements to another - so a single RAM allocation algorithm will only ever be appropriate for a subset of applications.To get around this problem the memory allocation API is included in the RTOS portable layer - where an application specific implementation appropriate for the real time system being developed can be provided. When the real time kernel requires RAM, instead of calling malloc() it makes a call to pvPortMalloc(). When RAM is being freed, instead of calling free() the real time kernel makes a call to vPortFree().Schemes included in the source code downloadThree sample RAM allocation schemes are included in the FreeRTOS source code download (V2.5.0 onwards). These are used by the various demo applications as appropriate. The following subsections describe the available schemes, when they should be used, and highlight the demo applications that demonstrate their use.Each scheme is contained in a separate source file (heap_1.c, heap_2.c and heap_3.c respectively) which can be located in the Source/Portable/MemMang directory. Other schemes can be added if required.Scheme 1 - heap_1.cThis is the simplest scheme of all. It does not permit memory to be freed once it has been allocated, but despite this is suitable for a surprisingly large number of applications.The algorithm simply subdivides a single array into smaller blocks as requests for RAM are made. The total size of the array is set by the definition configTOTAL_HEAP_SIZE - which is defined in FreeRTOSConfig.h.This scheme:∙Can be used if your application never deletes a task or queue (no calls to vT askDelete() or vQueueDelete() are ever made).∙Is always deterministic (always takes the same amount of time to return a block).∙Is used by the PIC, AVR and 8051 demo applications - as these do not dynamically create or delete tasks after vT askStartScheduler() has been called.heap_1.c is suitable for a lot of small real time systems provided that all tasks and queues are created before the kernel is started.Scheme 2 - heap_2.cThis scheme uses a best fit algorithm and, unlike scheme 1, allows previously allocated blocks to be freed. It does not however combine adjacent free blocks into a single large block.Again the total amount of available RAM is set by the definition configTOTAL_HEAP_SIZE - which is defined in FreeRTOSConfig.h.This scheme:∙Can be used even when the application repeatedly callsvT askCreate()/vT askDelete() or vQueueCreate()/vQueueDelete() (causingmultiple calls to pvPortMalloc() and vPortFree()).∙Should not be used if the memory being allocated and freed is of a random size - this would only be the case if tasks being deleted each had a different stack depth, or queues being deleted were of different lengths.∙Could possible result in memory fragmentation problems should your application create blocks of queues and tasks in an unpredictable order. This would beunlikely for nearly all applications but should be kept in mind.∙Is not deterministic - but is also not particularly inefficient.∙Is used by the ARM7, and Flashlite demo applications - as these dynamically create and delete tasks.heap_2.c is suitable for most small real time systems that have to dynamically create tasks.Scheme 3 - heap_3.cThis is just a wrapper for the standard malloc() and free() functions. It makes them thread safe.This scheme:∙Requires the linker to setup a heap, and the compiler library to provide malloc() and free() implementations.∙Is not deterministic.∙Will probably considerably increase the kernel code size.∙Is used by the PC (x86 single board computer) demo application.Task Creation[API] Modules∙xT askCreate∙vT askDeleteDetailed DescriptionxTaskHandletask. hType by which tasks are referenced. For example, a call to xTaskCreate returns (via a pointer parameter) an xTaskHandle variable that can then be used as a parameter to vTaskDelete to delete the taskxTaskCreate[Task Creation]task. hportBASE_TYPE xTaskCreate(pdTASK_CODE pvTaskCode,const portCHAR * const pcName,unsigned portSHORT usStackDepth,void *pvParameters,unsigned portBASE_TYPE uxPriority,xTaskHandle *pvCreatedTask);Create a new task and add it to the list of tasks that are ready to run.Parameters:pvTaskCode Pointer to the task entry function. Tasks must be implemented to never return (i.e. continuous loop).pcName A descriptive name for the task. This is mainly used to facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN.usStackDepth The size of the task stack specified as the number of variables the stack can hold - not the number of bytes. For example, if the stack is 16 bitswide and usStackDepth is defined as 100, 200 bytes will be allocated forstack storage. The stack depth multiplied by the stack width must notexceed the maximum value that can be contained in a variable of typesize_t.pvParameters Pointer that will be used as the parameter for the task being created.uxPriority The priority at which the task should run.pvCreatedTask Used to pass back a handle by which the created task can be referenced. Returns:pdPASS if the task was successfully created and added to a ready list, otherwise an error code defined in the file projdefs. hExample usage:// Task to be created.void vTaskCode( void * pvParameters ){for( ;; ){// Task code goes here.}}// Function that creates a task.void vOtherFunction( void ){unsigned char ucParameterToPass;xTaskHandle xHandle;// Create the task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );// Use the handle to delete the task.vTaskDelete( xHandle );}vTaskDelete[Task Creation]task. hvoid vTaskDelete( xTaskHandle pxTask );INCLUDE_vTaskDelete must be defined as 1 for this function to be available. See the configuration section for more information.Remove a task from the RTOS real time kernels management. The task being deleted will be removed from all ready, blocked, suspended and event lists.NOTE: The idle task is responsible for freeing the kernel allocated memory from tasks that have been deleted. It is therefore important that the idle task is not starved of microcontroller processing time if your application makes any calls to vTaskDelete (). Memory allocated by the task code is not automatically freed, and should be freed before the task is deleted.See the demo application file death. c for sample code that utilises vTaskDelete ().Parameters:pxTask The handle of the task to be deleted. Passing NULL will cause the calling task to be deleted.Example usage:void vOtherFunction( void ){xTaskHandle xHandle;// Create the task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );// Use the handle to delete the task.vTaskDelete( xHandle );}vTaskDelay[Task Control]task. hvoid vTaskDelay( portTickType xTicksToDelay );INCLUDE_vTaskDelay must be defined as 1 for this function to be available. See the configuration section for more information.Delay a task for a given number of ticks. The actual time that the task remains blocked depends on the tick rate. The constant portTICK_RATE_MS can be used to calculate real time from the tick rate - with the resolution of one tick period.Parameters:xTicksToDelay The amount of time, in tick periods, that the calling task should block. Example usage:// Perform an action every 10 ticks.// NOTE:// This is for demonstration only and would be better achieved// using vTaskDelayUntil().void vTaskFunction( void * pvParameters ){portTickType xDelay, xNextTime;// Calc the time at which we want to perform the action// next.xNextTime = xTaskGetTickCount () + ( portTickType ) 10;for( ;; ){xDelay = xNextTime - xTaskGetTickCount ();xNextTime += ( portTickType ) 10;// Guard against overflowif( xDelay <= ( portTickType ) 10 ){vTaskDelay( xDelay );}// Perform action here.}}vTaskDelayUntil[Task Control]task. hvoid vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available. See the configuration section for more information.Delay a task until a specified time. This function can be used by cyclical tasks to ensure a constant execution frequency.This function differs from vTaskDelay() in one important aspect: vTaskDelay() specifies a time at which the task wishes to unblock relative to the time at which vTaskDelay() is called, whereas vTaskDelayUntil() specifies an absolute time at which the task wishes to unblock.vTaskDelay() will cause a task to block for the specified number of ticks from the time vTaskDelay() is called. It is therefore difficult to use vTaskDelay() by itself to generate a fixed execution frequency as the time between a task unblocking following a call to vTaskDelay() and that task next calling vTaskDelay() may not be fixed [the task may take a different path though the code between calls, or may get interrupted or preempted a different number of times each time it executes].Whereas vTaskDelay() specifies a wake time relative to the time at which the function is called, vTaskDelayUntil() specifies the absolute (exact) time at which it wishes to unblock.It should be noted that vTaskDelayUntil() will return immediately (without blocking) if it is used to specify a wake time that is already in the past. Therefore a task using vTaskDelayUntil() to execute periodically will have to re-calculate its required wake time if the periodic execution is halted for any reason (for example, the task is temporarily placed into the Suspended state) causing the task to miss one or more periodic executions. This can be detected by checking the variable passed by reference as the pxPreviousWakeTime parameter against the current tick count. This is however not necessary under most usage scenarios.The constant portTICK_RATE_MS can be used to calculate real time from the tick rate - with the resolution of one tick period.Parameters:pxPreviousWakeTime Pointer to a variable that holds the time at which the task was lastunblocked. The variable must be initialised with the current timeprior to its first use (see the example below). Following this thevariable is automatically updated within vTaskDelayUntil().xTimeIncrement The cycle time period. The task will be unblocked at time(*pxPreviousWakeTime + xTimeIncrement). CallingvTaskDelayUntil with the same xTimeIncrement parameter valuewill cause the task to execute with a fixed interval period. Example usage:// Perform an action every 10 ticks.void vTaskFunction( void * pvParameters ){portTickType xLastWakeTime;const portTickType xFrequency = 10;// Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount();for( ;; ){// Wait for the next cycle.vTaskDelayUntil( &xLastWakeTime, xFrequency );// Perform action here.}}uxTaskPriorityGet[Task Control]task. hunsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ); INCLUDE_vTaskPriorityGet must be defined as 1 for this function to be available. See the configuration section for more information.Obtain the priority of any task.Parameters:pxTask Handle of the task to be queried. Passing a NULL handle results in the priority of the calling task being returned.Returns:The priority of pxT ask.Example usage:void vAFunction( void ){xTaskHandle xHandle;// Create a task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );// ...// Use the handle to obtain the priority of the created task.// It was created with tskIDLE_PRIORITY, but may have changed// it itself.if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY ){// The task has changed it's priority.}// ...// Is our priority higher than the created task?if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) ){// Our priority (obtained using NULL handle) is higher.}}vTaskPrioritySet[Task Control]task. hvoid vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. See the configuration section for more information.Set the priority of any task.A context switch will occur before the function returns if the priority being set is higher than the currently executing task.Parameters:pxTask Handle to the task for which the priority is being set. Passing a NULLhandle results in the priority of the calling task being set.uxNewPriority The priority to which the task will be set.Example usage:void vAFunction( void ){xTaskHandle xHandle;// Create a task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );// ...// Use the handle to raise the priority of the created task.vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );// ...// Use a NULL handle to raise our priority to the same value.vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );}vTaskSuspend[Task Control]task. hvoid vTaskSuspend( xTaskHandle pxTaskToSuspend );INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. See the configuration section for more information.Suspend any task. When suspended a task will never get any microcontroller processing time, no matter what its priority.Calls to vTaskSuspend are not accumulative - i.e. calling vTaskSuspend () twice on the same task still only requires one call to vTaskResume () to ready the suspended task.Parameters:pxTaskToSuspend Handle to the task being suspended. Passing a NULL handle will causethe calling task to be suspended.Example usage:void vAFunction( void ){xTaskHandle xHandle;// Create a task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );// ...// Use the handle to suspend the created task.vTaskSuspend( xHandle );// ...// The created task will not run during this period, unless// another task calls vTaskResume( xHandle ).//...// Suspend ourselves.vTaskSuspend( NULL );// We cannot get here unless another task calls vTaskResume// with our handle as the parameter.}vTaskResume[Task Control]task. hvoid vTaskResume( xTaskHandle pxTaskToResume );INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. See the configuration section for more information.Resumes a suspended task.A task that has been suspended by one of more calls to vTaskSuspend () will be made available for running again by a single call to vTaskResume ().Parameters:pxTaskToResume Handle to the task being readied.Example usage:void vAFunction( void ){xTaskHandle xHandle;// Create a task, storing the handle.xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );// ...// Use the handle to suspend the created task.vTaskSuspend( xHandle );// ...// The created task will not run during this period, unless// another task calls vTaskResume( xHandle ).//...// Resume the suspended task ourselves.vTaskResume( xHandle );// The created task will once again get microcontroller processing // time in accordance with it priority within the system.}vTaskResumeFromISR[Task Control]task. hportBASE_TYPE vTaskResumeFromISR( xTaskHandle pxTaskToResume ); INCLUDE_vTaskSuspend and INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be available. See the configuration section for more information.A function to resume a suspended task that can be called from within an ISR.A task that has been suspended by one of more calls to vTaskSuspend() willbe made available for running again by a single call to xTaskResumeFromISR().。
【FreeRTOS操作系统教程】第8章 FreeRTOS调试方法(打印任务执行情况)

2016年06月30日
版本:1.0
第 3 页 共 22 页
武汉安富莱电子有限公司
else if (TIMx == TIM6) irq = TIM6_IRQn;
else if (TIMx == TIM7) irq = TIM7_IRQn;
//PCLK2 = HCLK RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14 APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
1
#define configGENERATE_RUN_TIME_STATS
1
#define configUSE_STATS_FORMATTING_FUNCTIONS
1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks = 0ul)
#include <stdint.h> extern volatile uint32_t ulHighFrequencyTimerTicks; #endif
/* Run time and task stats gathering related definitions. */
#define configUSE_TRACE_FACILITY
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验5-8知识点
实验5:时间片调度/任务信息状态查询与统计
实验6:信号量
实验7:软件定时器/事件标志组
实验8:任务通知
回答下列问题时,尽量通过读代码得到答案,这有助于你理解和记住代码。
1.《11-1 FreeRTOS任务状态或信息查询实验》
本实验同时用到了TIM3和TIM5。
TIM5可以换成TIM4。
但是,如果我们想把这一实验和以前的实验合并成一个工程时,TIM3/TIM4和实验6-1中断测试实验冲突,这个该如何解决?给出思路即可。
??
uxTaskGetNumberOfTasks函数的作用和用法?
P156获取当前系统中存在的任务的个数
uxTaskGetSystemState函数的作用和用法?
P151获取系统中任务状态
uxTaskGetSystemState中的TaskStatus_t结构体的成员变量有哪些?
作业20180521/1:
typedef struct xTASK_STATUS
{
TaskHandle_t xHandle; //任务句柄
const char *pcTaskName; //任务名字
UBaseType_t xTaskNumber; //任务编号
eTaskState eCurrentState; //当前任务状态
UBaseType_tuxCurrentPriority; //任务当前优先级
UBaseType_t uxBasePriority; //任务基础优先级
uint32_t ulRunTimeCounter; //任务运行的总时间
StackType_t *pxStackBase; //堆栈基地址
uint16_tusStackHighWaterMark; //从任务创建以来任务堆栈剩余的最小大小
} TaskStatus_t;
xTaskGetHandle函数的作用和用法?
P154根据任务名字查找某个任务的句柄
vTaskGetInfo函数的作用和用法?
P152获取某个任务信息
eTaskGetState函数的作用和用法?
P154获取某个任务的状态(eTaskState类型)
pvPortMalloc函数的作用和用法?
P161内存申请函数
vPortFree函数的作用和用法?
P161内存释放函数
memset函数的作用和用法?
P162内存设置函数
2.《FreeRTOS实验11-2 FreeRTOS任务运行时间统计实验》
统计任务运行时间功能的问题:
(1)使用统计功能需要开放哪几个宏?
P164一共要开放3个宏
(2)配置统计时钟基准的函数是什么?其内容是什么?
P165其实就是初始化定时器
(3)要能够正常统计,统计时间基准和OS时间节拍的关系是什么?
P165时钟基准的精度要比系统时钟高10-20倍
(4)tasks.c中的哪个函数中计算了每个任务的运行时间?
P169vTaskGetRunTimeStats()
调试的问题:
在软件仿真状态下,当设置一个管脚为上拉输入时,它的初始值是什么?
设置完GPIO状态为上拉输入时,发现ODR里对应值为1,而PIN和IDR里为0。
3.《FreeRTOS实验13-1 FreeRTOS队列操作实验》
uxQueueSpacesAvailable函数的作用和用法
13-1main.c&queue.c用于求队列剩余大小
uxQueueMessagesWaiting函数的作用和用法
13-1main.c&queue.c用于求当前已使用队列大小
xQueueCreate函数的作用和用法
P189队列创建函数,本质上是一个宏,用来动态创建队列,最终会调用xQueueGenericCreate ()
my_mem_init函数的作用
P213初始化内部内存池
mymalloc函数的作用和用法
P212申请内存
myfree函数的作用和用法
P212释放内存
xQueueSend函数的作用和用法
P196用于向队列中发送消息,本质上是一个宏,后向入队,新消息插入到队列后面,最终会调用xQueueGenericSend(),只能用于任务函数中
xQueueReceiveFromISR函数的作用和用法
P209用于在中断服务函数中从队列读取一条信息,读取成功后会将队列中这条数据删除
定时器的定时中断周期与自动重装值、预分频数、定时器时钟源之间的计算公式是什么?
中断周期(s)=[(自动重装载值+1)×(预分频数+1) ]/定时器时钟源(MHz)
*补充:已知中断周期和定时器时钟源频率,假定预分频数,求自动重装值。
例:已知时钟源频率72MHz,中断周期1.75s,假定时钟源2000分频,预分频数即为1999,分频后的时钟频率为72MHz/(1999+1)=36000Hz,
则装载值=1.75/(1/36000)=63000。
重装载值越大,误差越小。
这一实验中的内存动态分配方式与13-1中的不同,差别体现在哪里?
??
4.《FreeRTOS实验14-1 FreeRTOS二值信号量实验》
什么是二值信号量?
P220
如何创建一个二值信号量?
P222
信号量的P操作和V操作分别体现在哪两个函数中?
如何释放一个信号量?
P224
任务中如何取一个信号量?当取不到时会如何?
P226
STM32F103的USART1的发送和接收引脚分别是哪一个?
文字或流程图描述DataProcess_task函数的作用和流程。
P230-P231答:指令处理任务,根据接收到的指令来控制不同的外设
文字或流程图描述USART1_IRQHandler函数的作用和流程。
P232答:作用:释放二值信号量
变量USART_RX_STA的作用是什么?
P232中最后一个if有调用答:获取接收到的数据
5.《FreeRTOS实验14-2 FreeRTOS计数型信号量实验》
什么是计数型信号量?
P234答:长度大于1的队列
如何创建一个计数型信号量?
P234分为静态和动态创建
如何获取一个计数型信号量的当前计数值?
P226获取信号量
6.《FreeRTOS实验14-3 FreeRTOS优先级翻转实验》
举例说明什么是优先级反转。
P241优先级翻转概念及例子
分析是否发生了优先级反转。
??
什么是优先级继承?
在优先级翻转实验代码的基础上设计一个信号量互锁。
先建立两个信号量S1和S2,high_task获取S1后,只有在获取到S2后才释放S1。
相反,low_task 获取S2后,只有在获取到S1后才释放S2。
设计程序实现一个信号量互锁的现象,分析互锁出现的条件。
??
7.《FreeRTOS实验14-4 FreeRTOS互斥信号量操作实验》
什么是互斥信号量?它与二值信号量的区别是什么?
P248
如何创建一个互斥信号量?
P248
允许使用互斥信号量的宏是哪一个?
configUSE_MUTEXES == 1
比较14-3反转实验和14-4互斥实验的main中的代码差别,以及实验结果的差别。
差别:14-4的第60-61,102-103,146,150,182,188行与14-3不同。
8.FreeRTOS实验15-1 FreeRTOS软件定时器实验
什么是软件定时器?
P268
软件定时器和硬件定时器的主要区别是什么?
在硬件定时器中,我们是在定时器中断中实现需要的功能,而使用软件定时器时,我们是在创建软件定时器时指定软件定时器的回调函数,在回调函数中实现相应的功能。
xTimerCreate函数的作用和用法?
P272 函数原型+参数解释
变量uxAutoReload的true和false会对定时器带来什么影响?
当参数为pdture时,创建的是周期定时器(P270);当参数为pdfalse时,创建的是单次定时器(P270)
如何启动和停止软件定时器?
P274
定时器1和定时器2的输出有什么规律?
P270
定时器1和2的回调(callback)函数的核心内容是什么?
P279
9.FreeRTOS实验16-1 FreeRTOS事件标志组实验
什么是事件标志组?
P281
如何创建一个事件标志组?
P282
如何定义事件位?
P283
xEventGroupSetBits函数的作用和用法
P284
xEventGroupWaitBits函数的作用和用法
P286
xEventGroupGetBits函数的作用和用法
P285
10.《FreeRTOS实验17-1 FreeRTOS任务通知模拟二值信号量实验》
本实验中的xTaskNotify的作用对应了14-1实验中的哪一个函数?
P239倒数第二段P306相当于xSemaphoreGive()
用于发送任务通知,与xTaskNotifyGive()函数作用相同
xTaskWait对应了14-1实验中的哪一个函数?
??
使用任务通知会有什么优势?
P306时间快/所需的RAM少
如何设计一个实验比较任务通知和二值信号量的性能差异???。