FreeRTOS的使用总结

更新时间:2023-11-07 13:49:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

FreeRTOS的使用说明

中断程序

FreeRTOS 中如果ISR中如果使用了Quene,则需要进行任务切换,需要在ISR设计时考虑

portEND_SWITCHING_ISR( ( cContextSwitchRequired ) ); 如果没有任务切换,则无需特殊处理

任务调度

调度存在几种情况:

? 自动放弃时间(SWI),yeild以及wait导致的挂起都算 ? Tick时间到(也进行调度)

VTaskSwitchContext 仅仅查找优先级最高的调度 相同的级别 占有相同的PCU时间

对于IDLE任务而言,如果用抢占式,并且执行到IDLE时,必须让出执行时间的话 a task that is sharing the idle priority (与IDLE任务有相同优先级),则会让出。

假定该任务是while(1){},并且一直处于Ready状态,没有诸如挂起等操作,则一进入IDLE任务就让出

则vApplicationIdleHook()函数基本没有时间执行。也就失去了意义

CoRoutine是一个函数,可以迅速执行完成 在vApplicationIdleHook中调用。

调度时,直接调用了CreateCorountine的任务函数

当执行完之后,IDLE任务会重新循环,检查是否有同级任务执行。

所以在IDLE层次上,有任务,但该任务执行完了还是需要释放一段时间以便让hook函数执行操作。

否则CoRoutine函数基本上没有时间执行。

QUENE操作

其中quene的发送和等待都可能进行任务切换。

当quene发送时,如果quune队列已满,则会挂起;而如果队列为空,take操作就会导致任务挂起

queen

高优先级别 发送 低优先级别 接受

发送完了,继续执行;如果不主动让出CPU的话,低优先级的无法唤醒进行队列处理 如果发送的多了的话,队列满后,高优先级挂起,然后才会让低优先级的任务进行处理 所以程序检测发送的状态,根据状态确定是否是否需要主动让出CPU时间给相同的优先级的任务

另外一个办法就是有效发送后,将任务挂起,当低优先级的任务处理后,再重新将高优先级任务挂起

如果不这样处理的话,队列总是处于满状态

低级别发送 高级别接受

发送完了后,低级别立刻被挂起,然后高级别执行, 因此队列一直为空

任务的处理 任务的原型

void vATaskFunction( void *pvParameters ); Or,

portTASK_FUNCTION_PROTO( vATaskFunction, pvParameters );

是一个死循环

空闲任务

优先级:tskIDLE_PRIORITY 该优先级可以共享

空闲的钩子函数

The Idle Task Hook,在空闲任务中处理一些事情。 如果用相同优先级,又增加一个堆栈空间

Co-routines

configMAX_CO_ROUTINE_PRIORITIES 最高的优先级 例程有以下形式:

void vACoRoutineFunction( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) {

crSTART( xHandle );

for( ;; ) {

-- Co-routine application code here. -- }

crEND(); }

//实际经展开后如下:

switch( ( ( corCRCB * )pxCRCB )->uxState ) { case 0: ; for (;;) { } };

//延时函数的处理

#define crDELAY( xHandle, xTicksToDelay ) \\ if( xTicksToDelay > 0 ) \\ { \\ vCoRoutineAddToDelayedList( xTicksToDelay, NULL ); \\ } \\ crSET_STATE0( xHandle );

//#define crSET_STATE0( xHandle )

( ( corCRCB * )xHandle)->uxState = (__LINE__ * 2); return;

case (__LINE__ * 2):

//可见在延时函数处理过后,函数就退出了

协作例程是一个执行完了,才执行另外一个。执行完了,就意味着放弃CPU,即退出运行。

//协作例程的限制

如果需要保存数据,则需要定义成全局变量或者static变量

//block 函数只能在循环的最外层调用,不能在函数中调用,因为在函数中调用,宏已经不对了

因此也不能在switch语句中调用

