首页 > 其他 > 详细

小X教你写嵌入式操作系统之------(一)多任务抢占调节机制

时间:2014-09-18 22:11:34      阅读:511      评论:0      收藏:0      [点我收藏+]

/****************************************************

Title: 嵌入式系统多任务抢占机制

Framework:MyOS V 1.0 Bate

Date:2014-9-18 21:31:54

Author:小X

Remark:ARM实现系统任务的调度

*****************************************************/

 

       今天我给大家带来的是如何理解嵌入式系统多任务机制.

       我们先来写一个多任务调节主架构。

 1 /**********************************************************
 2  *  多语言嵌套写嵌入式系统框架
 3  *  C/C++/C#
 4  *  嵌入式系统,单片机的系统原理其实和PC类似,但是PC系统比单片机复杂上千上万倍。
 5  *  本来是写C的,后来使用C++和C#大量语法,搞的代码有点不伦不类望见谅。
 6  * ********************************************************/
 7 /// <summary>程序入口</summary>
 8 int Main(int argc, char argv[])
 9 { 
10     try
11     {
12         App.Init();  //初始化APP
13         MyOS.Init();  //操作系统初始化
14         MyOS.ShowInFo(); //操作系统信息
15         Debug.Print(DateTime.Now.ToString());
16         Debug.Print("All OK!");
17         MyOS.TaskCreate(Task0,&StackTask0[StackSizeTask0-1],PrioTask0); //  创建一个任务
18         Debug.Printf("Ready to start MyOS!\r\n\r\n"); 
19         MyOS.Start();      //开始运行操作系统
20         return 0;  
21     } 
22     catch (Exception ex)
23     {
24         Debug.Print(ex.Message);
25     }
26     while (true) { Thread.Sleep(1000); }
27 } 
28 void Task0(void) 
29 { 
30     App.Start();  //设置中断向量,启动操作系统的硬件定时器中断
31     Debug.Printf("Start MyOS!\r\n"); 
32     //  创建其他任务
33     MyOS.TaskCreate(Task1,&StackTask1[StackSizeTask1 - 1],PrioTask1); 
34     MyOS.TaskCreate(Task2,&StackTask2[StackSizeTask2 - 1],PrioTask2); 
35     MyOS.TaskCreate(Task3,&StackTask3[StackSizeTask2 - 1],PrioTask3); 
36     while(1) 
37     { 
38         Debug.Printf("Task0\r\n"); 
39         MyOS.TimeDly(2000);    //     2 秒运行一次
40     } 
41 } 
42 void Task1(void) 
43 { 
44     while(1) 
45     { 
46         Debug.Printf("Task1\r\n"); 
47         MyOS.TimeDly(4000);  //   4 秒运行一次
48     } 
49 } 
50 
51 void Task2(void) 
52 { 
53     while(1) 
54     {
55         Debug.Printf("Task2\r\n"); 
56         MyOS.TimeDly(1000);  //   1 秒运行一次
57         Debug.Printf("Suspend Task2!\r\n"); 
58         MyOS.TaskSuspend(PrioTask2);  //   进入挂起状态
59     } 
60 } 
61 void Task3(void) 
62 { 
63     while(1) 
64     {
65         Debug.Printf("Resume Task2!\r\n"); 
66         MyOS.TaskResume(PrioTask2);  //  恢复任务 2
67         MyOS.TimeDly(10000); 
68     } 
69 }

 

整体语法可多错误,我们不必在意这些细节。

系统过程分析:

我们整个系统创建了四个任务处理,任务 0 每 2 秒运行一次,

                任务 1 每 4 秒运行一次,

                任务 2 每 1 秒运行一次,

                然后即把自己挂起,

                任务 3 每 10 秒运行一次,

                并把任务 2 恢复。

