UCOS-III笔记

1.单片机程序分类:轮询程序,前后台程序,多任务系统程序

2.多任务系统伪代码

1 int flag1 = 0;
2 int flag2 = 0;
3 int flag3 = 0;
4
5 int main(void)
6 {
7 /* 硬件相关初始化 */
8 HardWareInit();
9
10 /* OS 初始化 */
11 RTOSInit();
12
13 /* OS 启动,开始多任务调度,不再返回 */
14 RTOSStart();
15 }
16
17 void ISR1(void)
18 {
19 /* 置位标志位 */
20 flag1 = 1;
21 }
23 void ISR2(void)
24 {
25 /* 置位标志位 */
26 flag2 = 2;
27 }
28
29 void ISR3(void)
30 {
31 /* 置位标志位 */
32 flag3 = 1;
33 }
34
35 voidDoSomething1(void)
36 {
37 /* 无限循环,不能返回 */
38 for (;;)
39 {
40 /* 任务实体 */
41 if (flag1)
42 {
43 }
44 }
45 }
46
47 voidDoSomething2(void)
48 {
49 /* 无限循环,不能返回 */
50 for (;;)
51 {
52 /* 任务实体 */
53 if (flag2)
54 {
55 }
56 }
57 }
58
59 voidDoSomething3(void)
60 {
61 /* 无限循环,不能返回 */
62 for (;;)
63 {
64 /* 任务实体 */
65 if (flag3)
66 {
67 }
68 }
69 }
View Code

3.三类系统异同

4.任务是什么:

在裸机系统中,系统的主体就是 main 函数里面顺序执行的无限循环,这个无限循环里面 CPU 按
照顺序完成各种事情。在多任务系统中,我们根据功能的不同,把整个系统分割成一个个独立的
且无法返回的函数,这个函数我们称为任务。

5.多任务系统中,要为每一个任务分配独立的栈空间

#define TASK1_STK_SIZE 128 (1)
#define TASK2_STK_SIZE 128
static CPU_STK Task1Stk[TASK1_STK_SIZE];(2)
static CPU_STK Task2Stk[TASK2_STK_SIZE];

6.重要宏定义

1 #ifndef CPU_H
2 #define CPU_H
3
4 typedef unsigned short CPU_INT16U;
5 typedef unsigned int CPU_INT32U;
6 typedef unsigned char CPU_INT08U;
7
8 typedef CPU_INT32U CPU_ADDR;
9
10 /* 栈数据类型重定义 */
11 typedef CPU_INT32U CPU_STK;
12 typedef CPU_ADDR CPU_STK_SIZE;
13
14 typedef volatile CPU_INT32U CPU_REG32;
15
16 #endif/* CPU_H */

7.系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块 TCB(Task Con-

trolBlock),这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的栈,
任务名称,任务的形参等。有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个 TCB 来实现。TCB 是一个新的数据类型

1 /* 任务控制块重定义 */
2 typedefstruct os_tcb OS_TCB;(1)
3
4 /* 任务控制块数据类型声明 */
5 struct os_tcb {(2)
6 CPU_STK *StkPtr;
7 CPU_STK_SIZE StkSize;
8 };

1 static OS_TCB Task1TCB;
2 static OS_TCB Task2TCB;

8.任务的栈,任务的函数实体,任务的 TCB 最终需要联系起来才能由系统进行统一调度。那么这

个联系的工作就由任务创建函数 OSTaskCreate 来实现,该函数在 os_task.c

1 void OSTaskCreate (OS_TCB *p_tcb,(1)//任务控制块指针
2          OS_TASK_PTR p_task,(2)//p_task 是任务函数名,类型为 OS_TASK_PTR
3              void *p_arg,(3)//p_arg 是任务形参,用于传递任务参数
4        CPU_STK *p_stk_base, (4)//p_stk_base 用于指向任务栈的起始地址
5       CPU_STK_SIZE stk_size, (5)//stk_size 表示任务栈的大小
6            OS_ERR *p_err) (6)//p_err 用于存错误码
7 {
8   CPU_STK *p_sp;
9
10   p_sp = OSTaskStkInit (p_task,(7)
11   p_arg,
12   p_stk_base,
13   stk_size);
14   p_tcb->StkPtr = p_sp;(8)
15   p_tcb->StkSize = stk_size;(9)
16
17   *p_err = OS_ERR_NONE;(10)
18 }

