系统模型
1 系统类别
裸机系统通常分成轮询系统和前后台系统。
1.1 轮询系统
轮询系统:即是在裸机编程的时候,先初始化好相关的硬件,然后让主程序在一个死循环里面不断循环,顺序地处理各种事件。
伪代码:
1 int main(void)
2 {
3 /* 硬件相关初始话 */
4 HardWareInit();
5
6 /* 无限循环 */
7 for(; ;){
8 /* 处理时间1 */
9 DoSomethin1();
10
11 /* 处理事件2 */
12 Dosomethin2();
13
14 /* 处理事件3 */
15 DoSomethin3();
16 }
17}
注意:轮询系统是一种非常简单的软件结构,通常只适用于仅需要顺序执行代码且不需要外部事件来驱动就可以完成的事情。
(如果只是实现LED翻转,串口输出,液晶显示等操作,那么使用轮询系统将会非常好。但是,如果加入了按键操作等需要检测外部信号的事件,那么整个系统的实时响应能力就不会那么好。)
例如:假设DoSomethin3是按键扫描,当外部按键被按下,用来模拟紧急报警,这个时候,需要立刻响应并做紧急处理,而这时程序刚好执行到DoSomethin1,如果DoSomethin1需要执行的时间比较久,久到按键释放之后还没有执行完毕,那么当执行到DoSomethin3时就会丢失一次事件。
1.2 前后台系统
前后台系统:是在轮询系统的基础上加入了中断。外部时间的响应是在中断里面完成,事件的处理还是回到轮询系统中完成。中断被称为前台,main()函数里面的无限循环称为后台。
伪代码:
1 int flag1 = 0;
2 int flag2 = 0;
3 int flag3 = 0;
4
5 int main(void)
6 {
7 /* 硬件相关初始化 */
8 HardWareInit();
9
10 /* 无限循环 */
11 for(; ;){
12 if(flag1 = 1){
13 /* 处理事件1 */
14 DoSomething1();
15 }
16 if(flag2 = 1){
17 /* 处理事件2 */
18 DoSomething2();
19 }
20 if(flag3 = 1){
21 /* 处理事件3 */
22 DoSomething3();
23 }
24 }
25 }
26
27 void ISR1(void)
28 {
28 /* 置位标志位 */
30 flag1 = 1;
31 }
32
33 void ISR2(void)
34 {
35 /* 置位标志位 */
36 flag2 = 1;
37 }
38
39 void ISR3(void)
40 {
41 /* 置位标志位 */
42 flag3 = 1;
43 }
注意:在顺序执行后台程序时,如果出现中断,那么中断会打断后台程序的正常执行流,转而去执行中断服务程序,在中断服务程序中标记事件。如果,事件要处理的事情很简短,则可以在中断服务程序中处理;如果,事件要处理的事情比较多,则返回后台程序中处理。
中断服务程序
2 多任务系统
多任务系统:多任务系统的事件响应也是在中断中完成的,但是事件的处理是在任务中完成的。
任务:一个个的独立的无限循环且不能返回的函数,由操作系统调度管理。
伪代码:
1 int flag1 = 0;
2 int flag2 = 0;
3 int flag3 = 0;
4
5 int main(void)
6 {
7 /* 硬件相关初始化 */
8 HardWareInit();
9
10 /* 操作系统初始化 */
11 RTOSInit();
12
13 /* 操作系统启动,开始多任务调度,不再返回 */
14 RTOSStart();
15 }
16
17 void ISR1(void)
18 {
19 /* 置位标志位 */
20 flag1 = 1;
21 }
22
23 void ISR2(void)
24 {
25 /* 置位标志位 */
26 flag2 = 1;
27 }
28
29 void ISR3(void)
30 {
31 /* 置位标志位 */
32 flag3 = 1;
33 }
34
35 void DOSomething1(void)
36 {
37 /* 无限循环,不能返回 */
38 for(; ;){
39 /* 任务实体 */
40 if(flag1){
41
42 }
43 }
44 }
45
46 void DOSomething2(void)
47 {
48 /* 无限循环,不能返回 */
49 for(; ;){
50 /* 任务实体 */
51 if(flag2){
52
53 }
54 }
55 }
56
57 void DOSomething3(void)
58 {
59 /* 无限循环,不能返回 */
60 for(; ;){
61 /* 任务实体 */
62 if(flag3){
63
64 }
65 }
66 }
注意:在多任务系统中,任务与中断一样,也具有优先级,优先级高的任务会优先执行。当一个紧急事件在中断中被标记之后,如果事件对应的任务的优先级足够高,就会立刻得到响应。多任务系统的实时性有提高了。
中断又称异步中断,由硬件触发;异常又称同步中断,由软件触发。
3 RTOS启动流程
在目前的RTOS中,主要有两种比较流行的启动方式。
3.1 “万事俱备,只欠东风”法
这种方法是在main()函数中将硬件、TOS系统初始化,所有任务创建完毕,最后启动RTOS的调度器,开始多任务的调度。
伪代码:
1 int main(void)
2 {
3 /* 硬件初始化 */
4 HardWare_Init();
5
6 /* RTOS系统初始化 */
7 RTOS_Init(); //不同的RTOS,它们的初始化有细微的差别
8
9 /* 创建任务1,但任务1不会执行,因为调度器还没有开启 */
10 RTOS_TaskCreate(Task1);
11 /* 创建任务2,但任务2不会执行,因为调度器还没有开6启 */
12 RTOS_TaskCreate(Task2);
13
14 /* 继续创建各种任务 */
15
16 /* 启动RTOS,开始调度 */
17 RTOS_Staert(); //这时,调度器就从刚刚创建好的任务中选一个优先级 最高的任务开始运行
18 }
19
20 void Task1(void *arg)
21 {
22 while(1){
23 /* 任务实体,必须有阻塞的情况出现 */
24 }
25 }
26
27 void Task2(void *arg)
28 {
29 while(1){
30 /* 任务实体,必须有阻塞的情况出现 */
31 }
32 }
注意:任务实体必须有阻塞的情况出现,否则任务(如果优先级恰好最高)会一直在while循环中执行,导致其他任务没有执行的机会。
3.2 “小心翼翼,十分谨慎”法
这种方法是在main()函数中将硬件和RTOS系统先初始化好,然后在创建一个启动任务后启动调度器,在启动任务中创建各种应用任务,当所有任务都创建成功后,启动任务把自己删除。
伪代码:
1 int main(void)
2 {
3 /* 硬件初始化 */
4 HardWare_Init();
5
6 /* RTOS系统初始化 */
7 RTOS_Init();
8
9 /* 创建一个任务 */
10 RTOS_TaskCreate(AppTaskCreate);
11
12 /* 启动RTOS,开始调度 */
13 RTOS_Start();
14 }
15
16 /* 初始任务,在里面创建其他任务 */
17 void AppTaskCreate(void *arg)
18 {
19 /* 创建任务1,然后执行 */
20 RTOS_TaskCreate(Task1);
21
22 /* 当任务1阻塞时,继续创建任务2,然后执行 */
23 RTOS_TaskCreate(Task2);
24
25 /* 继续创建各种任务 */
26
27 /* 当任务创建完成,删除初始任务 */
28 RTOS_TaskDelete(AppTaskCreate);
29 }
30
31 void Task1(void *arg)
32 {
33 while(1){
34 /* 任务实体,必须有阻塞的情况出现 */
35 }
36 }
37
38 void Task2(void *arg)
39 {
40 while(1){
41 /* 任务实体,必须有阻塞的情况出现 */
42 }
43 }
注意:我们通常说任务是一个不带返回的值的无限循环C函数,但是因为初始任务的特殊性,它不能是无限循环的,只执行一次后就关闭了。
每创建一个任务后它都将进入就绪态,系统会进行一次调度,如果新创建的任务的优先级比初始任务的优先级高,那么将执行新创建的任务,当新的任务阻塞时,再回到初始任务被打断的地方继续执行。反之,则继续往下创建新的任务,直到所有任务创建完成。

浙公网安备 33010602011771号