FreeRTOS原函数库API

参考资料

1:API翻译
2:原文

任务

xTaskCreateStatic静态任务创建

1:任务使用的栈和任务控制块都使用静态内存,即预先定义好的全局变量,这些预先定义好的全局变量都存在内部的 SRAM 中。
2:任务的栈占用的是 MCU 内部的 RAM,当任务越多的时候,需要使用的栈空间就越大,即需要使用的RAM 空间就越多。一个 MCU 能够支持多少任务,就得看你的 RAM 空间有多少
3:将任务主体函数,任务栈(静态的)和任务控制块(静态的)这三者联系在一起,让任务可以随时被系统启动
4:自己需要预先创建任务堆栈,任务控制块,任务句柄

/* LED任务堆栈 */
static StackType_t LED_Task_Stack[128];//StackType_t ->portSTACK_TYPE -> uint32_t
/* AppTaskCreate 任务控制块 */
static StaticTask_t LED_Task_TCB; 
/* LED任务句柄 */
static TaskHandle_t LED_Task_Handle;


/* 创建LED_Task任务 */
LED_Task_Handle = xTaskCreateStatic((TaskFunction_t	)LED_Task,		//任务函数
									(const char* 	)"LED_Task",		//任务名称
									(uint32_t 		)128,				//任务堆栈大小,单位为字,128×4字节
									(void* 		  	)NULL,			//传递给任务函数的参数
									(UBaseType_t 	)4, 	//任务优先级,数值越大优先级越高,0 代表最低优先级
									(StackType_t*   )LED_Task_Stack,//任务堆栈,任务栈起始地址,只有在使用静态内存的时候才需要提供,在使用动态内存的时候会根据提供的任务栈大小自动创建
									(StaticTask_t*  )&LED_Task_TCB);//任务控制块,任务控制块指针,在使用静态内存的时候,需要给任务初始化函数 xTaskCreateStatic()传递预先定义好的任务控制块的指针。在使用动态内存的时候,任务创建函数 xTaskCreate()会返回一个指针指向任务控制块,该任务控制块是 xTaskCreate()函数里面动态分配的一块内存   


static void LED_Task(void* parameter)
{
   	
    while (1)
    {
   
        LED1_ON;
        vTaskDelay(500);   /* 延时500个tick */
        printf("LED_Task Running,LED1_ON\r\n");
        
        LED1_OFF;     
        vTaskDelay(500);   /* 延时500个tick */		 		
        printf("LED_Task Running,LED1_OFF\r\n");
    }
}

xTaskCreate动态任务创建

1:在创建单任务—SRAM 静态内存的例程中,任务控制块和任务栈的内存空间都是从内部的 SRAM 里面分配的,具体分配到哪个地址由编译器决定。现在我们开始使用动态内存,即堆,其实堆也是内存,也属于 SRAM。FreeRTOS 做法是在 SRAM 里面定义一个大数组,也就是堆内存,供 FreeRTOS 的动态内存分配函数使用,在第一次使用的时候,系统会将定义的堆内存进行初始化,这些代码在 FreeRTOS 提供的内存管理方案中实现(heap_1.c、heap_2.c、heap_4.c 等,具体的内存管理方案后面详细讲解)
2:只需创建任务句柄,任务句柄就是指向任务控制块的

BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS,这个没什么意义,操作的是 AppTaskCreate_Handle*/

 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;//TaskHandle_t 就是一个空指针typedef void * TaskHandle_t;

/* 创建AppTaskCreate任务 */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */
                        (const char*    )"AppTaskCreate",/* 任务名字 */
                        (uint16_t       )512,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )1, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务句柄,指向任务控制块 */ 


static void AppTaskCreate(void)
{
   
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  
  taskENTER_CRITICAL();           //进入临界区
  
  /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */
                        (const char*    )"LED1_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED1_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED1_Task任务成功!\r\n");
  
	/* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */
                        (const char*    )"LED2_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )3,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED2_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED2_Task任务成功!\r\n");
  
  vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  
  taskEXIT_CRITICAL();            //退出临界区
}