9.OSTaskStkInit() 是任务栈初始化函数。当任务第一次运行的时候,

加载到 CPU 寄存器的参数就放在任务栈里面,在任务创建的时候,预先初始化好栈。

1 CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,(1)//p_task 是任务名,指示着任务的入口地址,在任务切换的时候,需要加载到 R15,即 PC 寄存器,这样 CPU 就可以找到要运行的任务
2 void *p_arg,(2)//p_arg 是任务的形参,用于传递参数,在任务切换的时候,需要加载到寄存器 R0。R0 寄存器通常用来传递参数。
3 CPU_STK *p_stk_base,(3)//p_stk_base 表示任务栈的起始地址
4 CPU_STK_SIZE stk_size)(4)
5 {
6   CPU_STK *p_stk;
7
8   p_stk = &p_stk_base[stk_size];(5)//获取任务栈的栈顶地址,ARMCM3 处理器的栈是由高地址向低地址生长的。所以初始化栈之前,要获取到栈顶地址,然后栈地址逐一递减即可。
9   /* 异常发生时自动保存的寄存器 */(6)
10   *--p_stk = (CPU_STK)0x01000000u; /* xPSR 的 bit24 必须置 1 */
11   *--p_stk = (CPU_STK)p_task; /* R15(PC) 任务的入口地址 */
12   *--p_stk = (CPU_STK)0x14141414u; /* R14 (LR) */
13   *--p_stk = (CPU_STK)0x12121212u; /* R12 */
14   *--p_stk = (CPU_STK)0x03030303u; /* R3 */
15   *--p_stk = (CPU_STK)0x02020202u; /* R2 */
16   *--p_stk = (CPU_STK)0x01010101u; /* R1 */
17   *--p_stk = (CPU_STK)p_arg; /* R0 : 任务形参 */
18   /* 异常发生时需手动保存的寄存器 */(7)
19   *--p_stk = (CPU_STK)0x11111111u; /* R11 */
20   *--p_stk = (CPU_STK)0x10101010u; /* R10 */
21   *--p_stk = (CPU_STK)0x09090909u; /* R9 */
22   *--p_stk = (CPU_STK)0x08080808u; /* R8 */
23   *--p_stk = (CPU_STK)0x07070707u; /* R7 */
24   *--p_stk = (CPU_STK)0x06060606u; /* R6 */
25   *--p_stk = (CPU_STK)0x05050505u; /* R5 */
26   *--p_stk = (CPU_STK)0x04040404u; /* R4 */
27
28   return (p_stk);(8) //返回栈指针 p_stk,这个时候 p_stk 指向剩余栈的栈顶
29 }

10.任务创建好之后,我们需要把任务添加到一个叫就绪列表的数组里面,表示任务已经就绪,系统随时可以调度。

1 typedef struct os_rdy_list OS_RDY_LIST;(1)
2
3 struct os_rdy_list {(2)
4 OS_TCB *HeadPtr;
5 OS_TCB *TailPtr;
6 };

1 #ifdef OS_GLOBALS
2 #define OS_EXT
3 #else
4 #define OS_EXT extern
5 #endif

#define OS_CFG_PRIO_MAX 32u
OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX];

1 /* 将任务加入到就绪列表 */
2 OSRdyList[0].HeadPtr = &Task1TCB;(1)
3 OSRdyList[1].HeadPtr = &Task2TCB;(2)

11.OS 系统初始化一般是在硬件初始化完成之后来做的,主要做的工作就是初始化 μC/OS-III 中定义的全局变量。

