我是靠谱客的博主 有魅力砖头,这篇文章主要介绍基于STM32的RTOS简易分析-混合式调度一、双向链表的实现二、同优先级轮转调度设计三、仿真验证,现在分享给大家,希望可以做个参考。

        FreeRTOS和Ucos中不同优先级的任务运行时采用的是抢占式调度,同一优先级下有多个任务需要运行时,则对同优先级的任务进行时间片轮转调度。将抢占式调度和时间片轮转调度联合使用就是混合式调度。

        在 RTOS 中,最小的时间单位为一个Tick,即 SysTick 的中断周期, 同优先级轮转调度时Ucos可以指定每个任务运行多少个 Tick,但是FreeRTOS的任务运行时间片是固定的一个Tick,不可调整。在Ucos中若优先级0下有两个任务A和B,任务时间片设置为10ms,SysTick 的中断周期为1ms。则系统运行结果 是A运行10ms后切换B运行10ms然后再切换为任务A运行如此反复。在FreeRTOS中则是A运行1ms切换任务B运行1ms再切换任务A运行。

        为了方便在同一优先级下面挂载与删除任务,RTOS的任务控制块当中(Task Control Block TCB)中引入了双向链表结构。FreeRTOS和Ucos任务控制块结构体如下,本例程中模仿FreeRTOS中链表的用法来实现双向循环链表。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*FreeRTOS*/ 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. */ ... ... ... } /*Ucos*/ struct os_tcb { CPU_STK *StkPtr; /* Pointer to current top of stack */ void *ExtPtr; /* Pointer to user definable data for TCB extension */ CPU_STK *StkLimitPtr; /* Pointer used to set stack 'watermark' limit */ OS_TCB *NextPtr; /* Pointer to next TCB in the TCB list */ OS_TCB *PrevPtr; /* Pointer to previous TCB in the TCB list */ OS_TCB *TickNextPtr; OS_TCB *TickPrevPtr; ... ... ... }

一、双向链表的实现

        网上关于双向循环链表的教程有很多,这里不再叙述链表的实现过程直接贴代码。推荐B站上的两个视频教程,一个是关于C语言指针的《强烈推荐】4小时彻底掌握C指针 - 顶尖程序员图文讲解 - UP主翻译校对 (已完结)》,另一个是关于数据结构的《【强烈推荐】深入浅出数据结构 - 顶尖程序员图文讲解 - UP主翻译校对 (已完结)》,讲师是一个印度小哥,讲解的很不错。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
typedef struct STRUCT_NODE { struct STRUCT_NODE* next; struct STRUCT_NODE* prev; void* pOwner; /* Pointer to a TCB that contains the node */ }Node,*NodePtr; typedef struct STRUCT_LIST { UINT16 nodeCount; NodePtr pHeadNode; }List,*ListPtr; /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void NodeInit(NodePtr pNode,void* pOwner) { pNode->next = pNode; pNode->prev = pNode; pNode->pOwner = pOwner; } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void ListInit(ListPtr pList) { pList->pHeadNode = NULL; pList->nodeCount = 0; } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void ListInsertAtHead(ListPtr pList,NodePtr pNode) { if(pList->pHeadNode == NULL) { pList->pHeadNode = pNode; pList->nodeCount++; return ; } pList->pHeadNode->prev->next = pNode; pNode->next = pList->pHeadNode; pNode->prev = pList->pHeadNode->prev; pList->pHeadNode->prev = pNode; pList->pHeadNode = pNode; pList->nodeCount++; } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void ListInsertAtTail(ListPtr pList,NodePtr pNode) { if(pList->pHeadNode == NULL) { pList->pHeadNode = pNode; pList->nodeCount++; return ; } pList->pHeadNode->prev->next = pNode; pNode->next = pList->pHeadNode; pNode->prev = pList->pHeadNode->prev; pList->pHeadNode->prev = pNode; pList->nodeCount++; } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ NodePtr ListPopHead(ListPtr pList) { NodePtr pTmpNode = NULL; if(pList->pHeadNode == NULL) { return NULL; } pTmpNode = pList->pHeadNode; pList->pHeadNode = pTmpNode->next; pList->pHeadNode->prev = pTmpNode->prev; pTmpNode->prev->next = pList->pHeadNode; pList->nodeCount--; return pTmpNode; } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void ListRemoveNode(ListPtr pList, NodePtr pNode) { pNode->prev->next = pNode->next; pNode->next->prev = pNode->prev; NodeInit(pNode,pNode->pOwner); pList->nodeCount--; }

二、同优先级轮转调度设计

        任务控制块中增加链表节点变量和时间片设置变量,当设置的任务运行时间片为0时,就采用系统缺省值代替0。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
