Live2d Test Env

任务创建与删除

1. 任务创建函数 

复制代码
// 创建任务的内存由 RAM 在 heap上动态分配
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
          const char * const pcName,
          unsigned short usStackDepth,
          void *pvParameters,
          UBaseType_t uxPriority,
          TaskHandle_t *pxCreatedTask );
/*注
FreeRTOSConfig.h 中 configSUPPORT_DYNAMIC_ALLOCATION 设为 1
#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请
*/

//创建任务保存数据的内存由 writer 控制
TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
          const char * const pcName,
          uint32_t ulStackDepth,
          void *pvParameters,
          UBaseType_t uxPriority,
          StackType_t * const puxStackBuffer,
          StaticTask_t * const pxTaskBuffer );

/*
example
*/

/* Define a structure called xStruct and a variable of type xStruct. These are just used to 
demonstrate a parameter being passed into a task function. */
typedef struct A_STRUCT
{
 char cStructMember1;
 char cStructMember2;
} xStruct; 
 
/* Define a variable of the type xStruct to pass as the task parameter. 定义一个参数传给任务*/
xStruct xParameter = { 1, 2 };
 
/* Define the task that will be created. Note the name of the function that implements the task 
is used as the first parameter in the call to xTaskCreate() below. */
void vTaskCode( void * pvParameters )
{
    xStruct *pxParameters;
 
     /* Cast the void * parameter back to the required type. 任务接收到创建任务时传递的参数指针*/
     pxParameters = ( xStruct * ) pvParameters;
 
     /* The parameter can now be accessed as expected. */
     if( pxParameters->cStructMember1 != 1 )
     {
         /* Etc. */
     } 
 
     /* Enter an infinite loop to perform the task processing. */
     for( ;; )
     {
         /* Task code goes here. */
     }
} 
/* Define a function that creates a task. This could be called either before or after the 
scheduler has been started. */
void vAnotherFunction( void )
{
    TaskHandle_t xHandle;
 
     /* Create the task. */
     if( pdPASS != xTaskCreate( 
           vTaskCode, /* Pointer to the function that implements the task. */
           "Demo task", /* Text name given to the task. */
           STACK_SIZE, /* The size of the stack that should be created for the task. This is defined in words, not bytes. */
           (void*) &xParameter,/* A reference to xParameters is used as the task parameter.This is cast to a void * to prevent compiler warnings.此处将定义的参数地址传入 */
        TASK_PRIORITY, /* The priority to assign to the newly created task. */
        &xHandle /* The handle to the task being created will be placed in xHandle. */
    ) ) 
 {
 /* The task could not be created as there was insufficient heap memory remaining. If
 heap_1.c, heap_2.c or heap_4.c are included in the project then this situation can be 
 trapped using the vApplicationMallocFailedHook() callback (or ‘hook’) function, and the 
 amount of FreeRTOS heap memory that remains unallocated can be queried using the
 xPortGetFreeHeapSize() API function.*/
 }
 else
 {
 /* The task was created successfully. The handle can now be used in other API functions,
 for example to change the priority of the task.*/
 vTaskPrioritySet( xHandle, 2 );
 } 
}


/*static creat*/
/* Dimensions the buffer that the task being created will use as its stack. NOTE: This is the number of words the stack will hold, not the number of bytes. For example, if each stack item is 32-bits, and this is set to 100, then 400 bytes (100 * 32-bits) will be allocated. */ #define STACK_SIZE 200 /* Structure that will hold the TCB of the task being created. */ StaticTask_t xTaskBuffer; /* Buffer that the task being created will use as its stack. Note this is an array of StackType_t variables. The size of StackType_t is dependent on the RTOS port. */ StackType_t xStack[ STACK_SIZE ]; /* Function that implements the task being created. */ void vTaskCode( void * pvParameters ) { /* The parameter value is expected to be 1 as 1 is passed in the pvParameters parameter in the call to xTaskCreateStatic(). */ configASSERT( ( uint32_t ) pvParameters == 1UL ); for( ;; ) { /* Task code goes here. */ } } /* Function that creates a task. */ void vFunction( void ) {   TaskHandle_t xHandle = NULL;   /* Create the task without using any dynamic memory allocation. */   xHandle = xTaskCreateStatic(   vTaskCode, /* Function that implements the task. */   "NAME", /* Text name for the task. */   STACK_SIZE, /* The number of indexes in the xStack array. */   ( void * ) 1, /* Parameter passed into the task. */   tskIDLE_PRIORITY,/* Priority at which the task is created. */   xStack, /* Array to use as the task's stack. */   &xTaskBuffer ); /* Variable to hold the task's data structure. */   /* puxStackBuffer and pxTaskBuffer were not NULL, so the task will have been created, and   xHandle will be the task's handle. Use the handle to suspend the task. */   vTaskSuspend( xHandle ); }
复制代码

  使用  xTaskCreateStatic 进行任务创建时,FreeRTOSConfig.h  中设置    #define configSUPPORT_STATIC_ALLOCATION         1  

