51单片机的多任务实时系统开发

Posted tianqiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51单片机的多任务实时系统开发相关的知识,希望对你有一定的参考价值。

51单片机的多任务实时系统开发 

   
 
 
技术分享图片 dagu 发表于 2015-4-5 22:28 显示全部楼层
    前言:
        此文章适合对51单片机感兴趣,也想利用51实现简单的实时系统的程序管理,适合学习交流用,望谨慎吐槽。


   准备一:
     所谓实时呢,这个概念三言两语不好解释, 在这里就不涉及太多的官方及专业名词和术语。就像你用电饭煲做饭一样,当你启动后,是希望它一直工作,直到把 饭做好,而不希望它会中途出现故障什么的。然后在中断,你希望想煮粥,那就停了电,再加水,调成煮粥模式,然后继续工作,直到完成。这个,就有点实时的解 释吧,如果这个解释不够形象,要不再举例另一个,请私下联系再作举例。
   所谓多任务呢,这个应该不难解释了,不过,还是再罗嗦一下。51单片机,就只有一个CPU,就像你在厨房做饭,只有你一个人,你又想煮饭,又想烧菜,还 想打扫卫生,但你一个人,不可能同时做的。所以,一个重要的概念就在这里。一个CPU不可能同时做这么多做事的。所以,它不得不像人一样,一会做这个,一 会做那个。比如10分钟扫一下地,然后10分钟烧一个菜,然后10分钟 去上个厕所,然后10分钟再回来扫一下地。就这样把时间分配好,但以一个小时来 看,就感觉你这一个小时是几个工作同时在做,而且这几个事互不影响的。
    好了,有了这两个概念就差不多了。
    51单片机靠什么来得到这个确定的时间,并把它分割成一段一段的呢。
   下面就以一个多任务系统来说,因为51单片机的储存空间不够,一般不适合做大的系统移植。玩过STM32的人应该清楚uC/OS系统的移植,把uC /OS移植到51单片机,也不无不可,只是光是把一个系统移植上去,单片机就没有多少空间做其它事了。就好比说,你一个硬盘是40G的,你装了个win 7系统后都差不多占了20G了,那你硬盘就没有多少空间再做其它事了。
   uC/OS不好移植了,就更别说把linux系统移植给51单片机了。那,就没有合适给51单片机的吗?答案是有的。
   如果你使用增强型的51单片机,还是可以考虑对uC/OS裁剪移植的。
   不过,对于增强型,还是普通型,还是基本51内核的单片机,都有一个比较适合做简单的多任务系统开发的。

  在KEIL里,开发了一个适合对51使用的多任务实时系统的开发的。就是RTX51系统。
  RTX51分有两个,一个是RTX51FULL,一个是RTX51TINY。
  在这里介绍RTX51TINY。
  对系统的移植,也不算移植吧,
   从硬件的角度来说,就是对CPU的时间调度做出设置,用来管理内存,时间等。越大的系统管理的越多,管理的也越周到,但操作也越复杂。
  从软件的角度来说,就是添加把一系列的库文件添加在程序里,然后,在程序里对库里的子程序调用就可了。越大的系统里,提供的库函数就越多,库函数越多,调 用越来考虑的就越多。库函数越少呢,程序应该会清晰一些,当然实现的功能及管理就跟不上去了。但对于51来说,RTX51TINY还是可以的。

   好,下面就一步一步来使用RTX51TINY来实现51的多任务的吧。

 一,库文件的添加及KEIL的设置。
  #include <rtx51tny.h>   //rtx51tny.h这个文件就是RTX51TINY的库文件,只有一个文件,因为这个文件是keil里包含有的,不必去哪里找。            
   #include <reg51.h>
 然后就是打开工程的设置,如图:
  技术分享图片 
  在Target这个选项里,找到如图中那个,选择RTX51 Tiny这个选项,这样,在编译的时候,就不用提示头文件不存在了。
这便是第一步在完成的。
 
二,对rtx51tny.h的解读。
   
    从软件的角度,也只是把这个头文件添加进来,然后对库函数做出调用。
 技术分享图片
 这个库文件的函数就这几个,所以,实现多任务管理,只要恰当的使用这个函数就可以了。
  其中,常用的几个函数是  os_create_task(),os_send_signal(),os_wait().。由于os_wait1和os_wait2的这两个函数是差不多的, 
 。
三,以一个简单的程序分析:
   #include <rtx51tny.h>               
