回 帖 发 新 帖 刷新版面

主题:[转帖]中断方面文章

调用中断

·中断

  中断是一种使CPU中止正在执行的程序而转去处理特殊事件的操作。

  这些引起中断的事件称为中断源,它们可能是来自外设的输入输出请求,也可能是计算机的一些异常事故或其它内部原因。

  由外设控制器或协处理器(8087/80287)引起的中断一般称为外中断,由程序中安排的中断指令INT产生的中断,或由CPU的某些错误结果产生的中断称为内中断。

·中断向量表

  我们给每种中断安排一个中断类型号。IBM PC中断系统能处理256种类型的中断,类型号为0-0FFH。例如:系统定时器的中断类型为08,键盘为09,内中断中的除法错误的中断类型为0,等等。

  每种类型的中断都由相应的中断处理程序来处理,中断向量表就是各中断类型的处理程序的地址表。

  存储器的低1.5K字节,地址从0到5FFH为系统占用,其中最低的1K字节,地址从0到3FFH存放中断向量。中断向量表中的256项中断向量对应256种中断类型,每项占用四个字节,其中两个字节存放中断处理程序的段地址,另两个字节存放偏移地址。

·调用中断

  调用中断需要使用汇编指令INT n(n为中断类型)。

  如:

asm
 int 23H
end;


  这段代码可以模拟按下Ctrl+Break键,结束程序运行。

  又如:

asm
 int 19H
end;  

  这段代码可以重启系统(Windows MS-DOS 方式下可以关闭窗口)。

内部扬声器

·内部扬声器

  内部扬声器是计算机内置的一种简单发声设备,原本是为BIOS(基本输入输出系统)设计的,用于发生异常或其它情况时的报警发声,后来被DOS游戏和软件广泛用于音乐的播放。

·通用发声程序

  ROM BIOS中有个BEEP子程序,它能根据BL中给出的时间计数值控制8254定时器,产生持续时间为1个或几个0.5秒,频率为896Hz的声音。它的用途是当“加电自测”系统发现硬件错误后,由ERROR_BEEP处理程序调用BEEP子程序,使扬声器发出“嘟嘟”的信号。BL中的时间计数值由ERROR_BEEP程序设置为533H,BEEP子程序将此计数值送给8254的定时器2来产生896Hz的声音,然后BEEP又将AL的第0位和第1位置1,并把AL的值送到8255的输出寄存器(I/O端口61H),使扬声器接通发出声音。

  由此,可以得出产生任一频率声音的计数值应为:533H×896÷给定频率=1192576÷给定频率。

  发声和关闭扬声器的程序如下:

procedure MakeSound(Freq:Word);
begin
 if Freq<19 then CloseSound
 else
 begin
  Port[66]:=1192576 div Freq and 255;
  Port[66]:=1192576 div Freq shr 8;
  Port[97]:=Port[97] or 3;
 end;
end;
procedure CloseSound;
begin
 Port[97]:=Port[97] and 252;
end;

·播放音乐

  播放音乐的核心在于获得各个音符的频率。按照乐理基本知识,每八度为一音程,每一音程中共有12个不同的音调,即1,#1,2,·2,3,4,#4,5,#5,6,#6,7。中央C调的1其频率为261.6Hz。每升高一个音程,频率为原先的两倍。在同一音程中,每升高一个音调,频率为原先的2^(1/12)倍。根据这一原理,若选定一个基本音频,比如音程0音调1的频率为32.7Hz,则给定某一音程及音调的数值,即可算得该音的频率值。

procedure PlayNote(Octave,Tone:Integer);{Octive:音程,0..6;Tone:音调,1..12}
begin
 MakeSound(Round(32.7*Exp(Ln(2)*(Octive+(Tone-1)/12))));
end;  
设置光标位置

·设置光标位置

  要设置光标位置,可以调用BIOS中断10H:
中断号   AH 功能         调用参数
10H 2H 设置光标位置 BH=页号 DH,DL=行,列
  例如(设置为0行0列):

asm
 mov ah,2H
 mov bh,0
 mov dh,0
 mov dl,0
 int 10H
end;
·获取光标位置

中断号 AH        功能     调用参数          返回参数
10H    3H 获取当前光标位置 BH=页号 CH=光标起始行DH,DL=行,列  
例如:

var
 Row,Col:Byte;
asm
 mov ah,3H
 mov bh,0
 int 10H
 mov Row,dh
 mov Col,dl
end;

设置显示模式

·设置显示模式

  要设置显示模式,可以调用BIOS中断10H:
中断号 AH   功能         调用参数
10H   0H   设置显示模式 AL=显示模式号
  例如(设置为640*480 16 Colors):
asm
 mov ah,0
 mov al,12H
 int 10H
end;
·获取显示模式
中断号 AH       功能             调用参数     返回参数
10H   FH   获取当前显示模式                 AL=显示模式号


例如:

var
 Mode:Byte;
asm
 mov ah,FH
 int 10H
 mov Mode,al
end;

·显示模式表

  标准VGA显示模式表:

显示模式 文本/图形 分辨率 颜色数
00H 文本 40*25 2
01H 文本 40*25 16
02H 文本 80*25 2
03H 文本 80*25 16
04H 图形 320*200 4
05H 图形 320*200 4
06H 图形 640*200 2
0DH 图形 320*200 16
0EH 图形 640*200 16
0FH 图形 640*350 2
10H 图形 640*350 16
11H 图形 640*480 2
12H 图形 640*480 16
13H 图形 320*200 256
设置中断子程序

·设置中断子程序

  设置自己的中断子程序,可以利用中断实现拦截Ctrl+Break、自动计时、实时响应键盘操作等诸多功能,在编写好的游戏和软件时必不可少。

  一般在检查或设置任何中断向量时,总是避免直接使用中断向量的绝对地址,而是使用DOS功能调用(21H)存取中断向量。

  DOS单元有两个过程分别执行设置中断向量和获取中断向量:SetIntVec和GetIntVec。其定义如下:
  procedure SetIntVec(IntNo:Byte;Vector:Pointer);
  procedure GetIntVec(IntNo:Byte;var Vector:Pointer);
  这两个过程都是使用DOS功能调用(21H)存取中断向量。

  如果新的中断功能只供自己使用,或用自己编写的中断处理程序代替系统中的中断处理功能时,要注意保存原中断向量,在设置自己的中断向量时,应先保存原中断向量再设置新的中断向量,再程序结束之前恢复原中断向量。

·编写自己的中断子程序

  编写自己的中断子程序是系统级程序设计员常用的技术之一。编写这类程序,常常需要很复杂的技术,并且要很细心,一般都用汇编语言或C语言来实现。然而,Turbo Pascal提供了实现这种技术的简便方法。

  中断过程可用Interrupt指令来声明:

procedure IntHandler(Flags,Cs,Ip,Ax,Bx,Cx,Dx,Si,Di,Ds,Es,Bp:word);interrupt;
begin
 ...
end;


  Turbo Pascal在中断过程的入口处自动保存所有寄存器并初始化DS寄存器。所有寄存器都作为参数传递,因而在过程中可以使用并修改其值。不一定要列出上面所有寄存器参数,但对参数表有几个规定:
  1.不能声明其它的参数;
  2.可以不声明任何参数;
  3.若前一个参数没有省略,则不能省略后一个参数。

  例如:
  procedure IntHandler;           {正确}
  procedure IntHandler(Si,Di,Ds,Es,Bp:Word);{正确}
  procedure IntHandler(Si,Es,Bp:Word);   {错误}

  最后一例的错误在于省略了Di和Ds,而没有省略Si。虽然编译程序不会报告此类错误,但你自己应负责参数顺序的正确性,否则会发生意外的错误。

  注意,Turbo Pascal并没有自动插入开中断指令----STI,因而不会产生进一步的中断。需要时可以用inline语句插入一条STI指令。

  中断过程的出口码将恢复寄存器并执行中断返回指令。中断过程可以修改寄存器参数,中断返回时,会导致相应寄存器的修改。

  值得注意的是,若是编写硬件中断处理程序,则不能使用Turbo Pascal的输入输出或动态内存分配子程序,因为它们是不可重入的。另外,由于DOS也是不可重入的,因而也不能使用DOS功能调用。



回复列表 (共2个回复)

沙发

好!已经收入经典集锦中!

板凳

呵呵

我来回复

您尚未登录,请登录后再回复。点此登录或注册