vTaskStartScheduler()启动任务,开启调度

int main(void)
{
   
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	 
	uart_init(115200);					//初始化串口
	KEY_Init();							//初始化按键
	BEEP_Init();						//初始化蜂鸣器
	my_mem_init(SRAMIN);            	//初始化内部内存池

	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

vTaskDelete 任务删除函数

  • vTaskDelete()用于删除一个任务。当一个任务删除另外一个任务时,形参为要删除任 务创建时返回的任务句柄,如果是删除自身,则形参为 NULL。
  • 删除的任务将从所有就绪,阻塞,挂起和事件列表中删除
  • 要想使用该函数必须在FreeRTOSConfig.h 中把 INCLUDE_vTaskDelete 定义为 1

案例1:

 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;

vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务

案例2:

	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
//开始任务任务函数
void start_task(void *pvParameters)
{
   
    taskENTER_CRITICAL();           //进入临界区
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )malloc_task,             
                (const char*    )"malloc_task",           
                (uint16_t       )MALLOC_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )MALLOC_TASK_PRIO,        
                (TaskHandle_t*  )&MallocTask_Handler);   
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

挂起任务

相当于暂停某个任务。

  • 当某个任务要停止运行一段时间的话就将这个任务挂起当。
  • 要重新运行这个任务的话就恢复这个任务的运行。

vTaskSuspend挂起任务

1:挂起指定任务。被挂起的任务绝不会得到CPU的使用权,不管该任务具有什么优先级。
参数:任务句柄
2:任务可以调用 vTaskSuspend()这个函数来挂起任务自身,但是在挂起自身的时候会进行一次任务上下文切换,需要挂起自身就将 xTaskToSuspend 设置为 NULL 传递进来即可。
3:可以用来暂停某个任务运行一段时间,其内部的资源都会保留下来,如果该任务的优先级是当前就绪态优先级最高的任务,那么立即会按照挂起前的任务状态继续执行该任务(就是说,挂起任务之前是什么状态,都会被系统保留下来,在恢复的瞬间,继续执行)
4:无论任务在挂起时候调用过多少次这个vTaskSuspend()函数,也只需调用一次 vTaskResume ()函数即可将任务恢复运行

      vTaskSuspend(LED_Task_Handle);/* 挂起LED任务 ,传入任务句柄,NULL来挂起自己*/
#if ( INCLUDE_vTaskSuspend == 1 )

	void vTaskSuspend( TaskHandle_t xTaskToSuspend )
	{
   
	TCB_t *pxTCB;

		taskENTER_CRITICAL();
		{
   
			/* If null is passed in here then it is the running task that is
			being suspended. */
			pxTCB = prvGetTCBFromHandle( xTaskToSuspend );//利用任务句柄来获得对应的任务控制块#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )

			traceTASK_SUSPEND( pxTCB );

			/* Remove task from the ready/delayed list and place in the
			suspended list. */
			if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
			{
   
				taskRESET_READY_PRIORITY( pxTCB->uxPriority );
			}
			else
			{
   
				mtCOVERAGE_TEST_MARKER();
			}

			/* 如果任务在等待事件,也将任务从等待事件中移除 */
			if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
			{
   
				( void ) uxListRemove( &( pxTCB->xEventListItem ) );
			}
			else
			{
   
				mtCOVERAGE_TEST_MARKER();
			}

			vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );//将任务添加到挂起列表中
		}
		taskEXIT_CRITICAL();

		if( xSchedulerRunning != pdFALSE )
		{
   
			/* 重置下一个任务的解除阻塞时间 */
			taskENTER_CRITICAL();
			{
   
				prvResetNextTaskUnblockTime();
			}
			taskEXIT_CRITICAL();
		}
		else
		{
   
			mtCOVERAGE_TEST_MARKER();
		}

		if( pxTCB == pxCurrentTCB )//如果挂起的是当前运行中的任务,并且调度器已经是运行的,则需要立即切换任务。不然系统的任务就错乱了,这是不允许的。
		{
   
			if( xSchedulerRunning != pdFALSE )
			{
   
				/* The current task has just been suspended. */
				configASSERT( uxSchedulerSuspended == 0 );
				 /* 调度器在运行时,如果这个挂起的任务是当前任务,立即切换任务。 */
				portYIELD_WITHIN_API();
			}
			else
			{
   
				/* The scheduler is not running, but the task that was pointed
				to by pxCurrentTCB has just been suspended and pxCurrentTCB
				must be adjusted to point to a different task. */
				if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
				{
   
					/* No other tasks are ready, so set pxCurrentTCB back to
					NULL so when the next task is created pxCurrentTCB will
					be set to point to it no matter what its relative priority
					is. */
					pxCurrentTCB = NULL;
				}
				else
				{
   
					vTaskSwitchContext();
				}
			}
		}
		else
		{
   
			mtCOVERAGE_TEST_MARKER();
		}
	}

