基于STM32结合CubeMX学习Free-RT-OS的源码之任务创建

任务创建

        目前free rt os与cube mx 结合地非常好,让开发都变得简单起来,就是因为它实在是太优雅了(总而言之就是太懂程序员了),让不少开发者STM32开发都离不开CUBE MX的自动配置。

        创建任务有两种方式,与RT-Thread一样,动态创建和静态创建两种,它们的区别在于每个任务(线程)所分配的任务栈是系统自动分配还是自己指定一块内存区域(通常以静态数组的形式)。

这里在配置的时候需要注意的在于

1.StackSize(任务栈大小),它是以字为单位,所以真正的大小应该为其4倍字节数。

2.任务栈是从RAM上分配下来的,这个RAM大小有多大看芯片的说明手册。另外CUBEMX在配置的时候回给一个默认的总的堆大小。

总的堆大小:这个值需要用户自己随着任务分配自己去修改,任务的栈是从这个总的堆上瓜分下来的(在创建任务时标记任务栈顶的地址以及栈大小为一个任务的任务栈)

关于这里堆栈的称呼实际上是一个意思,这与平时我们所说堆栈不同。在这里它们都是内存RAM的部分,任务栈从系统设定的总的堆大小上分配出来一块区域(一块数组)作为栈。504=4*96+其他属性信息所占内存大小(比如说任务的入口函数地址,任务的名字,任务的优先级大小,任务的任务栈大小等等)

在FreeRTOSConfig.h里进行配置。裁剪出用户自定义的一些配置(比如OS的心跳(systick的中断函数,idle的钩子函数,定时器的最大深度等等)),其中就包括所定义的总的堆大小。

创建任务

 使用封装的一个函数 osThreadNew 传入函数入口地址,函数入口参数,配置的属性结构体

以动态创建函数为例。在各种判断后最终执行动态创建函数 

在动态创建函数中,初始化堆栈,然后根据该任务的优先级插入到对应的优先级列表中,尾插法插入,

新加入的同优先级的任务放在尾部。 

所做的正是插入链表的算法。

  1. 获取当前尾结点(尾结点是一个空的结点),它的前继永远执行真正的最后一个结点。新结点的后继为尾结点。
  2. 新结点(新创建的任务)的前继为尾结点的前继结点(旧链表的最后一个任务)。
  3. 尾结点的前继的后继也就是旧链表的最后一个任务结点的后继为当前新结点。
  4. 更新尾结点的前继为当前任务结点。

 

最后在main函数里开启调度。

开启调度时创建一个空闲任务。

关于空闲任务:

空闲线程的入口函数

static portTASK_FUNCTION( prvIdleTask, pvParameters )
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
	/* Stop warnings. */
	( void ) pvParameters;

	/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
	SCHEDULER IS STARTED. **/

	/* In case a task that has a secure context deletes itself, in which case
	the idle task is responsible for deleting the task's secure context, if
	any. */
	portTASK_CALLS_SECURE_FUNCTIONS();

	for( ;; )
	{
		/* See if any tasks have deleted themselves - if so then the idle task
		is responsible for freeing the deleted task's TCB and stack. */
		prvCheckTasksWaitingTermination();

		#if ( configUSE_PREEMPTION == 0 )
		{
			/* If we are not using preemption we keep forcing a task switch to
			see if any other task has become available.  If we are using
			preemption we don't need to do this as any task becoming available
			will automatically get the processor anyway. */
			taskYIELD();
		}
		#endif /* configUSE_PREEMPTION */

		#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
		{
			/* When using preemption tasks of equal priority will be
			timesliced.  If a task that is sharing the idle priority is ready
			to run then the idle task should yield before the end of the
			timeslice.

			A critical region is not required here as we are just reading from
			the list, and an occasional incorrect value will not matter.  If
			the ready list at the idle priority contains more than one task
			then a task other than the idle task is ready to execute. */
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
			{
				taskYIELD();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */

		#if ( configUSE_IDLE_HOOK == 1 )
		{
			extern void vApplicationIdleHook( void );

			/* Call the user defined function from within the idle task.  This
			allows the application designer to add background functionality
			without the overhead of a separate task.
			NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
			CALL A FUNCTION THAT MIGHT BLOCK. */
			vApplicationIdleHook();
		}
		#endif /* configUSE_IDLE_HOOK */

		/* This conditional compilation should use inequality to 0, not equality
		to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
		user defined low power mode	implementations require
		configUSE_TICKLESS_IDLE to be set to a value other than 1. */
		#if ( configUSE_TICKLESS_IDLE != 0 )
		{
		TickType_t xExpectedIdleTime;

			/* It is not desirable to suspend then resume the scheduler on
			each iteration of the idle task.  Therefore, a preliminary
			test of the expected idle time is performed without the
			scheduler suspended.  The result here is not necessarily
			valid. */
			xExpectedIdleTime = prvGetExpectedIdleTime();

			if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
			{
				vTaskSuspendAll();
				{
					/* Now the scheduler is suspended, the expected idle
					time can be sampled again, and this time its value can
					be used. */
					configASSERT( xNextTaskUnblockTime >= xTickCount );
					xExpectedIdleTime = prvGetExpectedIdleTime();

					/* Define the following macro to set xExpectedIdleTime to 0
					if the application does not want
					portSUPPRESS_TICKS_AND_SLEEP() to be called. */
					configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );

					if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
					{
						traceLOW_POWER_IDLE_BEGIN();
						portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
						traceLOW_POWER_IDLE_END();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				( void ) xTaskResumeAll();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_TICKLESS_IDLE */
	}
}

空闲任务的优先级永远是0 (最低优先级,且空闲任务永远礼让给别的优先级任务哪怕在空闲链表里得到执行也会主动礼让。) 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值