且在main.c(也可以是其他源文件) 中创建空闲任务和定时模块堆栈变量 

复制代码
#if configSUPPORT_STATIC_ALLOCATION
/* 空闲任务任务堆栈 */
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];

/* 空闲任务控制块 */ 
static StaticTask_t IdleTaskTCB; 

/* 定时器服务任务堆栈 */ 
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; 

/* 定时器服务任务控制块 */ 
static StaticTask_t TimerTaskTCB;
                     
#endif


#if configSUPPORT_STATIC_ALLOCATION


/** 
* @brief 获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的静态内存,因此空闲任务的任务堆栈和任务控制块的内存就由用户提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()实现此函数即可。
* @param ppxIdleTaskTCBBuffer:任务控制块内存
         ppxIdleTaskStackBuffer:任务堆栈内存
         pulIdleTaskStackSize:任务堆栈大小
* @retval 无 
*/ 
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) 
{ 
    *ppxIdleTaskTCBBuffer = &IdleTaskTCB;
    *ppxIdleTaskStackBuffer = IdleTaskStack; 
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; 
} 
/**
* @brief 获取定时器服务任务的任务堆栈和任务控制块内存
* @param ppxTimerTaskTCBBuffer:任务控制块内存
         ppxTimerTaskStackBuffer:任务堆栈内存
         pulTimerTaskStackSize:任务堆栈大小
* @retval 无 
*/ 
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) 
{ 
    *ppxTimerTaskTCBBuffer = &TimerTaskTCB;
    *ppxTimerTaskStackBuffer = TimerTaskStack;
    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; 
}
                 
#endif
复制代码

参数传递:

  任务创建的时候,有一个参数用于向任务传递 data,类型是void *,任务中使用的时候,根据数据类型进行强转。

 

2. 任务挂起和恢复

复制代码
vTaskSuspend(Task1_Handler);
vTaskResume(Task1_Handler);
 
//如果用户打算采用这个函数实现中断与任务的同步,要注意一种情况,如果此函数的调用优先于函数
//vTaskSuspend 被调用,那么此次同步会丢失,这种情况下建议使用信号量来实现同步。
//此函数是用于中断服务程序中调用的
xTaskResumeFromISR(xHandleTask); 
if (KEY0_PRES == keyTemp)
        {
            if (NULL != Task1_Handler)
            {
                printf("Task1_Handler suspend\r\n");
                vTaskSuspend(Task1_Handler);
            }
        }
        else if (KEY1_PRES == keyTemp)
        {
            if (NULL != Task1_Handler)
            {
                printf("Task1_Handler resum\r\n");
                vTaskResume(Task1_Handler);
            }    
        }
        else
        {

        }        
复制代码

 

实验现象:

按键触发任务挂起时,任务1 挂起,停止输出;

按键触发任务恢复时,任务1运行,开始输出;

 

3. 任务删除

复制代码
//任务删除函数接口

vTaskDelete(Task1_Handler);


     if
