void vTaskDelete( TaskHandle_t xTask );//形参是句柄
//任务优先级
#define XXX_TASK_PRIO 1
//任务堆栈大小
#define XXX_STK_SIZE 128
//任务句柄
TaskHandle_t XXXTask_Handler = NULL;
/*
* 放在开始任务,只需要执行一次为了创建任务
*/
void Create_XXX_Task(void)
{
BaseType_t xReturned;
//创建XXX任务
xReturned = xTaskCreate((TaskFunction_t )XXX_Task,
(const char* )"XXX_Task",
(uint16_t )XXX_STK_SIZE,
(void* )NULL,
(UBaseType_t )XXX_TASK_PRIO,
(TaskHandle_t* )&XXXTask_Handler);
//判断任务是否正常创建
if( xReturned != pdPASS)
{
/* 任务创建失败 一般原因是栈空间不够 */
vTaskDelete( XXXTask_Handler );
/* 打印创建失败消息---使用宏定义选择性使用,一般就是调试的时候使用 */
#if 0
printf("xxxx失败");
#endif
}
}
/*
* 任务函数
*/
void XXX_Task(void *pvParameters)
{
while(1)
{
}
}
1:高优先级得任务必须存在阻塞状态,一个任务得大部分时间是处于阻塞状态得
2:对于新建工程以及新建任务,其任务得堆栈大小和优先级先配置为128和1,后面再调与改
1:任务切换函数taskYIELD()
作用:切换任务(可手动切换任务)
我们知道当优先级任务相同的时候,每个任务运行的时间为一个时间片,假如我们此时的任务只需要0.5ms就可以了,不需要1ms,那么我们就可以手动切换任务了
taskYIELD() 用于请求切换上下文到另一个任务。 但是, 除非存在其他任务,其优先级等于或高于调用 taskYIELD() 的任务的优先级, 否则 RTOS 调度器将选择 调用了 taskYIELD() 的任务并使其再次运行。
2:临界段保护代码函数
//任务使用 void taskENTER_CRITICAL( void ); void taskEXIT_CRITICAL( void );场景:很重要的代码,不允许被其他中断打断,比如我这里是数据处理,而有一个任务是数据判断 ,我必须此时先处理数据才能有效,不然就浪费了一次 要求:执行代码必须要短,不能花很长时间 taskENTER_CRITICAL(); /*执行语句代码*/ taskEXIT_CRITICAL();
//中断使用 UBaseType_t taskENTER_CRITICAL_FROM_ISR( void ); void taskEXIT_CRITICAL_FROM_ISR( UBaseType_t uxSavedInterruptStatus );使用在中断中,与任务不同的事情是需要单独定义一个变量(模板) 使用起来与任务一样 UBaseType_t save_state; save_state = taskENTER_CRITICAL_FROM_ISR(); /*执行语句代码*/ taskEXIT_CRITICAL_FROM_ISR(save_state);
注意点:
临界区必须保持非常短,否则将影响 更高优先级的中断的响应时间,会导致该中断嵌套。 每次 taskENTER_CRITICAL_FROM_ISR() 调用都必须紧密配taskEXIT_CRITICAL_FROM_ISR() 调用一起使用。
不得从临界区调用 FreeRTOS API 函数。
1:xTaskCreate
2:vTaskDelete
void vTaskDelete( TaskHandle_t xTask );//形参是句柄
INCLUDE_vTaskDelete 必须定义为 1 才能使用此函数
此函数的作用为从 RTOS 内核管理中移除任务。被删除的任务将从所有的就绪、阻塞、挂起和事件的列表中移除。
请注意,空闲任务负责从已删除任务中释放 RTOS 内核分配的内存。因此,重要的是,如果您的应用程序调用了 vTaskDelete (),空闲任务不会失去微控制器处理时间。任务代码分配的内存(相当于自己malloc的内存)不会自动释放,并且应在删除任务之前释放。
if( XXXTask_Handler != NULL ) { /* 这样写是防止输出重复删除任务,任务只能删除一次,不然会打印错误信息 */ vTaskDelete( XXXTask_Handler ); printf("任务删除"); XXXTask_Handler = NULL; //然后此任务会在空闲任务中回收资源, }
1:vTaskDelay
void vTaskDelay( const TickType_t xTicksToDelay );必须将 INCLUDE_vTaskDelay 定义为 1,此函数才可用
形参是多少个tick,因此不要觉得是多少个ms,只不过我们学的时候,一直是1tick就是1ms,因此初学会误认为这个函数是专门延时ms的
非周期延时
2:vTaskDelayUntil
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement
INCLUDE_vTaskDelayUntil 必须被定义为 1 才能使用此函数
// Perform an action every 10 ticks. void vTaskFunction( void * pvParameters ) { TickType_t xLastWakeTime; const TickType_t xFrequency = 10; // Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount(); for( ;; ) { // Wait for the next cycle. vTaskDelayUntil( &xLastWakeTime, xFrequency ); // Perform action here. } }周期延时
3:uxTaskPriorityGet
作用:获取任务的优先级
原型:UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ); //返回值为typedef unsigned long UBaseType_t;
返回值:优先级
使用步骤如下:
#define INCLUDE_uxTaskPriorityGet 1UBaseType_t TaskPriority_Num = 0;
TaskPriority_Num = uxTaskPriorityGet( xHandle );//uxTaskPriorityGet( NULL );
printf("%ld",TaskPriority_Num);4:vTaskPrioritySet
作用:改变任务的优先级
原型:void vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t uxNewPriority );
使用步骤如下:
#define INCLUDE_vTaskPrioritySet 1
UBaseType_t TaskNewPriority_Num = 20; //TaskNewPriority_Num的范围为0-31(推荐是最大优先级数为32)
vTaskPrioritySet(xHandle,TaskNewPriority_Num); //vTaskPrioritySet(NULL,TaskNewPriority_Num);5:vTaskResume和vTaskSuspend
中断的恢复稍微复杂一点点
* 挂起和恢复函数模板使用 */ /* 宏置一 */ //挂起不支持嵌套,多次挂起,一次恢复就可以了 //任务 vTaskResume(XXXTask_Handler); --无返回值 vTaskSuspend(XXXTask_Handler);--无返回值 //中断 BaseType_t xYieldRequired; /* 恢复被挂起的任务 */ xYieldRequired = xTaskResumeFromISR( XXXTask_Handler ); if ( xYieldRequired == pdTRUE ) { /* 执行上下文切换, ISR 返回的时候将运行另外一个任务 */ portYIELD_FROM_ISR(); }
调试使用的函数目的:分析我们分配的堆栈空间和优先级是否符合
1:vTaskList
void vTaskList( char *pcWriteBuffer )参数:
pcWriteBuffer 一个缓冲区, 上面提到的细节将以 ASCII 形式写入其中。假设此缓冲区 的大小足以容纳产生的报告。 大约为每个任务分配 40 字节的缓冲区就足够了。 这一个函数基本就可以显示每个任务的基本信息了,我们一般关心的就只有Stack
X:表示运行态
你看下面的使用是很简单的,给足空间直接打印即可
统计运行时间和每一个任务函数运行的时间
1:xQueueCreate
QueueHandle_t xQueue1 = NULL; #define QUEUE1_LENGTH 3 #define QUEUE1_ITEMSIZE sizeof(uint8_t) void vATask( void *pvParameters ) { /* Create a queue capable of containing 10 unsigned long values. */ xQueue1 = xQueueCreate( QUEUE1_LENGTH , QUEUE1_ITEMSIZE ); if( xQueue1 == NULL ) { /* Queue was not created and must not be used. */ vQueueDelete(xQueue1 ); //创建失败,需要打印错误信息,一般因为空间不够而无法正确 } }
2:xQueueSend
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
它等同于 xQueueSendToBack()作用就是将信息送至队列(从尾部送入)
参数:
x队列 队列的句柄,数据项将发布到此队列。 pvItemToQueue 指向待入队数据项的指针。创建队列时定义了队列将保留的项的大小,因此固定数量的字节将从 pvItemToQueue 复制到队列存储区域。 xTicksToWait 如果队列已满,则任务应进入阻塞态等待队列上出现可用空间的最大时间。如果队列已满,并且 xTicksToWait 设置为0 ,调用将立即返回。时间在 tick 周期中定义,因此如果需要,应使用常量 portTICK_PERIOD_MS 转换为实时。 如果 INCLUDE_vTaskSuspend 设置为 “1” ,则将阻塞时间指定为 portMAX_DELAY 会导致任务无限期地阻塞(没有超时)。
Returns:如果成功发布,返回 pdTRUE,否则返回 errQUEUE_FULL
if( xQueueSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdTURE ) { /* Failed to post the message, even after 10 ticks. */ //打印发送错误信息 }
如何学好FreeRTOS
学会看懂官网给的信息
This page describes the RTOS uxTaskPriorityGet() FreeRTOS API function which is part of the RTOS task control API. FreeRTOS is a professional grade, small footprint, open source RTOS for microcontrollers.
如果忘记了,重新看一遍就行,基础知识其实很少,忘记了就来查找就行