• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

谈谈关于复杂性多任务程序的原理和设计程序

当你看到操作系统的多任务并行的时候,你是否觉的很神奇呢?你是否想过那些任务的时间片轮转是怎么实现的呢?这个时间片轮转的秘密是什么呢?相信很多单片机初学者都会对这个问题感兴趣。

当你查看单片机的汇编指令的时候,你是否留意过中断返回指令的操作过程?如果你留意过这个操作过程的话,你一定会发现它通过堆栈复原PC指针的过程。也就是说:当单片机产生中断的时候,它会把当前程序正在运行的PC指针保存在堆栈当中;然后当中断程序运行完毕的时候,程序执行中断返回指令,把堆栈中保存的PC指针再返回出来。

这个是单片机运行的正常情况,但是如果在单片机的中断中修改了堆栈中的PC指针值,那么是不是中断就返不回来原来的程序地址?如果还是这个地址是我故意设定的值那么他是不是执行完这个中断就跳到我的设定的这个地址上去了?

如果这个地址又是另外一个任务的地址的时候不是正好实现了从一个任务的死循环中跳到了另外一个任务的死循环中去了?对了!没错!多任务并行运行、时间片轮转的秘密就是:在定时中断中修改堆栈,使保存在中断中PC指针按照预定的方式改变从而让PC指针在几个任务地址中不停的跳转。

如果你有空去看UCOS的移植代码的时候,你会发现切换任务的asm函数就是在修改堆栈的内容。当然了,真正的任务的切换过程不仅仅是修改PC指针的堆栈内容,同时也修改了单片机所用到的所有可能被用到的寄存器的内容。

全部回复(15)
正序查看
倒序查看
001a
LV.3
2
2014-02-11 16:30

分享的是我写的一个双任务并行的程序。一个任务是“main”函数的死循环,另外一个任务是函数“task1”中的死循环。任务操作很简单,就是两个io口不停在切换电平,但是由于两个任务中的时间延时不一样而是切换电平的频率不一样。单片机用的是瑞萨k0s系列的单片机(应为这个是我工作中常用的型号,我现在对这个比较熟,而51单片机很久没有用过了,所以用的是这个型号,什么时候有空了我再写个51单片机的程序)。有这个系列单片机开发板的可以单步运行看看任务切换过程中“偷换”堆栈内容的过程。(后面将分享我在这个平台下写的一个简单的时间片轮转的小操作系统)修改堆栈内容的中断函数:

__interrupt void MD_INTTM80( void )

{

/* TODO */

#asm

push ax

push bc

push de

push hl

movw ax,sp

movw bc,ax

mov a,#0ffh

sub a, c

inc a

mov c,a ;the sp_long

;/*********************;load the sp_long*****************************/

mov a,c

mov !0fec0h,a ;load the sp_long

;/**************************************************/

mov b,a ;load the data

movw de,#0feffh

movw hl,#0fec1h

?L_mov1: mov a,[de]

mov [hl],a

decw de

dec b

incw hl

mov a,b

cmp a,#0h

bnz $?L_mov1

;/************************load the data to sp**************************/

mov a,!0fea0h ;load the data to sp

mov b,a

movw de,#0fea1h

movw hl,#0feffh

?L_mov2: mov a,[de]

mov [hl],a

incw de

dec b

decw hl

mov a,b

cmp a,#0h

bnz $?L_mov2

;/*************************get the new sp_point*************************/

mov a,#0ffh ;get the new sp_point

sub a,!0fea0h

inc a

mov !0fe90h,a

mov a,#0feh

mov !0fe91h,a

;/************************save the sp_data**************************/

mov a,!0fec0h ;save the sp_data

mov !0fea0h,a

mov b,a

movw de,#0fec1h

movw hl,#0fea1h

?L_mov_sp: mov a,[de]

mov [hl],a

incw de

dec b

incw hl

mov a,b

cmp a,#0h

bnz $?L_mov_sp

#endasm

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

#asm

mov a,!0fe90h

mov x,a

mov a,!0fe91h

movw sp,ax

pop hl

pop de

pop bc

pop ax

#endasm

}

 

附上原理图,之后咱们再谈谈如何设计复杂的多任务程序

程序和原理图:

AVR-多任务模拟系统设计(程序 原理图).rar

 

