一种裸奔多任务嵌入式操作系统模型.docx

上传人:b****2 文档编号:16919258 上传时间:2023-04-24 格式:DOCX 页数:20 大小:20.68KB
下载 相关 举报
一种裸奔多任务嵌入式操作系统模型.docx_第1页
第1页 / 共20页
一种裸奔多任务嵌入式操作系统模型.docx_第2页
第2页 / 共20页
一种裸奔多任务嵌入式操作系统模型.docx_第3页
第3页 / 共20页
一种裸奔多任务嵌入式操作系统模型.docx_第4页
第4页 / 共20页
一种裸奔多任务嵌入式操作系统模型.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

一种裸奔多任务嵌入式操作系统模型.docx

《一种裸奔多任务嵌入式操作系统模型.docx》由会员分享,可在线阅读,更多相关《一种裸奔多任务嵌入式操作系统模型.docx(20页珍藏版)》请在冰豆网上搜索。

一种裸奔多任务嵌入式操作系统模型.docx

一种裸奔多任务嵌入式操作系统模型

一种裸奔多任务模型

一个网友的总结:

stateMachine + timerTick + queue。

在RTOS环境下的多任务模型:

任务通常阻塞在一个OS调用上(比如从消息队列取数据)。

外部如果想让该任务运转,就要向消息队列发送消息。

任务收到消息时,根据当前状态,决定如何处理消息。

这就是状态机。

任务将消息队列中的消息处理完毕后,重新进入阻塞状态。

任务在处理中,有时要延时一段时间,然后才继续工作:

    为了充分使用CPU,可以通过OS调用让其它任务去工作。

    OS通常会提供一个taskDelay调用。

    当任务调用taskDelay时,即进入阻塞状态,直到超时,才重新进入可工作状态(就绪状态)。

下面说说裸奔环境下的多任务模型:

裸奔也可以多任务,但调度是由用户自主控制。

在RTOS环境下,一般提供抢占式调度。

在裸奔时,一般是任务在处理告一段落后,主动结束处理。

RTOS环境下的任务,一般处于一个while

(1)循环中。

    while

(1){

        从消息队列接收消息。

如果没有,将阻塞。

        处理消息。

        }

裸奔下的任务,一般采用查询方式:

    查询是否有待处理的事件。

    如果没有,返回。

    如果有,根据任务的当前状态,进行处理。

处理完毕后,可能返回,也可能将待处理事件全部处理完毕后再返回。

裸奔任务其实也处于一个while

(1)循环中,只不过这个循环在任务外部。

main()

