目前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 传入函数入口地址,函数入口参数,配置的属性结构体
以动态创建函数为例。在各种判断后最终执行动态创建函数
在动态创建函数中,初始化堆栈,然后根据该任务的优先级插入到对应的优先级列表中,尾插法插入,
新加入的同优先级的任务放在尾部。
所做的正是插入链表的算法。
最后在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 (最低优先级,且空闲任务永远礼让给别的优先级任务哪怕在空闲链表里得到执行也会主动礼让。)