0
回复
matou
LV.3
3
2014-02-22 20:08
@001a
分享的是我写的一个双任务并行的程序。一个任务是“main”函数的死循环,另外一个任务是函数“task1”中的死循环。任务操作很简单,就是两个io口不停在切换电平,但是由于两个任务中的时间延时不一样而是切换电平的频率不一样。单片机用的是瑞萨k0s系列的单片机(应为这个是我工作中常用的型号,我现在对这个比较熟,而51单片机很久没有用过了,所以用的是这个型号,什么时候有空了我再写个51单片机的程序)。有这个系列单片机开发板的可以单步运行看看任务切换过程中“偷换”堆栈内容的过程。(后面将分享我在这个平台下写的一个简单的时间片轮转的小操作系统)修改堆栈内容的中断函数:__interruptvoidMD_INTTM80(void){/*TODO*/#asmpushaxpushbcpushdepushhlmovwax,spmovwbc,axmova,#0ffhsuba,cincamovc,a;thesp_long;/*********************;loadthesp_long*****************************/mova,cmov!0fec0h,a;loadthesp_long;/**************************************************/movb,a;loadthedatamovwde,#0feffhmovwhl,#0fec1h?L_mov1:mova,[de]mov[hl],adecwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov1;/************************loadthedatatosp**************************/mova,!0fea0h;loadthedatatospmovb,amovwde,#0fea1hmovwhl,#0feffh?L_mov2:mova,[de]mov[hl],aincwdedecbdecwhlmova,bcmpa,#0hbnz$?L_mov2;/*************************getthenewsp_point*************************/mova,#0ffh;getthenewsp_pointsuba,!0fea0hincamov!0fe90h,amova,#0fehmov!0fe91h,a;/************************savethesp_data**************************/mova,!0fec0h;savethesp_datamov!0fea0h,amovb,amovwde,#0fec1hmovwhl,#0fea1h?L_mov_sp:mova,[de]mov[hl],aincwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov_sp#endasm/**************************************************/#asmmova,!0fe90hmovx,amova,!0fe91hmovwsp,axpophlpopdepopbcpopax#endasm} 附上原理图,之后咱们再谈谈如何设计复杂的多任务程序[图片]程序和原理图:AVR-多任务模拟系统设计(程序原理图).rar 
这个想法不错,实现起来不知道难不难,能不能用c语言实现
0
回复
daylight
LV.4
4
2014-02-22 20:09
@001a
分享的是我写的一个双任务并行的程序。一个任务是“main”函数的死循环,另外一个任务是函数“task1”中的死循环。任务操作很简单,就是两个io口不停在切换电平,但是由于两个任务中的时间延时不一样而是切换电平的频率不一样。单片机用的是瑞萨k0s系列的单片机(应为这个是我工作中常用的型号,我现在对这个比较熟,而51单片机很久没有用过了,所以用的是这个型号,什么时候有空了我再写个51单片机的程序)。有这个系列单片机开发板的可以单步运行看看任务切换过程中“偷换”堆栈内容的过程。(后面将分享我在这个平台下写的一个简单的时间片轮转的小操作系统)修改堆栈内容的中断函数:__interruptvoidMD_INTTM80(void){/*TODO*/#asmpushaxpushbcpushdepushhlmovwax,spmovwbc,axmova,#0ffhsuba,cincamovc,a;thesp_long;/*********************;loadthesp_long*****************************/mova,cmov!0fec0h,a;loadthesp_long;/**************************************************/movb,a;loadthedatamovwde,#0feffhmovwhl,#0fec1h?L_mov1:mova,[de]mov[hl],adecwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov1;/************************loadthedatatosp**************************/mova,!0fea0h;loadthedatatospmovb,amovwde,#0fea1hmovwhl,#0feffh?L_mov2:mova,[de]mov[hl],aincwdedecbdecwhlmova,bcmpa,#0hbnz$?L_mov2;/*************************getthenewsp_point*************************/mova,#0ffh;getthenewsp_pointsuba,!0fea0hincamov!0fe90h,amova,#0fehmov!0fe91h,a;/************************savethesp_data**************************/mova,!0fec0h;savethesp_datamov!0fea0h,amovb,amovwde,#0fec1hmovwhl,#0fea1h?L_mov_sp:mova,[de]mov[hl],aincwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov_sp#endasm/**************************************************/#asmmova,!0fe90hmovx,amova,!0fe91hmovwsp,axpophlpopdepopbcpopax#endasm} 附上原理图,之后咱们再谈谈如何设计复杂的多任务程序[图片]程序和原理图:AVR-多任务模拟系统设计(程序原理图).rar 
单片机小型操作系统多任务并行的原理,不错
0
回复
001a
LV.3
5
2014-02-22 20:11
@001a
分享的是我写的一个双任务并行的程序。一个任务是“main”函数的死循环,另外一个任务是函数“task1”中的死循环。任务操作很简单,就是两个io口不停在切换电平,但是由于两个任务中的时间延时不一样而是切换电平的频率不一样。单片机用的是瑞萨k0s系列的单片机(应为这个是我工作中常用的型号,我现在对这个比较熟,而51单片机很久没有用过了,所以用的是这个型号,什么时候有空了我再写个51单片机的程序)。有这个系列单片机开发板的可以单步运行看看任务切换过程中“偷换”堆栈内容的过程。(后面将分享我在这个平台下写的一个简单的时间片轮转的小操作系统)修改堆栈内容的中断函数:__interruptvoidMD_INTTM80(void){/*TODO*/#asmpushaxpushbcpushdepushhlmovwax,spmovwbc,axmova,#0ffhsuba,cincamovc,a;thesp_long;/*********************;loadthesp_long*****************************/mova,cmov!0fec0h,a;loadthesp_long;/**************************************************/movb,a;loadthedatamovwde,#0feffhmovwhl,#0fec1h?L_mov1:mova,[de]mov[hl],adecwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov1;/************************loadthedatatosp**************************/mova,!0fea0h;loadthedatatospmovb,amovwde,#0fea1hmovwhl,#0feffh?L_mov2:mova,[de]mov[hl],aincwdedecbdecwhlmova,bcmpa,#0hbnz$?L_mov2;/*************************getthenewsp_point*************************/mova,#0ffh;getthenewsp_pointsuba,!0fea0hincamov!0fe90h,amova,#0fehmov!0fe91h,a;/************************savethesp_data**************************/mova,!0fec0h;savethesp_datamov!0fea0h,amovb,amovwde,#0fec1hmovwhl,#0fea1h?L_mov_sp:mova,[de]mov[hl],aincwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov_sp#endasm/**************************************************/#asmmova,!0fe90hmovx,amova,!0fe91hmovwsp,axpophlpopdepopbcpopax#endasm} 附上原理图,之后咱们再谈谈如何设计复杂的多任务程序[图片]程序和原理图:AVR-多任务模拟系统设计(程序原理图).rar 

写自己的小型单片机操作系统代码解析三:__interrupt void MD_INTTM80( void ) 解析:这用的C语言中嵌入汇编语言的方式写的汇编语言。实现的功能是我放第一贴讲的任务切换的汇编语言是一样的。简单说一下这里汇编实现的功能:

1、调用函数 stick_chang_task(void)获取当前任务堆栈的初始地址和下个任务堆栈的初始地址。

2、保存此时单片机中的堆栈内容到当前运行的任务的中的任务堆栈

3、把下一个任务中的任务堆栈数组的内容覆盖到单片机的堆栈中

4、根据下一个任务堆栈数组中的内容恢复SP的值

0
回复
001a
LV.3
6
2014-02-22 20:11
@001a
写自己的小型单片机操作系统代码解析三:__interruptvoidMD_INTTM80(void)解析:这用的C语言中嵌入汇编语言的方式写的汇编语言。实现的功能是我放第一贴讲的任务切换的汇编语言是一样的。简单说一下这里汇编实现的功能:1、调用函数stick_chang_task(void)获取当前任务堆栈的初始地址和下个任务堆栈的初始地址。2、保存此时单片机中的堆栈内容到当前运行的任务的中的任务堆栈3、把下一个任务中的任务堆栈数组的内容覆盖到单片机的堆栈中4、根据下一个任务堆栈数组中的内容恢复SP的值

自己的小型单片机操作系统代码解析二:

void cread_task(void(*task)(void),unsigned char *stack_) 解析

这个函数的作用是:建立死循环的任务。

参数:

task

任务函数。建立死循环任务的时候,任务的函数名,用来获取任务的函数名。

stack_

任务堆栈的数组指针。

os_sub_tasknum++;// 任务总数加1

ostask_stask_adress[(os_sub_tasknum-1)]=(unsigned int)stack_;//把当前任务 用的任务堆栈地址首地址,赋值到这个数组给任务调度分配的时候用,也就是当前时间片运行完后,决定运行那一个任务的时候就靠他了。

int_task(task,stack_);//初始化任务堆栈

void stick_chang_task(void) 解析

这个函数在 “时间中断函数”__interrupt void MD_INTTM80( void ) 中调用。用来实现任务调度的功能。在里,任务可以按照时间片一个个进行循环运行就是靠这个函数实现的。

old_task=ostask_stask_adress[os_cur_tasknum];//当前运行的任务堆栈首地址赋值给全局变量old_task

os_cur_tasknum++;//当前第几个任务

if(os_cur_tasknum>=os_sub_tasknum)

{

os_cur_tasknum=0;

}

new_task=ostask_stask_adress[os_cur_tasknum];//下一个要运行的任务堆栈首地址赋值给全局变量new_task

//判断是否是第一次任务切换时候用到。第一次任务切换的时候是从main中切换出来的,不需要保存当前的的堆栈内容,所以设这个值给“时间中断函数”__interrupt void MD_INTTM80( void ) 切换任务的时候进行判断

os_1st_time++;

if(os_1st_time>1)

{

os_1st_time=2;

}

0
回复
001a
LV.3
7
2014-02-22 20:13
@001a
自己的小型单片机操作系统代码解析二:voidcread_task(void(*task)(void),unsignedchar*stack_)解析这个函数的作用是:建立死循环的任务。参数:task任务函数。建立死循环任务的时候,任务的函数名,用来获取任务的函数名。stack_任务堆栈的数组指针。os_sub_tasknum++;//任务总数加1ostask_stask_adress[(os_sub_tasknum-1)]=(unsignedint)stack_;//把当前任务用的任务堆栈地址首地址,赋值到这个数组给任务调度分配的时候用,也就是当前时间片运行完后,决定运行那一个任务的时候就靠他了。int_task(task,stack_);//初始化任务堆栈voidstick_chang_task(void)解析这个函数在“时间中断函数”__interruptvoidMD_INTTM80(void)中调用。用来实现任务调度的功能。在里,任务可以按照时间片一个个进行循环运行就是靠这个函数实现的。old_task=ostask_stask_adress[os_cur_tasknum];//当前运行的任务堆栈首地址赋值给全局变量old_taskos_cur_tasknum++;//当前第几个任务if(os_cur_tasknum>=os_sub_tasknum){os_cur_tasknum=0;}new_task=ostask_stask_adress[os_cur_tasknum];//下一个要运行的任务堆栈首地址赋值给全局变量new_task//判断是否是第一次任务切换时候用到。第一次任务切换的时候是从main中切换出来的,不需要保存当前的的堆栈内容,所以设这个值给“时间中断函数”__interruptvoidMD_INTTM80(void)切换任务的时候进行判断os_1st_time++;if(os_1st_time>1){os_1st_time=2;}

写自己的小型单片机操作系统代码解析一

:我写的这个小型操作系统核心代码在工程的“mini_os”目录下。从今天开始将陆续对mini_os.c文件的函数进行解析。里面总共4个函数,分别是:

void cread_task(void(*task)(void),unsigned char *stack_);

void int_task(void(*task)(void),unsigned char *stack_);

void stick_chang_task(void);

__interrupt void MD_INTTM80( void );

他们分别实现的功能是:建立任务API函数;初始化任务函数,在建立任务函数中掉用;实现任务调度顺序的函数;实现任务切换的核心代码,是汇编语言写的。void int_task(void(*task)(void),unsigned char *stack_);

解析:可能很多人看着个函数都觉的很奇怪,为啥全是赋值?操作系统说白是用代码虚拟一个CPU出来,那么你想想,一个CPU要想运行是不是需要自己的基本数据空间呢?那就对了。这个作为一个任务的初始化函数,那肯定得给一个任务虚拟一段这任务的数据空间了。这一段数据通常被称为任务堆栈。所以任务建立的时候每一个任务都要建立自己的一个数组所为任务堆栈,不同的任务是不能共用同一个数组作为任务堆栈的。这个数据结构包括:数据的长度(两个字节)、PSW、任务函数的地址、通用寄存器的。这个结构的顺序并不是固定的,但是要和任务切换函数里写的要一致。

0
回复
close3
LV.5
8
2014-02-22 20:15
混合编程,多谢分享
0
回复
001a
LV.3
9
2014-02-22 20:17
@001a
分享的是我写的一个双任务并行的程序。一个任务是“main”函数的死循环,另外一个任务是函数“task1”中的死循环。任务操作很简单,就是两个io口不停在切换电平,但是由于两个任务中的时间延时不一样而是切换电平的频率不一样。单片机用的是瑞萨k0s系列的单片机(应为这个是我工作中常用的型号,我现在对这个比较熟,而51单片机很久没有用过了,所以用的是这个型号,什么时候有空了我再写个51单片机的程序)。有这个系列单片机开发板的可以单步运行看看任务切换过程中“偷换”堆栈内容的过程。(后面将分享我在这个平台下写的一个简单的时间片轮转的小操作系统)修改堆栈内容的中断函数:__interruptvoidMD_INTTM80(void){/*TODO*/#asmpushaxpushbcpushdepushhlmovwax,spmovwbc,axmova,#0ffhsuba,cincamovc,a;thesp_long;/*********************;loadthesp_long*****************************/mova,cmov!0fec0h,a;loadthesp_long;/**************************************************/movb,a;loadthedatamovwde,#0feffhmovwhl,#0fec1h?L_mov1:mova,[de]mov[hl],adecwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov1;/************************loadthedatatosp**************************/mova,!0fea0h;loadthedatatospmovb,amovwde,#0fea1hmovwhl,#0feffh?L_mov2:mova,[de]mov[hl],aincwdedecbdecwhlmova,bcmpa,#0hbnz$?L_mov2;/*************************getthenewsp_point*************************/mova,#0ffh;getthenewsp_pointsuba,!0fea0hincamov!0fe90h,amova,#0fehmov!0fe91h,a;/************************savethesp_data**************************/mova,!0fec0h;savethesp_datamov!0fea0h,amovb,amovwde,#0fec1hmovwhl,#0fea1h?L_mov_sp:mova,[de]mov[hl],aincwdedecbincwhlmova,bcmpa,#0hbnz$?L_mov_sp#endasm/**************************************************/#asmmova,!0fe90hmovx,amova,!0fe91hmovwsp,axpophlpopdepopbcpopax#endasm} 附上原理图,之后咱们再谈谈如何设计复杂的多任务程序[图片]程序和原理图:AVR-多任务模拟系统设计(程序原理图).rar 
补充下,任务切换是不分优先级的
0
回复
001a
LV.3
10
2014-02-22 20:20

今天公开我的之前写的仿UCOS(只有多任务切换的功能,是我发的第一个贴的程序的升级版),任务建立的多少跟ram的空间大小有关,平台MCU:NEC 公司的(现在为瑞萨公司)k0s系列9234,开发环境PM+。

任务调用程序一览:

void task1(void);//任务1函数声明

void task2(void);/任务2函数声明

void task3(void);/任务3函数声明

unsigned char task1_stask[30],task2_stask[30],task3_stask[30];//任务堆栈用到的数据空间

void delay(unsigned int i)

{

while(i--);

}

unsigned int ii1,ii2;

unsigned char a1;

int j;

void main( void )

{

/* TODO. add user code */

static unsigned int j,i;

ii1=0;

ii2=0;

PM3.3=0;

PM3.2=0;

PM4.2=0;

//inti_task_sp();

#asm

mov a,#0feh

mov x,#0ffh

movw sp,ax

#endasm

//初始化SP指针

cread_task(task1, task1_stask);

cread_task(task2, task2_stask);

cread_task(task3, task3_stask);

//建立三个任务

TM80_Start();

//开始任务调度

while(1);

}

void task1(void)//任务1内容

{

static unsigned int i;

i=1;

stask_:

while(1)

{

//ii2++;

//i=50000;

P3.2=~P3.2;

delay(20000);

//while(i--);

}

ii2++;

ii2++;

ii2++;

goto stask_;

}

void task2(void)//任务2内容

{

main_:

while(1){

//ii1++;

//j=300;

P3.3=~P3.3;

delay(1000);

//while(j--);

//j=10000;

//while(j--);

//i=10000;

//while(i--);

//i=10000;

//while(i--);

}

//ii1++;

//ii1++;

//ii1++;

goto main_;

}

void task3(void)//任务3内容

{

main_:

while(1){

//ii1++;

//j=300;

P4.2=~P4.2;

delay(4000);

//while(j--);

//j=10000;

//while(j--);

//i=10000;

//while(i--);

//i=10000;

//while(i--);

}

//ii1++;

//ii1++;

//ii1++;

goto main_;

}

caozuoxintong_v3.1.zip

0
回复
for_real
LV.3
11
2014-02-22 20:22
@001a
今天公开我的之前写的仿UCOS(只有多任务切换的功能,是我发的第一个贴的程序的升级版),任务建立的多少跟ram的空间大小有关,平台MCU:NEC公司的(现在为瑞萨公司)k0s系列9234,开发环境PM+。任务调用程序一览:voidtask1(void);//任务1函数声明voidtask2(void);/任务2函数声明voidtask3(void);/任务3函数声明unsignedchartask1_stask[30],task2_stask[30],task3_stask[30];//任务堆栈用到的数据空间voiddelay(unsignedinti){while(i--);}unsignedintii1,ii2;unsignedchara1;intj;voidmain(void){/*TODO.addusercode*/staticunsignedintj,i;ii1=0;ii2=0;PM3.3=0;PM3.2=0;PM4.2=0;//inti_task_sp();#asmmova,#0fehmovx,#0ffhmovwsp,ax#endasm//初始化SP指针cread_task(task1,task1_stask);cread_task(task2,task2_stask);cread_task(task3,task3_stask);//建立三个任务TM80_Start();//开始任务调度while(1);}voidtask1(void)//任务1内容{staticunsignedinti;i=1;stask_:while(1){//ii2++;//i=50000;P3.2=~P3.2;delay(20000);//while(i--);}ii2++;ii2++;ii2++;gotostask_;}voidtask2(void)//任务2内容{main_:while(1){//ii1++;//j=300;P3.3=~P3.3;delay(1000);//while(j--);//j=10000;//while(j--);//i=10000;//while(i--);//i=10000;//while(i--);}//ii1++;//ii1++;//ii1++;gotomain_;}voidtask3(void)//任务3内容{main_:while(1){//ii1++;//j=300;P4.2=~P4.2;delay(4000);//while(j--);//j=10000;//while(j--);//i=10000;//while(i--);//i=10000;//while(i--);}//ii1++;//ii1++;//ii1++;gotomain_;}caozuoxintong_v3.1.zip
看汇编,就象看天书啊
0
回复
soap泡泡
LV.4
12
2014-02-22 20:23
C语言也有时间片轮转啊。网上一搜大把的。
0
回复
elio
LV.2
13
2014-02-22 20:24
加上调度机制,这其实就是就是所有操作系统最基础的东西。
0
回复
vidas
LV.2
14
2014-02-22 20:25
@for_real
看汇编,就象看天书啊
看不懂汇编,但是好多的底层必须用汇编,真纠结呀,,,好比对SP,PC的更改,对堆栈的更改
0
回复
candyman
LV.2
15
2014-02-22 20:27
有C语言的吗?
0
回复
001a
LV.3
16
2014-02-22 20:28
@candyman
有C语言的吗?

木有啊。。。C语言不能获取堆栈SP当前的值,这样获取不了堆栈长度(当前堆栈长度=当前堆栈的值和原来设的堆栈底之差的绝对值)。       

上面汇编的内容是:先保护常用寄存器 ax bc de hl(如果是51单片那么对应的应该是r0 r1 r2 r3 ...) ;然后计算堆栈长度;再把堆栈数据全部复制到一段数据“1”区内(这个是数据去起中间缓存的作用),并且保存这段数据的长度;再把数据“2”区内的数据覆盖回原来的堆栈(数据“2”区就是上一个任务的堆栈数据);再根据数据“2”去的数据长度回复SP值;再把数据“1”区的数据覆盖数据“2”去的数据(下个中断来的时候再把这个数据“2”区的书覆盖堆栈);最后还原常用寄存器 ax bc de hl 数据,退出中断(因为我写的汇编是嵌在C语言中的,所以不用这个汇编指令)。

0
回复