typedef struct STRUCT_TASK_TCB { UINT32 *stackPtr; /*Points to the location of the last item placed on the tasks stack*/ Node taskTcbNode; UINT8 priority; /*The priority of the task. 0 is the highest priority*/ UINT8 timeSliceSet; UINT8 timeSlice; }TaskTcb,*TaskTcbPtr; List taskTcbPtrPrioTbl[OS_TASK_MAX_PRIORITIES + 1]; /********************************************************************************************** * @brief TaskCreate * * @param None * @retval None **********************************************************************************************/ void TaskCreate(TaskTcb *pTcb, FunPtr pTaskFun, UINT32* pTaskStack, UINT32 stackSize, UINT8 taskPrio, UINT8 timeSlice) { UINT32 *pStack; UINT32 cnt; for(cnt = 0; cnt < stackSize*sizeof(UINT32);cnt++)/* Fill the stack with a known value to assist debugging. */ { *((UINT8*)pTaskStack + cnt) = OS_STACK_FILL_BYTE; } pStack = &pTaskStack[stackSize];/* Get top address of stack, because grows from high memory to low*/ pStack = (UINT32 *)((UINT32)(pStack) & 0xFFFFFFF8u);/* AAPCS(ARM application procedure all standard) Align the stack to 8bytes */ /*Registers stacked as if auto-saved on exception*/ *(--pStack) = (UINT32)0x01000000uL; /*xPSR bit24 thumb state bit*/ *(--pStack) = (UINT32)pTaskFun; /*Entry Point(PC)*/ *(--pStack) = (UINT32)0x12121212uL; /*R14 (LR)*/ *(--pStack) = (UINT32)0x12121212uL; /* R12*/ *(--pStack) = (UINT32)0x03030303uL; /* R3*/ *(--pStack) = (UINT32)0x02020202uL; /* R2*/ *(--pStack) = (UINT32)0x01010101uL; /* R1*/ *(--pStack) = (UINT32)0x00000000u; /* R0*/ /*Remaining registers saved on process stack*/ *(--pStack) = (UINT32)0x11111111uL; /* R11*/ *(--pStack) = (UINT32)0x10101010uL; /* R10*/ *(--pStack) = (UINT32)0x09090909uL; /* R9*/ *(--pStack) = (UINT32)0x08080808uL; /* R8*/ *(--pStack) = (UINT32)0x07070707uL; /* R7*/ *(--pStack) = (UINT32)0x06060606uL; /* R6*/ *(--pStack) = (UINT32)0x05050505uL; /* R5*/ *(--pStack) = (UINT32)0x04040404uL; /* R4*/ pTcb->stackPtr = pStack; pTcb->priority = taskPrio; if(timeSlice != 0) pTcb->timeSliceSet = timeSlice; else pTcb->timeSliceSet = OS_TASK_DEFAULT_TIME_SLICE; pTcb->timeSlice = pTcb->timeSliceSet; NodeInit(&pTcb->taskTcbNode, pTcb); ListInsertAtTail(&taskTcbPtrPrioTbl[taskPrio], &pTcb->taskTcbNode); BitMapSetBit(&taskPrioBitMap, taskPrio); }

        将taskTcbPtrPrioTbl由上一章的任务控制块指针数组修改为双向链表数组,并修改相应的函数。在OsTaskStart函数中自动获取最高优先级任务的控制块指针并启动任务运行。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void TaskScheduleInit(void) { UINT8 i = 0; for(i = 0; i < OS_TASK_MAX_PRIORITIES + 1; i++) { ListInit(&taskTcbPtrPrioTbl[i]); } BitMapInit(&taskPrioBitMap); } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void OsTaskStart(void) { UINT8 highestPrio = BitMapFirstGet(&taskPrioBitMap); pOsHighRdyTcb = (TaskTcbPtr)(taskTcbPtrPrioTbl[highestPrio].pHeadNode->pOwner); OSStartHighRdy(); } /********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void TaskSchedule(void) { UINT8 prio = BitMapFirstGet(&taskPrioBitMap); if((TaskTcbPtr)(taskTcbPtrPrioTbl[prio].pHeadNode->pOwner) != pOsCurTcb) { pOsHighRdyTcb = (TaskTcbPtr)(taskTcbPtrPrioTbl[prio].pHeadNode->pOwner); TaskSwitch(); } }

        每进入一次SysTick中断就将时间片减1,只有同优先级任务数量大于1个时才进行轮转调度,并更新下一任务运行时的时间片长度。时间片运行结束的任务放入队尾,等待下一周期的轮转调用。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/********************************************************************************************** * @brief * * @param None * @retval None **********************************************************************************************/ void SysTick_Handler(void) { NodePtr pHeadNode; TaskTcbPtr pTaskTcb; if(pOsCurTcb->timeSlice) pOsCurTcb->timeSlice--; if(taskTcbPtrPrioTbl[pOsCurTcb->priority].nodeCount > 1) { if(pOsCurTcb->timeSlice == 0) { pHeadNode = ListPopHead(&taskTcbPtrPrioTbl[pOsCurTcb->priority]); ListInsertAtTail(&taskTcbPtrPrioTbl[pOsCurTcb->priority],pHeadNode); pTaskTcb = (TaskTcbPtr)(taskTcbPtrPrioTbl[pOsCurTcb->priority].pHeadNode->pOwner); pTaskTcb->timeSlice = pTaskTcb->timeSliceSet; } } TaskSchedule(); }

三、仿真验证

         在main函数当中创建两个任务,优先级设置为0,StartTask任务时间片设置为2,SecondTask任务时间片设置为3。仿真查看两个两个任务是否交替运行。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); LED_GPIO_Config(); SysTickRateInit(); TaskScheduleInit(); TaskCreate(&StartTaskTcb, StartTask, StartTaskStack, START_TASK_SIZE,0, 2); TaskCreate(&SecondTaskTcb, SecondTask, SecondTaskStack, SECOND_TASK_SIZE,0,3); OsTaskStart(); return 0; }

        当前StartTask任务的时间片运行结束即将切换到SecondTask运行。

         当前SecondTask任务的时间片运行结束即将切换到StartTask运行。

 

最后

以上就是有魅力砖头最近收集整理的关于基于STM32的RTOS简易分析-混合式调度一、双向链表的实现二、同优先级轮转调度设计三、仿真验证的全部内容,更多相关基于STM32内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(86)

评论列表共有 0 条评论

立即
投稿
返回
顶部