#include <reg51.h>
void  job()  _task_  0  
{                  
  os_create_task (1);                
  os_create_task (2);              
  os_create_task (3); 
    while(1)
{   
     P1=~P1;
 os_wait(K_TMO,50,0);
}   
}
 
void  num1() _task_ 1 
{
                     
   while(1)
{   
     P0=~P0;
     os_wait(K_TMO,100,0);
}                      
}
 
void num2 () _task_ 2  
{
  while (1)  
  {                     
    P2=~P2;                     
    os_wait1(K_SIG);
  }
}
 
void num4 () _task_ 3  
{
  while (1)  {                     
           
    P3=~P3;                     
  }
}

以上便是一个完整的程序。首先,这个程序有一个特点,就是没有main函数了。 下面,就对这个程序作出分析并对rtx51加深学习和理解。
void  job()  _task_  0  {}, 这个,便是一个任务,所谓任务,就是披着嫁衣的函数。void,这个,名义上可有可无,但,有为好,一般不需要做什么返回。job()这个,就是函数名了。这个job可以随便一个名字,自己可以随便起。 然后_task_是一个关键字,必须要有,表示你建的这个函数就是一个任务。  然后 0呢, 表示这个任务的优先级是0。拥有最高优先级。
   因为,使用rtx51这个,并没有main函数,所以,程序是从任务0开始的,然后,做任务0开始执行的后,程序该干嘛就干嘛了。那现在看一下任务0干了嘛。
  os_create_task (1);   ,这个,就是任务0做的事。就是创建了任务1。因为 void  num1() _task_ 1 {}只是定义了任务1的函数,或者只是定义了任务1该干什么的。但,程序没有调用到它,它就还不能正常工作。所以os_create_task (1);的工作就是调用了任务1,让任务1可以正常工作。然后,把任务1创建后,就和任务0无关了。同理,也可以os_delete_task(1);来删除任务1,这样,删除了任务1后,任务1里的内容就不再工作了。
  rtx51tiny这个可以定义16个任务。16个任务,对于用51实现的系统,基本就可以了。有一些初学者有点困惑的是,以为程序只是定义16个函数,这里只是说最大支持16个任务,而你要定义各种函数呢,定义多少个都可以的。
   然后,现在就是每个任务的作用,联系及区别了。
   以上程序定义了0,1,2,3共四个任务。 
任务0所做的是:
  while(1)
{   
     P1=~P1;
 os_wait(K_TMO,50,0);
}   
   就是在一定的时间间隔里,对P1的值取反。os_wait(K_TMO,50,0);这个函数就是等待时间溢出,具体参考os_wait()这个函数。K_TMO表示是对时间溢出的方式做出等待,K_SIG,这个表示对信号作出等待。如果用到了K_SIG,就要用到os_send_signal 这个函数,表示对某个任务发送信号。然后,那个函数接收到了另一个任务接收到的信号,就跳出等待,作出下一步的指令。这个的50呢,表示的是表示50个时 间间隔。就像刚才在厨房里的时间间隔为10分钟,那这里就等了50个分钟。在rtx51默认的时间间隔是0.01s,也就是10ms,100Hz.,那 50个时间间隔,就是间隔了0.5s,那任务0的功能就是每隔0.5来对P1的状态取反。

   同理,分析任务1就不难了。 也有一些人疑惑了,每个任务里都有一个while()循环,程序都进入了死循环,怎么再执行其它的指令呢。
 所 以,在这里需要接受的概念就是,每一个任务被建立之后,就不再管其它任务了,就自己在做自己的事了。每个程序就相当于一个main函数一样了。或者这么 说,一个12Mhz的晶振,你定义了12个任务,然后,这个CPU就被分成12个CPU,每一个CPU的时钟频率为1Mhz,然后,每个CPU就在做自己 的事,和其它CPU无关,只是两个CPU之间是可以通信管理了。这样的解释虽然不恰当,不过,还是很形象地让不少同学接受了这个概念。

     以上便是一个简单的多任务管理了。它有什么优点,这个, 就看你程序的用途了。举个简单的说法吧,比如你要用51单片机实现键盘的扫描,又要实现数码管 的动态扫描显示,还要实现通信,管理,控制等信息。其中一点,要做到键盘的扫描,就必须让程序至少在每10ms内或者更严格的时间里,对键盘作出扫描,那 么,这个扫描程序如果用中断来实现的话,还是可以接受的,但如果不是用中断,而是在非中断程序里实现的话,但,你的程序还是要做其它事的,而且程序在做其 它的事的情况下,还要照顾的键盘的扫描。还有数码管的动态扫描,如果用定时中断来说才能保证程序不因其它指令的执行而影响了数码管显示的延迟或不稳定。但 要保证这些都要照顾到,程序写起来就毕竟麻烦了。但如果采用了这种多任务的方式的话,就免去了这个麻烦了。比如,键盘扫描就定义成一个任务,这样,这个任 务的工作就是键盘的扫描,其它事也不做,这样,就不受其它程序段的影响,而且这个任务也可以方便的移植到相同的系统中去。数码管的显示也定义一个任务来实 现。
    比如你还想添加一个超声波的显示上去,那么,你只要再定义多一个任务用来作超声波测距的就可以了。对原有程序几乎不需要作修改,而且对原来的程序结构也不改变。

