打印
[PIC®/AVR®/dsPIC®产品]

(二)FreeRTOS任务介绍

[复制链接]
1370|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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中.






987835d088910d6019.png (51.46 KB )

987835d088910d6019.png

184225d088dfac03cc.png (116.4 KB )

184225d088dfac03cc.png

使用特权

评论回复
沙发
643757107| | 2019-6-18 22:58 | 只看该作者
教程不错,学习。

使用特权

评论回复
板凳
小卡| | 2019-6-20 11:03 | 只看该作者
不错啊~ 这个好

使用特权

评论回复
地板
天灵灵地灵灵| | 2019-6-20 23:26 | 只看该作者
很棒

使用特权

评论回复
5
lcczg| | 2019-6-25 11:32 | 只看该作者
好,继续。

使用特权

评论回复
6
zhuotuzi| | 2019-6-26 00:36 | 只看该作者
好移植吗

使用特权

评论回复
7
奔波儿熊|  楼主 | 2019-6-26 10:57 | 只看该作者

如果在同系列(主要是同内核)之间移植,还算好移植. 不同系列之间就不好移植了.

使用特权

评论回复
8
pzsh| | 2019-6-28 10:07 | 只看该作者
FreeRTOS相对uCOS来说,就是参考的文件和书籍少了点。

使用特权

评论回复
9
aoyi| | 2019-7-25 11:21 | 只看该作者
是不是所有型号单片机流程都差不多啊

使用特权

评论回复
10
drer| | 2019-7-25 14:05 | 只看该作者
讲解的非常详细

使用特权

评论回复
11
jinniuxing| | 2019-11-29 16:53 | 只看该作者
谢谢分享!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

503

帖子

2

粉丝