关于多线程工作

技术分享定时中断实现任务切换 技术分享
如图 4A 所示,CPU 在空闲任务循环等待,定时中断将 CPU 周期性唤回,根据任务设计
了不同的响应频度,满足条件的任务将获得CPU资源,CPU为不同任务“关照”完成后,再
次返回空闲任务,如此周而复始,对于各个任务而言,好像各自拥有一个独立的CPU,各自
独立运行。用这种思想构建的程序框架,最大的好处是任务很容易裁剪,系统能够做得很复
杂。
在充分考虑单片机中断特性(在哪里中断就返回到哪里)后,实际可行的任务切换如图
4B所示,定时中断可能发生在任务调度,随机任务执行的任何时候,图中最大的框框所示,
不管中断在何时发生,它都会正常返回,定时中断所产生的影响只在任务调度模块起作用,
即依次让不同的任务按不同的节拍就绪。任务调度会按一定的优先级执行就绪任务。
总结不同的任务需要CPU关照的频度,选择最快的那个频度来设定定时器中断的节拍,
一般选择 200Hz,或者 100Hz 都可以。另外再给每个任务设定一个节拍控制计数器 C,也就
是定时器每中断多少次后执行任务一次。例如取定时中断节拍为 200Hz,给任务设定的 C=10,
则任务执行频度为 200/10=20Hz,如果是数码管扫描,按 40Hz 不闪烁规律,则任务节拍控制
计数器 C=5 即可。在程序设计中,C 代表着任务运行的节拍控制参数,我们习惯用 delay 来
描述,不同的任务用task0,task1……来描述。
明天继续写如何用代码实现!2009-6-29
下面我们来用代码实现以上多任务程序设计思想。
首先是任务切换
while(1)
{
if(task_delay[0]==0)   task0();  //task0就绪,
if(task_delay[1]==0)   task1();  //task1就绪,
……
}
很显然,执行任务的条件是任务延时量task_delay=0,那么任务延时量谁来控制呢?定时
器啊!定时器中断对任务延时量减一直到归零,标志任务就绪。当没有任务就绪时,任务切
换本身就是一个Idle 任务。
void timer0(void) interrupt 1
{
if(task_delay[0]) task_delay[0]--;
if(task_delay[1]) task_delay[1]--;
……
}
例如 timer0 的中断节拍为 200Hz,task0_delay 初值为 10,则 task0()执行频度为
200/10=20Hz。
有了以上基础,我们来设计一个简单多任务程序,进一步深入理解这种程序设计思想。
任务要求:用单片机不同 IO 脚输出 1Hz,5Hz,10Hz,20Hz 方波信号,这个程序很短,将
直接给出。
#include "reg51.h"
#define TIME_PER_SEC 200    //定义任务时钟频率,200Hz
#define CLOCK 22118400    //定义时钟晶振,单位Hz  
#define MAX_TASK 4      //定义任务数量

extern void task0(void);  //任务声明
extern void task1(void);
extern void task2(void);
extern void task3(void);

sbit f1Hz  = P1^0;  //端口定义
sbit f5Hz  = P1^1;
sbit f10Hz = P1^2;
sbit f20Hz = P1^3;

unsigned char task_delay[4];  //任务延时变量定义

//定时器0初始化
void timer0_init(void)
{
    unsigned char i;
   for(i=0;i<MAX_TASK;i++) task_delay=0;  //任务延时量清零
    TMOD = (TMOD & 0XF0) | 0X01;        //定时器 0工作在模式 1, 16Bit定时器模
式  
    TH0 = 255-CLOCK/TIME_PER_SEC/12/256;   
  TL0 = 255-CLOCK/TIME_PER_SEC/12%256;   
   TR0 =1;  
ET0 =1;         //开启定时器和中断
}