#endif /* INCLUDE_vTaskSuspend */

vTaskSuspendAll 挂起所有任务

1:挂起所有任务就是挂起任务调度器。调度器被挂起后则不能进行上下文切换,但是中断还是使能的。当调度器被挂起的时候,如果有中断需要进行上下文切换,那么这个中断将会被挂起,在调度器恢复之后才响应这个中断
2:这个函数是可以进行嵌套的,调度器恢复可以调用 xTaskResumeAll()函数,调用了多少次的 vTaskSuspendAll()就要调用多少次xTaskResumeAll()进行恢复

void vTaskSuspendAll( void )
{
   
	/*uxSchedulerSuspended 用于记录调度器是否被挂起,该变量默认初始值为 pdFALSE,表明调度器是没被挂起的,每调用一次 vTaskSuspendAll()函数就将变量加一,用于记录调用了多少次vTaskSuspendAll()函数 */
	++uxSchedulerSuspended;
}

vTaskResume任务恢复函数

1:任务恢复就是让挂起的任务重新进入就绪状态,恢复的任务会保留挂起前的状态信息,在恢复的时候根据挂起时的状态继续运行。如果被恢复任务在所有就绪态任务中,处于最高优先级列表的第一位,那么系统将进行任务上下文的切换。
2:无论任务在挂起时候调用过多少次这个vTaskSuspend()函数,也只需调用一次 vTaskResume ()函数即可将任务恢复运行

#if ( INCLUDE_vTaskSuspend == 1 )

	void vTaskResume( TaskHandle_t xTaskToResume )
	{
   
	TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;// 根据 xTaskToResume 获取对应的任务控制块

		/* 检查要恢复的任务是否被挂起,如果没被挂起,恢复调用任务没有意义 */
		configASSERT( xTaskToResume );

		/*TCB指针不能为NULL(肯定要已经挂起的任务才需要恢复),同时要恢复的任务不能是当前正在运行的任务(因为正在运行的任务不需要恢复) */
		if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
		{
   
			taskENTER_CRITICAL();//进入临界区
			{
   
				if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )//判断要恢复的任务是否真的被挂起了
				{
   
					traceTASK_RESUME( pxTCB );

					/* 将要恢复的任务从挂起列表(xSuspendedTaskList)中删除,恢复任务就是将要恢复的任务从挂起列表中删除 */
					( void ) uxListRemove(  &( pxTCB->xStateListItem ) );
					/* 将要恢复的任务添加到就绪列表(pxReadyTasksLists)中去 */
					prvAddTaskToReadyList( pxTCB );

					/* We may have just resumed a higher priority task. 
					如果刚刚恢复的任务优先级比当前任务优先级更高则需要进行任务的切换*/
					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
					{
   
						/* 调用taskYIELD_IF_USING_PREEMPTION进行一次任务切换*/
						taskYIELD_IF_USING_PREEMPTION();

你可能感兴趣的:(FreeRTOS,stm32,c语言,物联网)