/***********************先预测一下结果************************/

 

 1 /******************终端显示效果*************************
 2  * Erase Done......
 3  * Erase OK.
 4  * Dowload......
 5  * Dowload OK.
 6  * Verify......
 7  * Verify OK.
 8  * Application running ......
 9  * ......................................................
10  * Info:  Hardware   XXXXX
11  *        OS:MyOS V1.0 Bete
12  *        TinyBooter:V1.0 Bate
13  *        App:V1.0 Bate
14  *        Date:18th Sep,2004
15  *        Author:BigBear
16  * Time:2014-9-18 17:12:05
17  * ALL OK!
18  * Ready to start MyOS!
19  * Start MyOS!
20  * 
21  * Tesk0;
22  * Tesk1;
23  * Tesk2;
24  * Suspend Task2!
25  * Resume Task2!
26  * Tesk2;
27  * Tesk0;
28  * Tesk0; 
29  * Tesk1;
30  * Tesk0;
31  * Tesk0;
32  * Tesk1;
33  * Tesk0;
34  * Tesk2;
35  * Suspend Task2!
36  * Resume Task2!
37  * Tesk2;
38  * Tesk0;
39  * Tesk0;
40  * Tesk1;
41  * Tesk0;
42  * Tesk0;
43  * Tesk1;
44  *   *
45  *   *
46  *   *   
47  *   *
48  *   (循环中。。。。。。)   
49  *   *
50  *   * 
51 ***************************************************/
什么协同多任务系统?


    在我们电脑中,腾讯让我们让成了开机登QQ的习惯,QQ登陆的过程中我们打开工作邮箱,这是QQ登录相当于任务A初始化,FoxMail相当于B初始化,我们习惯打开一下浏览器看看救赎论坛,这属于任务C。
其实单核CPU里面,这些任务是单一工作的。不存在真正的多任务机制,每个任务同一时间都使用同一个CPU是不可能的。所有单一CPU是单一任务的。但是我们操作系统是通过任务调度来实现多个任务执行。通过CPU快速切换,达到让人感觉像是多个任务同时运行一样。这个就是操作系统的多任务调度机制。
现在的计算机硬件系统中,CPU通常是两个或多核CPU。可以真正意义上同时处理多个任务。这些是X86等复杂CPU以及操作系统来协同调节任务。

  多任务的好处就是可以充分利用我们的硬件资源。在单片机中,硬件资源非常简单。多任务的机制显得更为重要。在之前的裸机程序中,我们的都是处理一件事情的时候就让他Delay一段时间。CPI在那里空转(等待),这样超级浪费CPU资源。但是我们加入任务调节机制之后,我们会让程序自己等待着,CPU去执行下一个任务,等条件满足后(比喻延时时间到了),我们在将这个任务挂载寄来去处理前面的事情。处理了之后再回来继续开始手上的事情。这样充分利用CPU。大大提高了应用的执行效率。

抢占式多任务处理调节机制。 


什么是任务的抢占式调节呢?
当系统在按任务执行时。多个任务同时请求。我们的系统到底应该执行哪一个任务呢?当然我们一般处理方式是当同时有多个任务响操作系统发出请求时,谁的任务优先级最高我们就去执行谁的程序。

我们先会定义一大堆的任务优先级别:
 1 public enum MultiTask:uint
 2 {
 3     PTesk0=0;
 4     PTesk1=1;
 5     PTesk2=2;
 6     PTesk3=3;
 7     PTesk4=4;
 8     PTesk5=5;
 9     PTesk6=6;
10     PTesk7=7;
11     PTesk8=8;
12     PTesk9=9;    
13 } ;

 