void vACoRoutineFunction( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) {

// Co-routines must start with a call to crSTART().

crSTART( xHandle );

for( ;; ) {

// It is fine to make a blocking call here, crDELAY( xHandle, 10 );

// but a blocking call cannot be made from within // vACalledFunction(). vACalledFunction(); }

// Co-routines must end with a call to crEND(). crEND(); }

void vACalledFunction( void ) {

// Cannot make a blocking call here!

}

协作例程的调度

void vApplicationIdleHook( void ) {

vCoRoutineSchedule( void ); } 或者

void vApplicationIdleHook( void ) {

for( ;; ) {

vCoRoutineSchedule( void ); } }

/////=======================展开后的程序相当怪异 /* Co-routines MUST start with a call to crSTART. */ //crSTART( xHandle ); 展开

switch( ( ( corCRCB * )xHandle )->uxState ) {

case 0:

;

//crSTART( xHandle ); 展开

for( ;; ) {

/* Post our uxIndex value onto the queue. This is used as the LED to flash. */

//crQUEUE_SEND( xHandle, xFlashQueue, ( void * crfPOSTING_BLOCK_TIME, &xResult ); 展开成如下

{

* &xResult = xQueueCRSend( xFlashQueue, ( void * ) &uxIndex, 0 ); if( * &xResult == (errQUEUE_BLOCKED ) ) {

( ( corCRCB * )xHandle)->uxState = (160 * 2); //__LINE__ return;

case (160 * 2)://__LINE__ ;

* &xResult = xQueueCRSend( xFlashQueue, ( void * ) &uxIndex, 0 ); }

if( * &xResult == ( errQUEUE_YIELD ) ) {

( ( corCRCB * )xHandle)->uxState = ((160 * 2)+1); //__LINE__ return;

case ((160 * 2)+1)://__LINE__ ;

* &xResult = ( pdPASS ); } } ;

//crQUEUE_SEND( xHandle, xFlashQueue, ( void * crfPOSTING_BLOCK_TIME, &xResult ); 展开成如上

///----------------------------正常语句--------------- if( xResult != ( pdPASS ) ) {

/* For the reasons stated at the top of the file we should always find that we can post to the queue. If we could not then an error has occurred. */

uxCoRoutineFlashStatus = ( 0 ); }

) &uxIndex,

) &uxIndex,

//crDELAY( xHandle, xFlashRates[ uxIndex ] ); ----展开 if( xFlashRates[ uxIndex ] > 0 )

{ vCoRoutineAddToDelayedList( xFlashRates[ uxIndex ], 0 ); }

( ( corCRCB * )xHandle)->uxState = (170 * 2); return;

case (170 * 2):; ;

//crDELAY( xHandle, xFlashRates[ uxIndex ] ); ----展开 }

/* Co-routines MUST end with a call to crEND. */ //crEND(); 展开 }

//crEND(); 展开 ;

quene的使用

between tasks, and between interrupts and tasks 是通过copy而不是ref进行的 xQueueCreate xQueueSend

xQueueSendToBack xQueueSendToFront xQueueReceive xQueuePeek

xQueueSendFromISR

xQueueSendToBackFromISR xQueueSendToFrontFromISR xQueueReceiveFromISR

从实现的函数看,可以在ISR和TASK之间进行传递。

查看例子,在ISR中发送后,导致调度的

void vBufferISR( void ) {

portCHAR cIn;

portBASE_TYPE xHigherPriorityTaskWoken;

/* We have not woken a task at the start of the ISR. */ xHigherPriorityTaskWoken = pdFALSE;

/* Loop until the buffer is empty. */ do {

/* Obtain a byte from the buffer. */

cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );

/* Post the byte. */

xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );

} while( portINPUT_BYTE( BUFFER_COUNT ) );

