登录 立即注册

电子DIY创易联盟

查看: 1417|回复: 7

超简单实用的基于C51的多任务机制及应用

[复制链接]
#论坛管理认证#  论坛管理认证

累计签到:112 天
连续签到:1 天

122

帖子

1461

积分

3

听众

版主

Rank: 18Rank: 18

积分
1461
发表于 2017-10-11 15:01:11 | 显示全部楼层 |阅读模式

终于等到你!马上注册,和广大电子DIY爱好者一起玩耍,还有更多功能和福利等着你!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
    大家好!
        

    我 Alex 又来了!
    这次带来的是《基于C51的多任务机制及应用序》。
    抛砖引玉,等你发大挥哦。

    希望这次能给大家带来点有用的资讯!
    谢谢围观!
    好人1生平安!


摘要:本文介绍了一种在MCS51单片机程序中实现多任务机制的简单方法,并给出了源代码和一个应用实例。通过中断进行实时任务切换,具有结构简单清晰、代码量少、不需使用汇编等优点。该方法亦可应用于其他单片机系统。

关键词:多任务系统 单片机 C51  中断 安防系统


源码实例:
    实现这个多任务机制的完整源代码如下:

  1. word idata PC_Value, SP_Value;    //储存中断返回点、SP初值的全局变量
  2. byte idata Ctrl_Code;             //控制任务切换的全局变量,在中断函数里被赋值
  3. void main()               
  4. {
  5.   Initial();                      //初始化函数,与程序结构无关
  6.   SP_Value=SP;                   //获取SP的初始值
  7.   PC_Value=Get_Next_PC();         //获取下一条指令的地址
  8.   EA=1;                           //获取PC、SP初值后再开中断保证稳定性
  9.   if(Ctrl_Code!=0)
  10.   SP=SP_Value;                   //重置堆栈指针,防止堆栈溢出
  11.   switch( Ctrl_Code)             //任务入口地址,即中断的返回点
  12.   {
  13.     case 1:   goto  TASK1;
  14.     case 2:   goto  TASK2;
  15.     case 3:   goto  TASK3;
  16.     default:  break;
  17.   }
  18.   TASK1:
  19.   for( ; ; )
  20.   {
  21.                                  //任务1代码
  22.   }
  23.   TASK2:
  24.   for( ; ; )
  25.   {
  26.                                 //任务2代码
  27.   }
  28.   TASK3:
  29.   for( ; ; )
  30.   {
  31.                                //任务2代码
  32.   }
  33. }

  34. word Get_Next_PC(void)                   //获取下一条指令的地址
  35. {
  36.   word address;
  37.   address=*((unsigned char *)SP);       //PC的高字节
  38.   address <<= 8;
  39.   address+=*((unsigned char *)(SP-1));  //PC的低字节
  40.   return address+4;                     //查看反汇编代码,计算所得
  41. }

  42. void Chuan_Kou_Interrupt(void) interrupt 4 using 0
  43. {
  44.   byte a1,a2;
  45.   a1=a1*a2;
  46.   *((unsigned char *)(SP-5))=PC_Value>>8;
  47.   *((unsigned char *)(SP-6))=PC_Value & 0x00ff;
  48.   {
  49.                                         //接收串口代码并根据代码修改Ctrl_Code的值
  50.                                         //其他操作
  51.   }
  52. }
复制代码


任务调度原理与实现
    程序的整体思路是在主函数main中依次放置几个死循环作为任务框架,即每个任务都是一个死循环,利用中断进行任务切换。以刚才所说的安防系统为例,由于主板、键盘、管理中心之间是通过串口通讯的,因此串口是用来触发任务切换的理想中断源。程序为所有任务设置一个总入口并放在主函数中,串口中断每次返回时必须先经过这个总入口,在总入口处检查任务控制变量(全局变量)的值,任务控制变量已在串口中断中被赋值,其值决定要切换到哪个任务。

    设计中可以把平时状态、入侵报警状态、危机报警状态、功能设置状态分别作为任务1、任务2、任务3、任务4。主板CPU平常工作在平时状态,即任务1;当串口收到管理中心的危机代码,在串口中断函数中令Ctrl_Code = 3,中断返回后会切换到任务3;同样,接收到键盘的功能设置代码后,会切换到任务4;由于入侵检测是由主板CPU自己负责,因此如果检测到有人入侵需要切换到入侵报警状态时,可以借由键盘中转产生串口中断,即向键盘发送一串口数据并要求键盘回送。这样就实现了各个状态的切换。

