目录
在MCU的设计与开发中有以下常见的程序结构设计:
其实一般情况下能上RTOS一般就上RTOS,根本不需要考虑时间片轮询的情况,斟酌使用时间片轮询的情况主要的考虑有以下几点:
使用时间片轮询时要注意的点:
其中,任务调度表中包含了任务编号(或者可以设计成表中的索引)、回调的任务函数、任务类型(周期或者事件类型)、任务开关、任务状态(包括执行后的状态)、任务时间片计数、任务时间片初始值
- /******************************************
- * OS Task No
- ******************************************/
- #define OS_TASK_NO1 0
- #define OS_TASK_NO2 1
- #define OS_TASK_NO3 2
- #define OS_TASK_NO4 3
- #define OS_TASK_NO5 4
- #define OS_TASK_NO6 5
- #define OS_TASK_NO7 6
- #define OS_TASK_NO8 7
-
- #define OS_TASK_MAX_NO 8
-
- /******************************************
- * OS Task switch
- ******************************************/
- #define OS_TASK_OFF 0
- #define OS_TASK_ON 1
-
- /******************************************
- * OS Task Type
- ******************************************/
- #define OS_TASK_EVENT 0
- #define OS_TASK_CYCLC 1
-
- /******************************************
- * OS Task Status
- ******************************************/
- #define OS_TASK_OK 0
- #define OS_TASK_READY 1
- #define OS_TASK_ERROR 2
-
- /******************************************
- * Struct and Enum
- ******************************************/
- typedef struct
- {
- uint8_t os_task_number;
- uint8_t (*taskFunc)(void);
- uint8_t os_task_type;
- uint8_t os_task_switch;
- uint8_t os_task_status;
- uint8_t os_task_tickCnt;
- uint8_t os_task_tickInit;
-
- }OS_TASK_SCHEDULE_t;
- void OS_TmrIsrTask(void)
- {
- uint8_t indx = 0;
-
- OS_DISABLE_INTERRUPT();
- for(indx = 0; indx < osTaskScheduleCfgSize; indx++)
- {
- if(osTaskScheduleCfg[indx].os_task_switch == OS_TASK_ON &&\
- osTaskScheduleCfg[indx].os_task_status != OS_TASK_READY)
- {
- if(osTaskScheduleCfg[indx].os_task_tickCnt > 0)
- {
- osTaskScheduleCfg[indx].os_task_tickCnt--;
- }
-
- if(osTaskScheduleCfg[indx].os_task_tickCnt == 0)
- {
- osTaskScheduleCfg[indx].os_task_status = OS_TASK_READY;
-
- switch(osTaskScheduleCfg[indx].os_task_type)
- {
- case OS_TASK_CYCLC:
- {
- osTaskScheduleCfg[indx].os_task_tickCnt = osTaskScheduleCfg[indx].os_task_tickInit;
- break;
- }
- case OS_TASK_EVENT:
- {
- break;
- }
- }
-
- }
-
- }
- }
- OS_ENABLE_INTERRUPT();
- }
任务的启停:
- void OS_TaskTmrEventStart(uint8_t task_number)
- {
- uint8_t indx = 0;
-
- OS_DISABLE_INTERRUPT();
- for(indx = 0; indx <= osTaskScheduleCfgSize; indx++)
- {
- if(task_number == osTaskScheduleCfg[indx].os_task_number)
- {
- osTaskScheduleCfg[indx].os_task_switch = OS_TASK_ON;
- osTaskScheduleCfg[indx].os_task_tickCnt = osTaskScheduleCfg[indx].os_task_tickInit;
-
- break;
- }
- }
- OS_ENABLE_INTERRUPT();
-
- }
-
- void OS_TaskTmrEventStop(uint8_t task_number)
- {
- uint8_t indx = 0;
-
- OS_DISABLE_INTERRUPT();
- for(indx = 0; indx <= osTaskScheduleCfgSize; indx++)
- {
- if(task_number == osTaskScheduleCfg[indx].os_task_number)
- {
- osTaskScheduleCfg[indx].os_task_switch = OS_TASK_OFF;
- osTaskScheduleCfg[indx].os_task_tickCnt = 0;
-
- break;
- }
- }
- OS_ENABLE_INTERRUPT();
- }
- void OS_StartSchedule(void)
- {
- uint8_t indx;
-
- for(;;)
- {
- for(indx = 0; indx < osTaskScheduleCfgSize; indx++)
- {
- switch(osTaskScheduleCfg[indx].os_task_status)
- {
- case OS_TASK_OK:
- {
- break;
- }
- case OS_TASK_ERROR:
- {
- break;
- }
- case OS_TASK_READY:
- {
- OS_DISABLE_INTERRUPT();
- if(osTaskScheduleCfg[indx].taskFunc != NULL)
- {
- osTaskScheduleCfg[indx].os_task_status = osTaskScheduleCfg[indx].taskFunc();
-
- if(osTaskScheduleCfg[indx].os_task_type == OS_TASK_EVENT)
- {
- osTaskScheduleCfg[indx].os_task_switch = OS_TASK_OFF;
- }
-
- }
- OS_ENABLE_INTERRUPT();
- break;
- }
- }
- }
- }
- }
- /*********************************************
- * OS Task Schedule Config
- *********************************************/
- OS_TASK_SCHEDULE_t osTaskScheduleCfg[] =
- {
- /* level taskFunc task_type task_switch os_task_status task_tickCnt task_tickInit */
- {OS_TASK_NO1, os_task1, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 0, 100 },
- {OS_TASK_NO2, os_task2, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 1, 100 },
- {OS_TASK_NO3, os_task3, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 2, 100 },
- {OS_TASK_NO4, os_task4, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 3, 100 },
- {OS_TASK_NO5, os_task5, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 4, 100 },
- {OS_TASK_NO6, os_task6, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 5, 100 },
- {OS_TASK_NO7, os_task7, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 6, 100 },
- {OS_TASK_NO8, os_task8, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 7, 100 },
-
- };
-
- uint8_t osTaskScheduleCfgSize = sizeof(osTaskScheduleCfg) / sizeof(OS_TASK_SCHEDULE_t);
-
- /******************************************
- * User Task Function
- ******************************************/
- uint8_t os_task1(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task2(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task3(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task4(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task5(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task6(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task7(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
-
- uint8_t os_task8(void)
- {
- /* do something */
-
- return OS_TASK_OK
- }
上述设计中,当两个任务同时Ready的时候,仅会按照顺序进行处理。当一些业务功能有优先级功能区分的时候,就无法满足这样的需求,这时候就要对上述设计进行改进。
在原来任务调度表的基础上再新增一个优先级调度表结构体,设计如下:包含优先级(索引)、任务调度表、任务调度表长度、就绪任务的编号FIFO。
(注:就绪任务队列中存放着已经准备就绪的任务编号)
- typedef struct
- {
- uint8_t head;
- uint8_t tail;
- uint8_t buf[OS_READY_FIFO_MAX];
-
- }OS_RdyNoFifo_t;
-
- typedef struct
- {
- uint8_t os_task_number;
- uint8_t (*taskFunc)(void);
- uint8_t os_task_type;
- uint8_t os_task_switch;
- uint8_t os_task_status;
- uint8_t os_task_tickCnt;
- uint8_t os_task_tickInit;
-
- }OS_TASK_SCHEDULE_t;
-
- typedef struct
- {
- uint8_t prio_number;
- OS_TASK_SCHEDULE_t *osTaskScheduleCfg;
- uint8_t *osTaskScheduleCfgSize;
- OS_RdyNoFifo_t *osRdyNofifoBuf;
-
- }OS_PRIO_SCHEDULE_t;
假如我们需要8层的优先级,我们可以以1个字节中的每一位来充当1级优先级。数值越大,则优先级越高。设计如下:
- /*******************************************************************
- * OS Priority Schedule Number(Index)
- *******************************************************************/
- #define OS_PRIO_LEVEL_1 0
- #define OS_PRIO_LEVEL_2 1
- #define OS_PRIO_LEVEL_3 2
- #define OS_PRIO_LEVEL_4 3
- #define OS_PRIO_LEVEL_5 4
- #define OS_PRIO_LEVEL_6 5
- #define OS_PRIO_LEVEL_7 6
- #define OS_PRIO_LEVEL_8 7
-
- #define OS_PRIO_LEVEL_MAX 8
-
- #define OS_PRIO_VAL_LEVEL(x) (1 << (7 - x))
- #define OS_PRIO_VAL_LEVEL_1 (1 << (7 - OS_PRIO_LEVEL_1))
- #define OS_PRIO_VAL_LEVEL_2 (1 << (7 - OS_PRIO_LEVEL_2))
- #define OS_PRIO_VAL_LEVEL_3 (1 << (7 - OS_PRIO_LEVEL_3))
- #define OS_PRIO_VAL_LEVEL_4 (1 << (7 - OS_PRIO_LEVEL_4))
- #define OS_PRIO_VAL_LEVEL_5 (1 << (7 - OS_PRIO_LEVEL_5))
- #define OS_PRIO_VAL_LEVEL_6 (1 << (7 - OS_PRIO_LEVEL_6))
- #define OS_PRIO_VAL_LEVEL_7 (1 << (7 - OS_PRIO_LEVEL_7))
- #define OS_PRIO_VAL_LEVEL_8 (1 << (7 - OS_PRIO_LEVEL_8))
以2层优先级为例,LEVEL_1与LEVEL_2,则有以下几种情况:
- // 仅LEVEL1 任务产生
- priority = 0x80;
-
- // 仅LEVEL2 任务产生
- priority = 0x40;
-
- // LEVEL1和LEVEL2任务同时产生,此时要先执行LEVEL1的任务
- priority = 0xC0;
优先级计算函数:
- static bool OS_isScheduleExistTask(OS_RdyNoFifo_t *osRdyNofifoBuf)
- {
- bool ret = false;
- if(osRdyNofifoBuf->head != osRdyNofifoBuf->tail)
- {
- ret = true;
- }
- return ret;
- }
-
-
- static uint8_t OS_SchedulePrioCal(void)
- {
- uint8_t indx = 0;
- uint8_t prio_number = 0;
- uint8_t priority = 0;
- OS_RdyNoFifo_t *osRdyNofifoBuf;
-
- for(indx = 0; indx < osTaskPrioScheduleCfgSize; indx++)
- {
- osRdyNofifoBuf = osTaskPrioScheduleCfg[indx].osRdyNofifoBuf;
- prio_number = osTaskPrioScheduleCfg[indx].prio_number;
-
- if(OS_isScheduleExistTask(osRdyNofifoBuf))
- {
- priority += OS_PRIO_VAL_LEVEL(prio_number);
- }
- }
-
- return priority;
- }
任务调度表与优先级调度表的配置
- /*********************************************
- * OS Task Ready FIFO Config
- *********************************************/
- OS_RdyNoFifo_t OsRdyFifoLv1 = {0};
- OS_RdyNoFifo_t OsRdyFifoLv2 = {0};
-
- /***********************************************************************
- * OS Task Schedule Config (include priority level)
- ***********************************************************************/
- OS_TASK_SCHEDULE_t osTaskScheduCfg_Lv1[] =
- {
- /* number taskFunc task_type task_switch os_task_status task_tickCnt task_tickInit */
- {OS_TASK_NO1, os_task1, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 0, 100 },
- {OS_TASK_NO2, os_task2, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 1, 100 },
- {OS_TASK_NO3, os_task3, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 2, 100 },
- };
-
- OS_TASK_SCHEDULE_t osTaskScheduCfg_Lv2[] =
- {
- /* number taskFunc task_type task_switch os_task_status task_tickCnt task_tickInit */
- {OS_TASK_NO1, os_task4, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 0, 100 },
- {OS_TASK_NO2, os_task5, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 1, 100 },
- {OS_TASK_NO3, os_task6, OS_TASK_CYCLC, OS_TASK_ON, OS_TASK_OK, 2, 100 },
- };
-
- uint8_t osTaskScheduleCfgSize_Lv1 = sizeof(osTaskScheduCfg_Lv1) / sizeof(OS_TASK_SCHEDULE_t);
- uint8_t osTaskScheduleCfgSize_Lv2 = sizeof(osTaskScheduCfg_Lv2) / sizeof(OS_TASK_SCHEDULE_t);
-
- /***********************************************************************
- * OS Task Priority Schedule
- ***********************************************************************/
- OS_PRIO_SCHEDULE_t osTaskPrioScheduleCfg[] =
- {
- /* prio_number osTaskScheduleCfg osTaskScheduleCfgSize osRdyNofifoBuf */
- {OS_PRIO_LEVEL_1, &osTaskScheduCfg_Lv1, &osTaskScheduleCfgSize_Lv1, &OsRdyFifoLv1},
- {OS_PRIO_LEVEL_2, &osTaskScheduCfg_Lv2, &osTaskScheduleCfgSize_Lv2, &OsRdyFifoLv2},
- };
-
- uint8_t osTaskPrioScheduleCfgSize = sizeof(osTaskPrioScheduleCfg) / sizeof(OS_PRIO_SCHEDULE_t);
时间片轮询处理函仅做少数改动,遍历整张优先级表的同时,将Ready的任务Push到任务就绪队列中。
- void OS_TmrIsrTask(void)
- {
- uint8_t indx, taskCfgSize, task_i;
- OS_TASK_SCHEDULE_t * osTaskScheduleCfg;
- OS_RdyNoFifo_t * osRdyFifo;
-
- OS_DISABLE_INTERRUPT();
- for(indx = 0; indx < osTaskPrioScheduleCfgSize; indx++)
- {
- osTaskScheduleCfg = osTaskPrioScheduleCfg[indx].osTaskScheduleCfg;
- taskCfgSize = *osTaskPrioScheduleCfg[indx].osTaskScheduleCfgSize;
- osRdyFifo = osTaskPrioScheduleCfg[indx].osRdyNofifoBuf;
-
- for(task_i = 0; task_i < taskCfgSize; task_i++)
- {
- if(osTaskScheduleCfg[task_i].os_task_switch == OS_TASK_ON &&\
- osTaskScheduleCfg[task_i].os_task_status != OS_TASK_READY)
- {
- if(osTaskScheduleCfg[task_i].os_task_tickCnt > 0)
- {
- osTaskScheduleCfg[task_i].os_task_tickCnt--;
- }
-
- if(osTaskScheduleCfg[task_i].os_task_tickCnt == 0)
- {
- osTaskScheduleCfg[task_i].os_task_status = OS_TASK_READY;
-
- if(OS_PushRdyTask(osRdyFifo, osTaskScheduleCfg[task_i].os_task_number) != OS_FIFO_OK)
- {
- /* push error dispose */
- }
-
- switch(osTaskScheduleCfg[task_i].os_task_type)
- {
- case OS_TASK_CYCLC:
- {
- osTaskScheduleCfg[task_i].os_task_tickCnt = osTaskScheduleCfg[task_i].os_task_tickInit;
- break;
- }
- case OS_TASK_EVENT:
- {
- break;
- }
- }
-
-
- }
-
- }
-
- }
-
- }
- OS_ENABLE_INTERRUPT();
-
- }
任务调度函数则需要先计算优先级,看优先处理哪一张任务调度表,再去从对应优先级的任务就绪队列中Pop出任务编号,然后执行对应任务。
- static void OS_StartPrioSchedule(uint8_t prio_number)
- {
- uint8_t prio_i, task_i;
- uint8_t task_number, osTaskScheduleCfgSize;
- OS_TASK_SCHEDULE_t * osTaskScheduleCfg;
- OS_RdyNoFifo_t * osRdyFifo;
-
- OS_DISABLE_INTERRUPT();
-
- osTaskScheduleCfg = osTaskPrioScheduleCfg[prio_number].osTaskScheduleCfg;
- osTaskScheduleCfgSize = *osTaskPrioScheduleCfg[prio_number].osTaskScheduleCfgSize;
- osRdyFifo = osTaskPrioScheduleCfg[prio_number].osRdyNofifoBuf;
-
- if(OS_PopRdyTask(osRdyFifo, &task_number) == OS_FIFO_OK)
- {
- switch(osTaskScheduleCfg[task_number].os_task_status)
- {
- case OS_TASK_OK:
- {
- break;
- }
- case OS_TASK_ERROR:
- {
- break;
- }
- case OS_TASK_READY:
- {
- osTaskScheduleCfg[task_number].os_task_status = osTaskScheduleCfg[task_number].taskFunc();
- if(osTaskScheduleCfg[task_number].os_task_type == OS_TASK_EVENT)
- {
- osTaskScheduleCfg[task_number].os_task_switch = OS_TASK_OFF;
- }
- break;
- }
- }
- }
- OS_ENABLE_INTERRUPT();
- }
-
-
-
- void OS_StartSchedule(void)
- {
- uint8_t indx;
- uint8_t priority;
- uint8_t task_number;
-
- for(;;)
- {
- /* Calculate the Schedule Priority */
- priority = OS_SchedulePrioCal();
- if(priority >= OS_PRIO_VAL_LEVEL_1)
- {
- OS_StartPrioSchedule(OS_PRIO_LEVEL_1);
- }
- else if(priority >= OS_PRIO_VAL_LEVEL_2)
- {
- OS_StartPrioSchedule(OS_PRIO_LEVEL_2);
- }
- }
- }