(KEY0_PRES == keyTemp) { if (NULL != Task1_Handler) { // printf("Task1_Handler suspend\r\n"); // vTaskSuspend(Task1_Handler); printf("Task1_Handler delete\r\n"); vTaskDelete(Task1_Handler); } } else if (KEY1_PRES == keyTemp) { if (NULL != Task1_Handler) { // printf("Task1_Handler resum\r\n"); // vTaskResume(Task1_Handler); printf("Task1_Handler recreat\r\n"); CreatTask(); } } else if (KEY2_PRES == keyTemp) { infoPrintf(); }


void CreatTask(void)
{
   xTaskCreate((TaskFunction_t )TaskCreat_1,            //任务函数
                (const char*    )"TaskCreat_1",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&Task1_Handler);       //任务句柄
}
 
uint8_t pcWriteBuffer[500];
void infoPrintf(void)
{
    printf("=================================================\r\n");
    printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
    vTaskList((char *)&pcWriteBuffer);
    printf("%s\r\n", pcWriteBuffer);
    printf("\r\n 任务名 运行计数 使用率\r\n");
    vTaskGetRunTimeStats((char *)&pcWriteBuffer);
    printf("%s\r\n", pcWriteBuffer);
}
 
//注
/*
使用vTaskGetRunTimeStats接口时,在 FreeRTOSConfig.h 中开启  
#define configGENERATE_RUN_TIME_STATS           1  
同时定义以下内容
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks = 0ul)  //计时变量 ulHighFrequencyTimerTicks 在定时器中,用于统计任务运行时间,一般要求是任务节拍的10倍,该变量一般用于调试阶段,因为该任务会降低整体系统的实时性。
#define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks  
*/
 
复制代码

 

 实验现象:

  

 4. 关闭、开启中断

taskDISABLE_INTERRUPTS( void );
taskENABLE_INTERRUPTS( void );

  这两个配套使用,中间代码尽可能的短,保证系统的实时性。

  如果没有使能宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 和 configMAX_API_CALL_INTERRUPT_PRIORITY,调用这两个函数将禁用全局中断。

  否则,调用 taskDISABLE_INTERRUPTS 将禁用 configMAX_SYSCALL_INTERRUPT_PRIORITY 优先级下的中断,而优先级比其高的中断并不会被禁用。

  这两个函数不支持嵌套,即无论调用几次disable,只要调用一次 enable,就会开启中断,如果需要嵌套,使用下面的进入临界区接口

5. 任务临界区

//任务中使用下面函数进入临界区
taskENTER_CRITICAL( void );
taskEXIT_CRITICAL( void );
//中断中使用下面的配套函数
taskENTER_CRITICAL_FROM_ISR( void );
taskEXIT_CRITICAL_FROM_ISR();

  进入临界区的代码是保持多任务共享数据的原子性,应该尽可能的短。

  通过禁用中断实现,禁用中断范围同4,根据 configMAX_SYSCALL_INTERRUPT_PRIORITY 值来定。

  支持嵌套,这两个函数必须配套使用

  临界区不能调用FreeRTOS API。

6.  xTaskNotifyWait

复制代码
 u int32_t ulBitsToClearOnExit,
 uint32_t *pulNotificationValue,
 TickType_t xTicksToWait );


void vAnEventProcessingTask( void *pvParameters )
{
uint32_t ulNotifiedValue;
 for( ;; )
 {
 /* Block indefinitely (without a timeout, so no need to check the function's
 return value) to wait for a notification.
 Bits in this RTOS task's notification value are set by the notifying
 tasks and interrupts to indicate which events have occurred. */
 xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
 ULONG_MAX, /* Reset the notification value to 0 on exit. */
 &ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
 portMAX_DELAY ); /* Block indefinitely. */
 /* Process any events that have been latched in the notified value. */
 if( ( ulNotifiedValue & 0x01 ) != 0 )
 {
 /* Bit 0 was set - process whichever event is represented by bit 0. */
 prvProcessBit0Event();
 }
 if( ( ulNotifiedValue & 0x02 ) != 0 )
 {
 /* Bit 1 was set - process whichever event is represented by bit 1. */
 prvProcessBit1Event();
 }
 if( ( ulNotifiedValue & 0x04 ) != 0 )
 {
 /* Bit 2 was set - process whichever event is represented by bit 2. */
 prvProcessBit2Event();
 }
 /* Etc. */
 }
}
复制代码

  如果该任务处于block状态,触发数据接收到后,就会接触block状态到 ready状态。

其他API

   

复制代码
xTaskGetCurrentTaskHandle()  //获取当前任务的句柄
/*
INCLUDE_xTaskGetIdleTaskHandle must be set to 1 in FreeRTOSConfig.h for 
xTaskGetIdleTaskHandle() to be available.
*/
xTaskGetIdleTaskHandle( void ); 

xTaskGetHandle( const char *pcNameToQuery );  //任务在创建时,有一个字符串参数 pcName,通过它进行查找该任务的任务句柄
 uxTaskGetNumberOfTasks( void );
  vTaskGetRunTimeStats( char *pcWriteBuffer );
  xTaskGetSchedulerState( void );
  uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
  eTaskGetState( TaskHandle_t pxTask );
  UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
                      const UBaseType_t uxArraySize,
                      unsigned long * const pulTotalRunTime );
 
 
 
 
复制代码

 

posted @   爬上那个坡  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示