{

    A_taskInit();        //任务的初始化

    B_taskInit();

    ...

    while

(1){

        A_taskProc();    //任务的处理

        B_taskProc();

        }

状态机既适用于OS环境,也适用于裸奔环境。

但在裸奔环境下,状态可能被切分得更细。

例如后面讲的如何在裸奔环境实现taskDelay()。

消息队列既适用于OS环境,也适用于裸奔环境。

在OS环境下,消息队列机制由OS提供。

在裸奔环境下,消息队列要自己来实现。

如果对队列的概念不清楚,可参考《数据结构》教材。

这个队列机制,可做成通用模块,在不同的程序中复用。

消息队列用于缓冲事件。

事件不知道什么时候会到来,也不能保证来了就能迅速得到处理。

    使用消息队列,可以保证每个事件都被处理到,以及处理顺序。

一般在两种情况下会用到消息队列:

    存储外部事件:

外部事件由中断收集,然后存储到队列。

        串口接收程序中的接收循环缓冲区,可理解为消息队列。

    任务间通讯:

一个任务给其它任务发送消息。

timerTick,就是系统中的时钟基准。

OS中总是有一个这样的基准。

在裸奔时,我们要用一个定时器(或RTC或watchdog)来建立这个时间基准。

一个tick间隔可以设置为10ms(典型RTOS的缺省设置)。

让定时器10ms中断一次,中断发生时给tickNum++。

    以前,我在定时器中断中设置1S标志、200ms标志等等。

时间相关的任务根据这些标志判断是否要执行。

    近来,一般让任务直接去察看tickNum。

两次相减来判断定时是否到达。

    也可以在系统中建立一个通用定时器任务,管理与不同任务相关的多个定时器;在定时到达时,由定时器任务去调用相应的callback。

系统时钟基准是所谓“零耗时裸奔”的基础。

timerTick的分辨率,决定了只适于于较大的时间延时。

    在做时序时的小延时,用传统方法好了。

OS中的taskDelay()在裸奔环境下的一种实现:

OS环境:

void xxxTask(void)

{

    while

(1){

        //waitEvent

        //do step_1

        taskDelay(TIME_OUT_TICK_NUM);

        //do step_2

    }

裸奔环境:

void xxxTask(void)

{

    static unsigned int taskStat = STAT_GENERAL;    //任务状态变量

    static timer_t startTick;

    timer_t currTick;

    

    if (taskStat == STAT_GENERAL)

    {

        //check event

        //if no event

            return;

        //do step_1

        startTick = sysGetTick();    //sysGetTick()就是察看系统时间

        taskStat = STAT_WAIT;

        return;

    }

    else if (taskStat == STAT_WAIT)

    {

        currTick = sysGetTick();    //sysGetTick()就是察看系统时间

        if ((currTick - startTick) >= TIME_OUT_TICK_NUM)

        {

            //do step_2    

            taskStat = STAT_GENERAL;

            return;

        }

        else

            return;

    }

}

老生常谈---一种裸奔多任务模型ourdev_629752P0O6JH.txt(文件大小:

4K) (原文件名:

老生常谈---一种裸奔多任务模型.txt)

C51多任务编程思想ourdev_629753EWA0LM.pdf(文件大小:

143K) (原文件名:

C51多任务编程思想.pdf) 

基于51单片机的C语言多任务操作 完美版ourdev_629754PETS4B.rar(文件大小:

3K) (原文件名:

基于51单片机的C语言多任务操作 完美版.rar)

Easy51RTOS的原理

//Easy51RTOS操作系统头文件

#include "os_cfg.h"     

#include "functns.h" //常用一些功能函数

unsigned char TempBuffer[6];            //显示温度字符串

unsigned char str2[12]={' ',' ',' ',0,0,0,0,0,0,0xdf,0x43,0};                             

//任务0:

测温度送显

void task0(void)

{     

         temp=ReadTemperature();

        IntToStr(temp,TempBuffer);

              str2[3]=TempBuffer[0];

        str2[4]=TempBuffer[1];

        str2[5]=TempBuffer[2];

              str2[6]=TempBuffer[3]; 

              str2[7]=TempBuffer[4];

              str2[8]=TempBuffer[5]; 

              GotoXY(0,1);

              Print(str2);

           delay_nms(300); 

}

//任务1:

键盘扫描,LCD显示 

void task1(void)

{

     if(CHANGE==0)                         //判断change温度键是否按下

             {

               set_temp=key_set();           //设定需要更改的温度值

       

                     if(set_temp

                 {

                    fengshan();                        //设定的温度<实际温度,则打开电机风扇

           }

                 else if(set_temp>temp)

                 {

                       dianlu();                                    //若大于,则打开电炉(这里用LED模拟一下)

                 }

         }

}

//任务2

void task2()

{  

}

//任务3

void task3()

{

}

//任务4

void task4(void)

{     

}

//任务5 

void task5(void)

{

}

//任务6 

void task6()

{

}

//任务7

void task7()

{

}

//main主函数

void main(void)

{            

OS_InitTimer0();

EA=1;

LCD_Init();

LCD_w_data(1,1,Temp_Str);

LCD_w_data(2,1,Key_Str);

while

(1)

{

  if (OS_Delay[0]==0){task0();OS_Delay[0]=100;} //温度测量,每秒1次

  if (OS_Delay[1]==0){task1();OS_Delay[1]=10;}  //键盘扫描,键值存储

  if (OS_Delay[2]==0){task2();OS_Delay[2]=100;} //读出存储的键值,LCD显示 

  if (OS_Delay[3]==0){task3();OS_Delay[3]=50;}  

  if (OS_Delay[4]==0){task4();OS_Delay[4]=100;}

  if (OS_Delay[5]==0){task5();OS_Delay[5]=60;}

  if (OS_Delay[6]==0){task6();OS_Delay[6]=70;}  

  if (OS_Delay[7]==0){task7();OS_Delay[7]=80;}

  Delay(50);

  //Taskturn;

}

}

//定时中断服务

void OS_Timer0(void) interrupt 1 using 2

{

uchar i;

//CRY_OSC,TIME_PER_SEC在easycfg.h中配置

TH0 = 255-CRY_OSC/TIME_PER_SEC/12/256;

TL0 = 255-CRY_OSC/TIME_PER_SEC/12%256;

//每节拍对任务延时变量减1 ,减至 0 后,任务就绪。

for(i=0;i

{

  if(OS_Delay[i]!

=0) OS_Delay[i]--;

}

//Runing(On);

}

//和传统的前后感觉基本上是一样的…

//唯一的优点呢,是感觉OS_Delay[n]数组起到了分配各

 

Easy51RTOS的原理ourdev_629755MEIQGP.txt(文件大小:

3K) (原文件名:

Easy51RTOS的原理.txt) 

基于51单片机的C语言多任务操作 完美版

/*

1.本程序不使用任何汇编指令

2.由定时器T0产生中断,切换进程

3.由于中断或调用子程序,要把PC堆栈,故可以以SP为基址的地方找到PC

4.中断或子程序返回,要把SP出栈给PC,故可以操作SP改变程序入口

5.本程序经调试运行  电路图已上传

6.程序编译是会有一个警告提示,为正常现象,因为保存R0-R7时,重新定义地址,

       出现地址覆盖的警告提示。

7.用户以此模板写程序只需写用户的进程子程序和用户初始化子程序,并把各进程参数

       放在规定地方,各程序放在规定地方就可以;所有的任务调度已处理好。

*/

//头文件

#include

//#include

//#include

//宏定义

#defineuchar unsigned char

#define uint unsigned int  

#define TN  65436

//进程1,2,3执行时间之比为  T1:

T2:

T3  (时间单位us)

#define TN1  55536  //1个进程循环周期内进程1执行的时间T1us  TN1=(65536-T1)

#define TN2  55536  //1个进程循环周期内进程2执行的时间T2us  TN2=(65536-T1)

#define TN3  55536  //1个进程循环周期内进程3执行的时间T3us  TN3=(65536-T1)

//

#define N1  4  // 进程1的延时参数  

#define N2  4  // 进程2的延时参数  

#define N3  4  // 进程3的延时参数  

idata uchar temp[8] _at_ 0x00; //R0--R7

uchar tempbf1[8];  //用于保存R0--R7 进程1

uchar tempbf2[8];  //用于保存R0--R7 进程2

uchar tempbf3[8];  //用于保存R0--R7 进程3

//定义全局变量

uint address1,address2,address3;

uchar test1_1=0,test2_1=0,test3_1=0,PID=1;

//各进程的标志位,是否为第一次执行,0第一次,非0非第一次;PID进程号;

uint ac1,ac2,ac3; //, PC_Next; 各进程的初始地址寄存器.

//test1  的参数  由于进程切换时 没有保存普通变量,

//所以各进程的普通参数需要定义成全局变量.

uint m1,i1,j1,k1;

uchar table1[4];

//在此加入 用户进程1参数

//test2  的参数   

int m2,i2,j2,k2;

uchar table2[4];

//在此加入 用户进程2参数

//test3  的参数

int m3,i3,j3,k3;    

uchar table3[4];

//在此加入 用户进程1参数

//声明

//unsigned int Get_Next_PC(void);//调用子程序,获取PC

void chushihua(void);  //初始化函数

void yonghuchushihua(void);  //用户初始化函数

void test1(void);  //进程一

void test2(void);

void test3(void);

//main函数

void main(void)

// PC_Next=Get_Next_PC();

 chushihua();

 ac1=(unsigned int)(test1); //获取进程1的入口地址

 ac2=(unsigned int)(test2);//获取进程2的入口地址

 ac3=(unsigned int)(test3); //获取进程3的入口地址

 yonghuchushihua();

 TR0=1;

 while

(1);

}

//初始化时钟

void chushihua(void)

{

    TMOD=0x01;// 

EA=1;

ET0=1;

TH0=TN/256;

TL0=TN%256;

}

//中断处理,进程调度

void time0() interrupt 1 using 1

{   uchar ib;

TR0=0;

//进程顺序分配

PID++;

if(PID==4)

   {PID=1;}

 //进程调度

switch(PID)

{

  case 1:

 

 {

if(test3_1!

=0)//第一次否?

    { //保存现场,还回地址

   address3=*((unsigned char *)(SP-4));//PC的高字节

           address3 <<= 8;

           address3+=*((unsigned char *)(SP-5));   //PC的低字节

   table3[0]=*((unsigned char *)(SP)); //现场保护

   table3[1]=*((unsigned char *)(SP-1)); //现场保护

   table3[2]=*((unsigned char *)(SP-2)); //现场保护

   table3[3]=*((unsigned char *)(SP-3)); //现场保护

   for(ib=0;ib<=7;ib++) //保护R0--R7

    {

  tempbf3[ib]=temp[ib];

}

}

    if(test1_1==0) //第一次执行

{ //执行新进程,恢复现场

test1_1=1;

    *((unsigned char *)(SP-4))=ac1>>8; //PC的高字节

        *((unsigned char *)(SP-5))=ac1 & 0x00ff; //PC的低字节

}

else//非第一次执行

{ //执行新进程,恢复现场

*((unsigned char *)(SP-4))=address1>>8;   //PC的高字节

        *((unsigned char *)(SP-5))=address1 & 0x00ff;  //PC的低字节

*((unsigned char *)(SP))=table1[0];   //现场恢复

*((unsigned char *)(SP-1))=table1[1];   //现场恢复

*((unsigned char *)(SP-2))=table1[2];   //现场恢复

*((unsigned char *)(SP-3))=table1[3];   //现场恢复

for(ib=0;ib<=7;ib++) //恢复R0--R7

    {

 temp[ib]=tempbf1[ib];

}

}

   TH0=TN1/256;

   TL0=TN1%256;

       TR0=1;

      }break;

  case 2:

  {

    if(test1_1!

=0)   //第一次否?

    {  //保存现场,还回地址,否

   address1=*((unsigned char *)(SP-4)); //PC的高字节

           address1 <<= 8;

           address1+=*((unsigned char *)(SP-5));  //PC的低字节

   table1[0]=*((unsigned char *)(SP));   //现场保护

   table1[1]=*((unsigned char *)(SP-1));//现场保护

   table1[2]=*((unsigned char *)(SP-2));//现场保护

   table1[3]=*((unsigned char *)(SP-3)); //现场保护

   for(ib=0;ib<=7;ib++)  //保护R0--R7

    {

  tempbf1[ib]=temp[ib];

}

}

if(test2_1==0)//第一次

{ //执行进程2,恢复现场

test2_1=1; 

    *((unsigned char *)(SP-4))=ac2>>8; //PC的高字节

        *((unsigned char *)(SP-5))=ac2 & 0x00ff; //PC的低字节

}

else   //非第一次

{ //执行进程2,恢复现场

*((unsigned char *)(SP-4))=address2>>8;//PC的高字节

        *((unsigned char *)(SP-5))=address2 & 0x00ff; //PC的低字节

*((unsigned char *)(SP))=table2[0]; //现场恢复

*((unsigned char *)(SP-1))=table2[1]; //现场恢复

*((unsigned char *)(SP-2))=table2[2]; //现场恢复

*((unsigned char *)(SP-3))=table2[3];  //现场恢复

for(ib=0;ib<=7;ib++)//恢复R0--R7

    {

  temp[ib]=tempbf2[ib];

}

}

       TH0=TN2/256;

    TL0=TN2%256;

        TR0=1;

  }break;

   case 3:

   { 

    if(test2_1!

=0)

    {  //保存现场,还回地址

   address2=*((unsigned char *)(SP-4));  //PC的高字节

           address2 <<= 8;

           address2+=*((unsigned char *)(SP-5));   //PC的低字节

   table2[0]=*(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1