1.我们使用8位单片机,比如AVR,最常用的做法是在main函数里使用while(1)循环, 状态机以及中断服务函数来实现应用程序. 这样的系统不涉及到任务的概念或者说while(1)里每一个函数调用就是一个任务,叫做前后台程序,中断服务函数作为前台程序,while(1)循环作为后台程序.这种做法的好处是实现简单,代码占用小,坏处是实时性差.下图是前后台程序的示意图.
2.我们还有另外一种选择,就是使用操作系统,比如FreeRTOS. 为了解决上面那种裸机开发的弊端--实时性差,我们通过创建多个任务,将紧急的任务优先级设置相对高一点,不紧急的任务优先级设置相对低一点, 高优先级的任务可以从低优先级任务手中抢占CPU的使用权,保证紧急任务能够优先运行.下图是抢占式操作系统中任务的调度示意图.
3.FreeRTOS的4种任务状态切换如下图所示,且任务必定处于图中所示状态中的一种. 任何时刻只有一个任务处于Running状态.
4.FreeRTOS任务的优先级可以为0~(configMAX_PRIORITIES-1)范围内的任何一个值. 数字越小,优先级越低,0是最低优先级;数字越大,优先级越高,configMAX_PRIORITIES-1是最高优先级.空闲任务的优先级为0.
5.FreeRTOS任务函数原型如下:
void ATaskFunction( void *pvParameters );
FreeRTOS任务函数的典型结构如下. 任务函数不能返回,要么是一个无限循环,要么在函数退出之前执行vTaskDelete( NULL );.
void ATaskFunction( void *pvParameters )
{
/* Variables can be declared just as per a normal function. Each instance
of a task created using this function will have its own copy of the
iVariableExample variable. This would not be true if the variable was
declared static – in which case only one copy of the variable would exist
and this copy would be shared by each created instance of the task. */
int iVariableExample = 0;
/* A task will normally be implemented as in infinite loop. */
for( ;; )
{
/* The code to implement the task functionality will go here. */
}
/* Should the task implementation ever break out of the above loop
then the task must be deleted before reaching the end of this function.
The NULL parameter passed to the vTaskDelete() function indicates that
the task to be deleted is the calling (this) task. */
vTaskDelete( NULL );
}
6.FreeRTOS使用TCB_t结构体存储任务的相关属性.
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock {
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS
MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
#if (portUSING_MPU_WRAPPERS == 1)
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND
MEMBER OF THE TCB STRUCT. */
#endif
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of
that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[configMAX_TASK_NAME_LEN];
/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified
char types are allowed
for strings and single
characters only. */
#if ((portSTACK_GROWTH > 0) || (configRECORD_STACK_HIGH_ADDRESS == 1))
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif
#if (portCRITICAL_NESTING_IN_TCB == 1)
UBaseType_t
uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count
in the port layer. */
#endif
#if (configUSE_TRACE_FACILITY == 1)
UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to
determine when a task has been deleted and then recreated. */
UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
#endif
#if (configUSE_MUTEXES == 1)
UBaseType_t
uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
UBaseType_t uxMutexesHeld;
#endif
#if (configUSE_APPLICATION_TASK_TAG == 1)
TaskHookFunction_t pxTaskTag;
#endif
#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0)
void *pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS];
#endif
#if (configGENERATE_RUN_TIME_STATS == 1)
uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
#endif
#if (configUSE_NEWLIB_REENTRANT == 1)
/* Allocate a Newlib reent structure that is specific to this task.
Note Newlib support has been included by popular demand, but is not
used by the FreeRTOS maintainers themselves. FreeRTOS is not
responsible for resulting newlib operation. User must be familiar with
newlib and must provide system-wide implementations of the necessary
stubs. Be warned that (at the time of writing) the current newlib design
implements a system-wide malloc() that must be provided with locks. */
struct _reent xNewLib_reent;
#endif
#if (configUSE_TASK_NOTIFICATIONS == 1)
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
/* See the comments above the definition of
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE \
!= 0) /*lint !e731 Macro has been consolidated for readability reasons. */
uint8_t
ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to
free the memory. */
#endif
#if (INCLUDE_xTaskAbortDelay == 1)
uint8_t ucDelayAborted;
#endif
} tskTCB;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;
7.FreeRTOS的任务调度器在进行任务切换的时候会先将当前运行任务的现场(如通用寄存器等)保存在此任务的任务堆栈中,等到此任务下次运行的时候会用堆栈中保存的数据恢复现场,恢复现场以后任务就会接着上次断开的的地方运行. 任务堆栈的地址保存在TCB_t中.
|