// 系统 OS定时中断服务
void timer0(void) interrupt 1
{
    unsigned char i;
    TH0 = 255-CLOCK/TIME_PER_SEC/12/256;
    TL0 = 255-CLOCK/TIME_PER_SEC/12%256;        
    for(i=0;i<MAX_TASK;i++) if(task_delay) task_delay--;  
//每节拍对任务延时变量减1 ,减至 0  后,任务就绪。   
}   

/*main主函数*/
void main(void)
{
    timer0_init();
    EA=1;//开总中断   
   while(1)
   {  
     if(task_delay[0]==0) {task0(); task_delay[0] = TIME_PER_SEC/ 2;}
  //要产生 1hz 信号,翻转周期就是 2Hz,以下同
  if(task_delay[1]==0) {task1(); task_delay[1] = TIME_PER_SEC/10;}
  //要产生 5hz 信号,翻转周期就是 10Hz,以下同
  if(task_delay[2]==0) {task2(); task_delay[2] = TIME_PER_SEC/20;}
  if(task_delay[3]==0) {task3(); task_delay[3] = TIME_PER_SEC/40;}     
   }
}

void task0(void)
{   
    f1Hz = !f1Hz;   
}

void task1(void)
{   
    f5Hz = !f5Hz;   
}

void task2(void)
{   
    f10Hz = !f10Hz;   
}

void task3(void)
{   
    f20Hz = !f20Hz;   
}

(他的程序粘贴下来我自己改了一下)

#include <reg51.h>
#define TIME_PER_SEC 200    //定义任务时钟频率,200Hz
#define CLOCK 22118400    //定义时钟晶振,单位Hz  
#define MAX_TASK 4      //定义任务数量

extern void task0(void);  //任务声明
extern void task1(void);
extern void task2(void);
extern void task3(void);

sbit f1Hz  = P1^0;  //端口定义
sbit f5Hz  = P1^1;
sbit f10Hz = P1^2;
sbit f20Hz = P1^3;

unsigned char task_delay[4];  //任务延时变量定义

//定时器0初始化
void timer0_init(void)
{
    unsigned char i;
   for(i=0;i<MAX_TASK;i++) task_delay[i]=0;  //任务延时量清零
    TMOD = (TMOD & 0XF0) | 0X01;        //定时器 0工作在模式 1, 16Bit定时器模式  
    TH0 = 220;   
      TL0 = 30;                                //定时器0定时周期10us
    TR0 =1;  
    ET0 =1;         //开启定时器和中断
}

// 系统 OS定时中断服务
void timer0(void) interrupt 1
{
    unsigned char i;
    TH0 = 220;
    TL0 = 30;        
    for(i=0;i<MAX_TASK;i++)
    {
        if(task_delay[i])
            task_delay[i]--;
        if(i==MAX_TASK)
            i=0;
    }
//每节拍对任务延时变量减1 ,减至 0  后,任务就绪。   
}   

/*main主函数*/
void main(void)
{
    timer0_init();
    EA=1;//开总中断   
   while(1)
   {  
     if(task_delay[0]==0) {task0(); task_delay[0] = TIME_PER_SEC/ 2;} //执行一次后不断填充新值
  //要产生 1hz 信号,翻转周期就是 2Hz,以下同
  if(task_delay[1]==0) {task1(); task_delay[1] = TIME_PER_SEC/10;}      //执行一次后不断填充新值
  //要产生 5hz 信号,翻转周期就是 10Hz,以下同
  if(task_delay[2]==0) {task2(); task_delay[2] = TIME_PER_SEC/20;}       //执行一次后不断填充新值
  if(task_delay[3]==0) {task3(); task_delay[3] = TIME_PER_SEC/40;}     //执行一次后不断填充新值
   }
}

void task0(void)
{   
    f1Hz = !f1Hz;   
}

void task1(void)
{   
    f5Hz = !f5Hz;   
}

void task2(void)
{   
    f10Hz = !f10Hz;   
}

void task3(void)
{   
    f20Hz = !f20Hz;   
}

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。