以上的程序只是一个简单的例子,而且很多人搜索的时候,也一般很容易搜索到这个类似的简单的例子。
下面献上自己编写的,根据超声波测距控制小车的前进后退的程序:
     #include <rtx51tny.h>               
#include <reg51.h>
 
sbit left0=P1^0;                       
sbit left1=P1^1;                     
sbit right0=P1^2;                      
sbit right1=P1^3;
sbit echo=P3^3;
sbit trig=P3^5;
typedef unsigned char uchar;
typedef unsigned int uint;
long  numecho=0;
uint num;
job0 () _task_ 0  
  { 
                
  os_create_task (1);  
  os_create_task (2);              
  os_create_task (3);  
  os_create_task (4);
  os_create_task (5);  
  TMOD=0x91;
   while(1)
{   
    }   
 }
 
void back () _task_ 2  
{
    while(1)
{   
     
    os_wait1(K_SIG);
left0=1;
left1=0;
right0=0;
right1=1;
 }
}                      
void go () _task_ 1 
{
    while (1)  
  {                     
      os_wait1(K_SIG);
left0=0;
left1=1;
right0=1;
right1=0;
    }
}
 
 
void Echo_test () _task_ 3  
{
 while (1) 
   {  
         trig=0;
  trig=1;
  TL1=0;
  TH1=0;
  os_wait(K_TMO,1,0);
  trig=0;
  TR1=1;
  os_wait(K_TMO,2,0);
  numecho=TH1*256+TL1;
  num=numecho*346/1000/2;
          }
}
 void panduan(void) _task_ 4
 {
    while(1)
{
  if(num>500)
  {
    os_send_signal(1);
  }
  if(num<500)
  {
    os_send_signal(2);
  }
  if(num<200)
  {
    os_send_signal(5);
  }
}   
   
 }
 
 
void stop() _task_ 5
{
   while (1)  
  {                     
        os_wait1(K_SIG);
left0=1;
left1=1;
right0=1;
right1=1;
   } 
}


在这个程序里,任务3就是作的是超声波的测距,这个任务是不停在做,也就是超声波在不断的测距,把测到的距离存到num这个全局变量里,然后任务4就是根据距离作出判断,根据不作的距离,让小车前进,后退或停止。
   

  最后,对这个系统再作一些解释。这个系统呢,肯定是用到了51单片机的资源的。首先,它需要做cpu作时间分割,那么就要用到定时器。这里就用了定时器0 来作定时用的。采用了工作方式1,并采用中断方式。所以,在使用的时候,一定要注意,不能改变了TMOD里对定时器0的设置,也就是低四位的数值。也就是 说TMOD的值为0x01的,如果需要定时器1的时候,需要注意的。还有中断,已经开户了全局中断和定时器0的中断,所以,要用到中断的时候,一定要注 意,不要在设置中断的时候,把IE的值对应的中断值改变了,这是注意一点的。

 而 且,学会了51的简单的多任务实时系统的开发,那么,再去学STM32的嵌入式操作系统就不难了。只不过,嵌入式操作系统要操作和管理调用的库函数比较 多,需要修改的参数也比较多,而且,也要对内存管理,时钟,系统等作进一步了解。这样,从51向嵌入式的转型就更容易了。
    寥寥数语,不能把RTX51解释清楚,更多的功能,还得靠读者自己去发挥,出现的问题 也待大家去发现并解决了。
































































以上是关于51单片机的多任务实时系统开发的主要内容,如果未能解决你的问题,请参考以下文章

关于单片机实时系统的问题KEIL中的rtx51tny

51单片机上实时多任务操作系统-教程

从头开始编写一个实时嵌入式操作系统的内核

51单片机 LCD1602+DS1302实时时钟+Proteus仿真

什么是unix 多任务

STM32CubeMX学习笔记(34)——FreeRTOS实时操作系统使用(任务通知)