实现任务调度需要解决3个关键问题:
    ① 获取任务入口点的程序地址。由于使用C语言不能直接获取和修改程序计数器PC的值,而在调用函数时会将PC值入栈,利用这个特点在任务入口处之前调用Get_Next_PC函数即可从堆栈中获得入口地址。Get_Next_PC中,SP为堆栈指针,得到的PC值要加4才是任务入口地址,因为查看反汇编窗口可知,将函数返回值传给全局变量PC_Value需要两条2字节长的mov指令。

    ② 修改中断返回地址。修改中断返回地址的操作与获取PC值类似,都是通过修改堆栈中的内容实现。但是由于编译器自身的特点,在进入中断时,编译器除了把返回地址入栈外,还会计算自身及它所调用的函数对寄存器ACC、 B、 DPH、 DPL、 PSW、 R0 ~ R7的改变,并将它认为被改变了的寄存器也入栈保护。如果堆栈结构会随中断函数内容改变而变化,就没办法计算中断返回地址堆栈中的位置。解决方法是,在中断函数定义时加上关键字using 0 告诉编译器中断函数及其调用的函数将使用寄存器组0,这样工作寄存器R0~R7将不会被保存。ACC、PSW、DPH、DPL在对PC_Value操作时已经用到,在中断函数开头定义两个变量a1、b1并令它们相乘,使B寄存器也被入栈,这样堆栈的结构就是固定的了。

    ③防止堆栈溢出。由于在调用函数时编译器会将当前地址入栈,返回时再出栈,当任务切换即中断多次发生在函数调用过程中时,堆栈会因为只入不出而最终导致溢出。这是不能容许的。因此,应在主函数开头初始化后立刻将SP值保存,再在每次任务切换后都将SP恢复为初值,这可以有效防止堆栈溢出。

结语
    根据以上的比较与分析可以看出这种实现多任务机制的方法具有如下优点:与采用单任务机制的程序相比,其结构简单清晰,易于控制;利用中断和堆栈实现任务切换时的长跳转,完全不需使用汇编语言,可移植性强;增加的代码量极小,实时性好,节省程序开发时间。

    以上介绍的方法已经通过测试并应用于几个实际项目中,包括智能小区安防系统、汽车CAN总线控制系统等,取得了良好效果。只要根据具体的硬件与编译环境稍作修改,亦可应用于其他的单片机系统中。


欲知后事如何,请自行实现!
希望能对您有帮助!!!


#论坛管理认证#  论坛管理认证

累计签到:207 天
连续签到:1 天

233

帖子

2871

积分

10

听众

超级版主

Rank: 19Rank: 19Rank: 19

积分
2871

优秀版主

发表于 2017-10-11 15:37:25 | 显示全部楼层
本帖最后由 for人生 于 2017-10-11 17:52 编辑


写的挺好的,操作堆栈指针,很实用的程序,赞!
泰山不让土壤,故能成其大;河海不择细流,故能就其深;王者不却众庶,故能明其德。            ——丞相李斯
累计签到:173 天
连续签到:1 天

175

帖子

1536

积分

4

听众

CY-4级

Rank: 5Rank: 5Rank: 5

积分
1536
发表于 2017-10-11 16:47:55 | 显示全部楼层
感谢楼主的分享精神
累计签到:105 天
连续签到:1 天

141

帖子

1407

积分

3

听众

CY-4级

Rank: 5Rank: 5Rank: 5

积分
1407
发表于 2017-10-11 20:02:28 | 显示全部楼层
不错嘛,赞
#论坛管理认证#  论坛管理认证

累计签到:132 天
连续签到:1 天

119

帖子

1317

积分

6

听众

版主

Rank: 18Rank: 18

积分
1317

最佳新人

发表于 2017-10-12 08:46:51 | 显示全部楼层
不错的分享不错的讲解,温习一下
累计签到:330 天
连续签到:7 天

14

帖子

2019

积分

0

听众

CY-5级

Rank: 7Rank: 7Rank: 7

积分
2019
发表于 2017-10-12 20:12:14 | 显示全部楼层
厉害厉害,一直想写一个,楼主考虑过用定时器写一个吗,感觉你这个和多任务有点不太像
累计签到:1 天
连续签到:1 天

36

帖子

3

积分

0

听众

CY-1级

Rank: 1

积分
3
发表于 2017-11-22 16:30:29 | 显示全部楼层
谢谢楼主,楼主好人
累计签到:160 天
连续签到:1 天

6

帖子

961

积分

0

听众

CY-3级

Rank: 3

积分
961
发表于 2018-4-25 08:55:32 | 显示全部楼层
谢谢楼主

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 收藏帖子 搜索
快速回复 返回顶部 返回列表