1 void OSInit (OS_ERR *p_err)
2 {
3   OSRunning = OS_STATE_OS_STOPPED;(1)//系统用一个全局变量 OSRunning 来指示系统的运行状态,刚开始系统初始化的时候,默认为停止状态,即 OS_STATE_OS_STOPPED
4
5   OSTCBCurPtr = (OS_TCB *)0;(2)//全局变量 OSTCBCurPtr 是系统用于指向当前正在运行的任务的TCB 指针,在任务切换的时候用得到
6   OSTCBHighRdyPtr = (OS_TCB *)0;(3)//全局变量 OSTCBHighRdyPtr 用于指向就绪任务中优先级最高的任务的 TCB,在任务切换的时候用得到
7
8   OS_RdyListInit();(4)
9
10   *p_err = OS_ERR_NONE;(5)
11 }

OS_RdyListInit() 用于初始化全局变量 OSRdyList[],即初始化就绪
列表


1 OS_EXT OS_TCB *OSTCBCurPtr;
2 OS_EXT OS_TCB *OSTCBHighRdyPtr;
3 OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX];
4 OS_EXT OS_STATE OSRunning;


1 #define OS_STATE_OS_STOPPED (OS_STATE)(0u)
2 #define OS_STATE_OS_RUNNING (OS_STATE)(1u)



1 void OS_RdyListInit(void) 2 { 3 OS_PRIO i; 4 OS_RDY_LIST *p_rdy_list; 5 6 for ( i=0u; i<OS_CFG_PRIO_MAX; i++ ) 7 { 8 p_rdy_list = &OSRdyList[i]; 9 p_rdy_list->HeadPtr = (OS_TCB *)0; 10 p_rdy_list->TailPtr = (OS_TCB *)0; 11 } 12 }

12.任务创建好,系统初始化完毕之后,就可以开始启动系统了

1 void OSStart (OS_ERR *p_err)
2 {
3     if ( OSRunning == OS_STATE_OS_STOPPED ) {(1)
4         /* 手动配置任务 1 先运行 */
5         OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;(2) //OSTCBHIghRdyPtr 指向第一个要运行的任务的 TCB
6
7         /* 启动任务切换,不会返回 */
8         OSStartHighRdy();(3)
9
10         /* 不会运行到这里,运行到这里表示发生了致命的错误 */
11         *p_err = OS_ERR_FATAL_RETURN;
12     }
13     else
14     {
15         *p_err = OS_STATE_OS_RUNNING;
16     }
17 }    

OSStartHighRdy() 用于启动任务切换,即配置 PendSV 的优先级
为最低,然后触发 PendSV 异常,在 PendSV 异常服务函数中进行任务切换

1 ;*******************************************************************
2 ; 开始第一次上下文切换
3 ; 1、配置 PendSV 异常的优先级为最低
4 ; 2、在开始第一次上下文切换之前,设置 psp=0
5 ; 3、触发 PendSV 异常,开始上下文切换
6 ;*******************************************************************
7 OSStartHighRdy
8 LDR R0, = NVIC_SYSPRI14 ; 设置 PendSV 异常优先级为最低(1)
9 LDR R1, = NVIC_PENDSV_PRI
10 STRB R1, [R0]
11
12 MOVS R0, #0 ; 设置 psp 的值为 0 ,开始第一次上下文切换 (2)
13 MSR PSP, R0
14
15 LDR R0, =NVIC_INT_CTRL ; 触发 PendSV 异常(3)
16 LDR R1, =NVIC_PENDSVSET
17 STR R1, [R0]
18
19 CPSIE I ; 启用总中断,NMI 和 HardFault 除外(4)
20
21 OSStartHang
22 B OSStartHang ; 程序应永远不会运行到这里


5 ; 有关内核外设寄存器定义可参考官方文档:STM32F10xxx Cortex-M3 programming manual
6 ; 系统控制块外设 SCB 地址范围:0xE000ED00-0xE000ED3F
7 ;--------------------------------------------------------------------
8 NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制及状态寄存器 SCB_ICSR。
9 NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器 SCB_SHPR3:
10 ; bit16~23
11 NVIC_PENDSV_PRI EQU 0xFF ; PendSV 优先级的值(最低)。
12 NVIC_PENDSVSET EQU 0x10000000 ; 触发 PendSV 异常的值 Bit28:PENDSVSET
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值