/* Now the buffer is empty we can switch context if necessary. */ if( xHigherPriorityTaskWoken ) {

/* Actual macro used here is port specific. */ taskYIELD_FROM_ISR ();//导致调度发生 } }

//如果导致切换的话

void vISR_Routine( void ) {

portBASE_TYPE xTaskWokenByReceive = pdFALSE; portCHAR cRxedChar;

while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) ) {

// A character was received. Output the character now. vOutputCharacter( cRxedChar );

// If removing the character from the queue woke the task that was // posting onto the queue xTaskWokenByReceive will have been set to // pdTRUE. No matter how many times this loop iterates only one // task will be woken. }

if( xTaskWokenByPost != pdFALSE ) {

// We should switch context so the ISR returns to a different task. // NOTE: How this is done depends on the port you are using. Check // the documentation and examples for your port. taskYIELD (); } }

//portEND_SWITCHING_ISR 参考

Note that interrupts must NOT use API functions that do not end in \

Mutex type semaphores cannot be used from within interrupt service routines. 由于存在优先级问题,所以在中断中不使用

API的选择问题: TASK有3套 ? 全特性的API ? 替代的API

? ISR中使用的轻量级的API

COROUTINE有

自己的一套,不能与TASK混用 ? xCoRoutineHandle ? xCoRoutineCreate ? crDELAY

? crQUEUE_SEND ? crQUEUE_RECEIVE

? crQUEUE_SEND_FROM_ISR ? crQUEUE_RECEIVE_FROM_ISR ? vCoRoutineSchedule

自定义:裁减

#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 configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 #define configCHECK_FOR_STACK_OVERFLOW 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 INCLUDE_uxTaskGetStackHighWaterMark 0

#define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1

内存管理的三种方法: ? 只分配 不回收 ? 分配佳回收

? C库函数中的分配及回收

堆栈检查功能

vApplicationStackOverflowHook 也有两种方式,检查指针大小,检查内存数据

任务创建 xTaskCreate vTaskDelete

任务控制 vTaskDelay

vTaskDelayUntil uxTaskPriorityGet vTaskPrioritySet vTaskSuspend vTaskResume

vTaskResumeFromISR

vTaskSetApplicationTag (多一个参数)

xTaskCallApplicationTaskHook 从中断中调用

内核控制

taskYIELD swi实现 taskENTER_CRITICAL taskEXIT_CRITICAL

taskDISABLE_INTERRUPTS taskENABLE_INTERRUPTS

vTaskStartScheduler vTaskEndScheduler

vTaskSuspendAll 禁止调度,但没有禁止TICK xTaskResumeAll 开始调度

任务工具

xTaskGetCurrentTaskHandle

uxTaskGetStackHighWaterMark (最高水位) xTaskGetTickCount xTaskGetSchedulerState uxTaskGetNumberOfTasks vTaskList (列出所有任务的状态,到缓冲区中) vTaskStartTrace ulTaskEndTrace

vTaskSetApplicationTag (多一个数据 多一个函数) xTaskCallApplicationTaskHook (任务钩子函数)

队列操作

uxQueueMessagesWaiting (等待的数目) vQueueDelete xQueueCreate xQueueSend

xQueueSendToBack xQueueSendToFront xQueueReceive xQueuePeek (只看 不删除) xQueueSendFromISR (需注意发送导致的任务切换操作) xQueueSendToBackFromISR xQueueSendToFrontFromISR xQueueReceiveFromISR

信号量操作

vSemaphoreCreateBinary vSemaphoreCreateCounting

xSemaphoreCreateMutex 带优先级

xSemaphoreTake (MUTEX也通过Sem的操作函数进行操作) xSemaphoreGive

xSemaphoreGiveFromISR(MUTEX的不行)

xSemaphoreCreateRecursiveMutex xSemaphoreTakeRecursive xSemaphoreGiveRecursive

MUTEX类型的不允许在中断中使用

CO ROUTINE控制 xCoRoutineHandle xCoRoutineCreate crDELAY

crQUEUE_SEND crQUEUE_RECEIVE

crQUEUE_SEND_FROM_ISR crQUEUE_RECEIVE_FROM_ISR vCoRoutineSchedule

不要使用任何形式的开关中断函数,portEXIT_CRITICAL().

而用portENTER_CRITICAL() and

本文来源:https://www.bwwdw.com/article/7962.html

Top