我们把每一个任务分别分配唯一的一个优先级。

 

 1 void TSys::Start()
 2 {
 3     debug_printf("系统准备就绪,开始循环处理%d个任务!\r\n", _TaskCount);
 4 
 5     _Running = true;
 6     while(_Running)
 7     {
 8         ulong now = Time.Current();    // 当前时间
 9         int k = 0;
10         for(int i=0; i < ArrayLength(_Tasks) && k < _TaskCount; i++)
11         {
12             Task* task = _Tasks[i];
13             if(task)
14             {
15                 if(task->NextTime <= now)
16                 {
17                     // 先计算下一次时间
18                     //task->NextTime += task->Period;
19                     // 不能通过累加的方式计算下一次时间,因为可能系统时间被调整
20                     task->NextTime = now + task->Period;
21                     task->Callback(task->Param);
22 
23                     // 如果只是一次性任务,在这里清理
24                     if(task->Period < 0)
25                     {
26                         _Tasks[i] = NULL;
27                         delete task;
28                         _TaskCount--;
29                     }
30                 }
31 
32                 k++;
33             }
34         }
35     }
36     debug_printf("系统停止调度,共有%d个任务!\r\n", _TaskCount);
37 }

 

这个调节机制做的比较好。非严格情况下可以说是实时系统。实时操作系统的做法都是先预测任务的延时时间。

通常在ms级别之类对任务请求作出反应。但是任务的改变会带来延时的复杂度。

 

我们的任务在还没有运行或者被Delete时,它的数据或者寄存器都会先保存在私有栈中。在任务切换时,都是按顺序入栈出栈。      

 任务切换原理:我们先把当前的任务现场状况保存在自己的私有栈中,再把将要进行的数据从内存的栈中转移到CPU上面去。

主要是改变下面的三个值来改变。

堆栈指针r13(SP)   程序把寄存器数据压入堆栈,返回时再出栈,保证了程序的完整性。

连接寄存器r14(LR)  保存子程序返回地址。当程序发生异常异常模式LR用来保存异常返回地址,处理栈中断。

程序计数器r15(PC)  计数功能

这三个参数传给CPU,CPU通过他们进行新旧任务切换。

 

过程如下:


 


 

 

  旧任务挂载


 

①:处理器PC指针压栈到任务堆栈

②:SP指针保存到任务控制块

 

新任务启动:


 

①:任务控制块载入到SP指针。

②:新任务的私人堆栈中PC指针出栈。

 

新旧任务切换恰好是两个相反的过程。


我们再来写写任务调换实现函数代码:
 1 void MyOSChange (void) 
 2 { 
 3     MyOS.Open(); 
 4     MyOS.High.Find();         // 找出就绪表中优先级最高的任务 
 5     if(MyOS.Tesk.High != MyOS.Ontime.High)  //  如果不是当前运行的任务,进行任务调度 
 6     { 
 7         p_spAdd  = &sp[MyOS.Ontime.High];  //  取得栈顶指针 
 8         p_spHigt = &sp[MyOS.Tesk.High]; 
 9         MyOS.Ontime.High= MyOS.Tesk.High;    // 更新
10         MyOS.Tesk    ();          //  调度任务 
11     } 
12     MyOS.Exit();
13 } 

入栈出栈函数都在汇编里面。我们不做详细讲解

1 uint* p = (uint*)__get_MSP();
2 
3     // 直接使用RAM最后,需要减去一点,因为TSys构造函数有压栈,待会需要把压栈数据也拷贝过来
4     uint top = SRAM_BASE + (ramSize << 10);
5     __set_MSP(top - 0x40);    // 左移10位,就是乘以1024
6     // 拷贝一部分栈内容到新栈
7     memcpy((void*)(top - 0x40), (void*)p, 0x40);


抢占式任务调节我们最高优先级的任务需要准备的时候。立即抢占正在运行任务的资源。
抢占优先级通俗的理解就是动态调节任务优先级别。

高优先级的任务有时候不需要CPU资源了。他就会主动请求自己挂起,然后CPu打开时钟滴答,调节任务优先级状态,执行当前状态下最高优先级的任务。

当时机滴答计数完还没有完。如果发现还有更高的优先级任务。CPU会切换更高优先级任务。这是嵌套的任务切换调节。

先写到这里。



End!

欢迎大家一起交流 ,分享程序员励志故事。   幸福的程序员 QQ群:bubuko.com,布布扣 


小X教你写嵌入式操作系统之------(一)多任务抢占调节机制

原文:http://www.cnblogs.com/1hua1ye/p/3979791.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!