FreeRTOS 任务的创建 (4)

前言
  1. 本博文基于FreeRTOS V9.0.0和MDK环境;
  2. 本博文属于野火学习笔记,如有不足之处还请多多指教;
任务的大三元素

先说几个基本概念:
任务: 相当于裸机大循环系统中的每个独立功能;例如LED和USART功能都可以作为一个单独的任务来说;
任务执行和裸机执行的区别: 裸机是顺序执行来完成总任务,而RTOS是通过任务的切换来完成;

①:任务函数 (独立函数,无限循环)
任务函数是最终实现功能的地方;

 void task_entry (void *parg)
 {
	 /* 任务主体,无限循环且不能返回 */
	 for (;;) {
	 /* 任务主体代码 */
	 }
 }

②:任务控制块TCB
每一个任务都有一个TCB,在程序中,TCB是任务的身份证,TCB结构体内包含着任务的重要信息;

typedef struct tskTaskControlBlock
{
	volatile StackType_t    *pxTopOfStack;    /*栈顶*/
	ListItem_t               xStateListItem;   /*任务节点*/
	StackType_t 		    *pxStack;					/*任务栈起始地址*/
	char					pcTaskName[ configMAX_TASK_NAME_LEN ];   /*任务名称,字符串形式*/
}tskTCB;

③任务栈(静态栈/动态栈)
每个任务都有一个独立的任务栈,用来临时存储截点信息,属于软件堆栈;

//静态栈
#define TASK1_STACK_SIZE							128  
StackType_t Task1Stack[TASK1_STACK_SIZE];

//动态栈:暂无
任务的创建流程

在这里插入图片描述
代码如下:

  	TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,   //任务函数名
					                const char * const pcName,   //配置任务名
									const uint32_t ulStackDepth, //任务堆栈尺寸(32位为单位)
									void * const pvParameters,   //任务参数;
									UBaseType_t uxPriority,		 //任务优先级 (野火这里对源程序有改动)
									StackType_t * const puxStackBuffer, //任务堆栈缓冲区起始地址
									TCB_t * const pxTaskBuffer   //任务控制块起始地址;(野火在这里对源程序有改动)
																 )
	{
		TCB_t *pxNewTCB;
		TaskHandle_t xReturn;  //建立一个任务句柄
		
		if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer ) )
		{
			pxNewTCB = ( TCB_t * )pxTaskBuffer;
			pxNewTCB->pxStack = ( StackType_t * )puxStackBuffer;
			
			//建立新的任务
			prvInitialiseNewTask( pxTaskCode,
							      pcName,
								  ulStackDepth,
								  pvParameters,
								  &xReturn,
								  pxNewTCB
								);
			
		}
		else
			xReturn = NULL;
		
		
		//返回任务句柄,如果任务创建成功,此时XReturn应该指向任务控制块
		return xReturn;
		
	}

//新任务初始化函数
void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
													 const char * const pcName,
													 const uint32_t ulStackDepth,
													 void *const pvParameters,
													TaskHandle_t *const pxCreatedTask,
													TCB_t *pxNewTCB		
													)
{
	StackType_t *pxTopOfStack;
	UBaseType_t x;
	
	/**********初始化TCB*************/
	//获取栈顶地址
	pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t )1 );
	//栈顶地址乡下做8字节对齐
	pxTopOfStack = ( StackType_t * )( ( ( uint32_t )pxTopOfStack )&(~(( uint32_t )0x007)) );
	//将任务的名字存储在TCB中
	for( x = ( UBaseType_t )0; x < ( UBaseType_t )configMAX_TASK_NAME_LEN; x++ )
	{
		pxNewTCB->pcTaskName[ x ] = pcName[x];
		
		if( pcName[x] == 0x00	)
			break;
		
	}
	//任务名字长度不能超过configMAX_TASK_NAMW_LEN
	pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';
	
	/************初始化任务栈****************/
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack,
											        pxTaskCode,
													pvParameters);
	
	
	
	//让任务句柄指向任务控制块
	if( ( void *)pxCreatedTask != NULL)
	{
		*pxCreatedTask = ( TaskHandle_t )pxNewTCB;
	}
}

//定义任务栈初始初始化函数
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, //此时进来的栈顶指针已经是指向栈顶的8字节对齐指针;
																		TaskFunction_t pxCode,     //任务函数名
																		void *pvParameters				 //任务参数
																		)
{
	//异常发生时,自动加载到CPU寄存器的内容;
	pxTopOfStack--;
	*pxTopOfStack = portINITIAL_XPSR;
	pxTopOfStack--;
	*pxTopOfStack = ( ( StackType_t )pxCode )&portSTART_ADDRESS_MASK;
	pxTopOfStack--;
	*pxTopOfStack = ( StackType_t )prvTaskExitError;
	pxTopOfStack -= 5;
	*pxTopOfStack = ( StackType_t )pvParameters;
	
	//异常发生时,手动加载CPU寄存器的内容;
	pxTopOfStack -= 8;
	
	//返回栈顶指针,此时pxTopOfStack指向空闲栈;
	return pxTopOfStack;
	
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值