系统级C语言程序设计

摘要:本文主要介绍C语言中中断服务程序的编写、安装和使用。由于硬中断服务程序的编写涉及到硬件端口读写操作,使得用户直接和硬件打交道,在程序设计过程中要用到的数据(如硬件端口地址等)比较多,这就使程序员和计算机的硬件设备间缺少一种“缓冲”的作用,况且,用汇编语言来直接对硬件编程要方便得多。本文仅对软中断程序的编写作个介绍。
关键词:软中断、中断向量、中断向量表、TSR内存驻留、DOS重入、中断请求、段地址、偏移量、寄存器、BIOS、DOS、setvect ( )、getvect ( )、keep ( )、disable ( )、enable ( )、geninterrupt ( )、int86 ( )、interrupt
    对于一般的C语言爱好者而言,就如何在C中使用中断例程这一问题应该已经非常熟悉,例如,我们可以通过int86 ( )函数调用13H号中断直接对磁盘物理扇区进行操作,也可以通过INT86 ( )函数调用33H号中断在屏幕上显示鼠标光标等。其实,13H号也好,33H号也好,它们只不过就是一些函数,这些函数的参数通过CPU的寄存器传递。中断号也只不过是间接地指向函数体的起始内存单元,说它是间接的,也就是说,函数的起始段地址和偏移量是由中断号通过一种方法算得的(具体如何操作,下面会作解释)。如此一来,程序员不必要用太多的时间去写操作硬件的程序了,只要在自己的程序中设置好参数,再调用BIOS或DOS提供的中断服务程序就可以了,大大减小了程序开发难度,缩短了程序开发周期。那么中断既然是函数,就可以由用户任意的调用、由用户任意地编写。
    计算机内存的前1024个字节(偏移量00000H到003FFH)保存着256个中断向量,每个中断向量占4个字节,前两个字节保存着中断服务程序的入口地址偏移量,后两个字节保存着中断程序的入口段地址,使用时,只要将它们分别调入寄存器IP及CS中,就可以转入中断服务程序实现中断调用。每当中断发生时,CPU将中断号乘以4,在中断向量表中得到该中断向量地址,进而获得IP及CS值,从而转到中断服务程序的入口地址,调用中断。这就是中断服务程序通过中断号调用的基本过程。在计算机启动的时候,BIOS将基本的中断填入中断向量表,当DOS得到系统控制权后,它又要将一些中断向量填入表中,还要修改一部分BIOS的中断向量。有一部分中断向量是系统为用户保留的,如60H到67H号中断,用户可以将自己的中断服务程序写入这些中断向量中。不仅如此,用户还可以自己更改和完善系统已有的中断向量。
    在C语言中,提供了一种新的函数类型interrupt,专门用来定义中断服务程序,比如我们可以写如下的中断服务程序:
/*例1:中断服务程序*/
void interrupt int60()
{
 puts("This is an example");
}
该中断的功能就是显示

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: 以下是一个使用中断程序设计的方法编写的驻留程序,用于在屏幕窗口的右下角显示当前时间。 ```assembly ; 定义常量和变量 TIME_INT equ 1Ch ; BIOS中断0x1A的子功能号,用于获取系统时间 VIDEO_SEG equ 0B000h ; 显存段地址 VIDEO_OFF equ 0FAEh ; 显示时间的显存偏移地址 hour db 0 ; 时 minute db 0 ; 分 second db 0 ; 秒 ; 程序入口点 start: mov ax, @data mov ds, ax ; 设置中断向量表 cli mov word ptr es:[0*4], offset old_int1c mov word ptr es:[1*4], cs mov word ptr es:[2*4], offset old_int1c sti ; 调用BIOS中断0x1A获取系统时间 mov ah, TIME_INT int 1Ah mov hour, ch mov minute, cl mov second, dh ; 不断更新时间并显示 update_time: ; 调用BIOS中断0x1A获取系统时间 mov ah, TIME_INT int 1Ah cmp dh, second je update_time ; 如果秒数没有变化则继续等待 mov second, dh ; 更新秒数 cmp cl, minute je update_time ; 如果分数没有变化则继续等待 mov minute, cl ; 更新分数 cmp ch, hour je update_time ; 如果小时数没有变化则继续等待 mov hour, ch ; 更新小时数 ; 将时间转换为字符并显示 call display_time ; 等待一段时间再更新时间 mov cx, 10000h delay: loop delay jmp update_time ; 将时间转换为字符并显示 display_time: push ax push bx push cx push dx push si push di ; 将小时数转换为字符并显示 mov al, hour mov bl, 10 div bl add al, '0' add ah, '0' mov si, VIDEO_SEG mov es, si mov di, VIDEO_OFF add di, 6 mov es:[di], ah add di, 2 mov es:[di], al ; 将分数转换为字符并显示 mov al, minute div bl add al, '0' add ah, '0' add di, 2 mov es:[di], ah add di, 2 mov es:[di], al ; 将秒数转换为字符并显示 mov al, second div bl add al, '0' add ah, '0' add di, 2 mov es:[di], ah add di, 2 mov es:[di], al pop di pop si pop dx pop cx pop bx pop ax ret ; 旧的中断1Ch处理程序 old_int1c: push ax push bx push cx push dx call update_time pop dx pop cx pop bx pop ax iret ``` 该程序首先设置了中断向量表,将中断1Ch的处理程序指向了`old_int1c`标签所在的位置。然后在程序的主循环中不断获取系统时间并将其转换为字符显示到屏幕窗口的右下角。由于使用了中断程序设计的方法,程序可以在后台运行,不会影响前台程序的正常运行。 ### 回答2: 驻留程序是指在后台运行的程序,而不会中断前台程序的正常运行。下面是使用中断程序设计的方法编写一个驻留程序,在屏幕窗口的右下角显示当前时间(格式为HH:MM:SS)。 首先,我们需要使用中断程序来获取当前系统时间。可以使用DOS中的INT 21h中断函数来获取系统时间。INT 21h的功能号为2Ch时,可以通过AH寄存器传递给INT 21h的参数来获取当前系统时间。 编写一个中断处理程序,将获取的系统时间保存在一个变量中。 ```assembly .MODEL SMALL .STACK 100h .DATA currentTime DB 9 DUP (?) .CODE MAIN PROC MOV AX, @DATA MOV DS, AX MOV AH, 2Ch ; 获取系统时间的功能号为2Ch INT 21h ; 调用DOS中断 MOV currentTime, CH ; CH寄存器存储时钟的小时 MOV currentTime+1, CL ; CL寄存器存储时钟的分钟 MOV currentTime+2, DH ; DH寄存器存储时钟的秒数 MOV AH, 4Ch ; 退出程序的功能号为4Ch INT 21h MAIN ENDP END MAIN ``` 以上是获取系统时间的代码。 然后,我们可以编写一个驻留程序,使用中断程序将当前时间显示在屏幕窗口的右下角。我们可以使用INT 10h中断函数来设置光标位置,并使用INT 21h中断函数来显示字符串。 ```assembly .MODEL SMALL .STACK 100h .DATA currentTime DB 9 DUP (?) msg DB 'Current Time: $' .CODE MAIN PROC MOV AX, @DATA MOV DS, AX MOV AH, 2Ch ; 获取系统时间的功能号为2Ch INT 21h ; 调用DOS中断 MOV AH, 3h ; 获取当前光标位置的功能号为3h MOV BH, 0 ; 页面号为0,即当前页 INT 10h ; 调用BIOS中断 MOV DL, 79 ; 将光标的X坐标设为79,即最右边的列 MOV DH, 24 ; 将光标的Y坐标设为24,即最下面的行 MOV AH, 2 ; 设置光标位置的功能号为2 INT 10h ; 调用BIOS中断 LEA DX, msg ; 将msg字符串的地址加载到DX寄存器 MOV AH, 9 ; 显示字符串的功能号为9 INT 21h ; 调用DOS中断 MOV AH, 4Ch ; 退出程序的功能号为4Ch INT 21h MAIN ENDP END MAIN ``` 以上是将当前时间显示在屏幕窗口右下角的代码。 最后,需要将上述两段代码结合起来,使得驻留程序在后台运行,以实现显示当前时间的功能。这可以通过将上述两段代码合并并调用中断来实现。 ```assembly .MODEL SMALL .STACK 100h .DATA currentTime DB 9 DUP (?) msg DB 'Current Time: $' .CODE MAIN PROC MOV AX, @DATA MOV DS, AX ; 获取系统时间 MOV AH, 2Ch ; 获取系统时间的功能号为2Ch INT 21h ; 调用DOS中断 ; 设置光标位置 MOV AH, 3h ; 获取当前光标位置的功能号为3h MOV BH, 0 ; 页面号为0,即当前页 INT 10h ; 调用BIOS中断 MOV DL, 79 ; 将光标的X坐标设为79,即最右边的列 MOV DH, 24 ; 将光标的Y坐标设为24,即最下面的行 MOV AH, 2 ; 设置光标位置的功能号为2 INT 10h ; 调用BIOS中断 ; 显示时间 LEA DX, msg ; 将msg字符串的地址加载到DX寄存器 MOV AH, 9 ; 显示字符串的功能号为9 INT 21h ; 调用DOS中断 MOV AH, 4Ch ; 退出程序的功能号为4Ch INT 21h MAIN ENDP END MAIN ``` 以上是完整的驻留程序代码。通过将此程序编译并运行,即可在屏幕窗口的右下角显示当前的时间,且不会影响前台程序的正常运行。 ### 回答3: 要编写一个驻留程序,在屏幕窗口的右下角显示当前的时间,格式为HH:MM:SS,并确保时间的显示不会影响前台程序的正常运行,可以使用中断程序设计的方法。 首先,需要编写一个中断程序,来获取当前时间并将其显示在屏幕窗口的右下角。使用INT 1Ah中断来获取系统时间,并将其转换为HH:MM:SS的格式。然后,将格式化后的时间字符串输出到屏幕窗口的正确位置。 要确保时间的显示不会影响前台程序的正常运行,可以使用一个辅助程序来实现。这个辅助程序运行在后台,并通过轮询的方式检测前台程序是否需要处理。当前台程序需要处理时,辅助程序将会立即停止显示时间,并将控制权交还给前台程序。只有在前台程序不需要处理时,辅助程序才会继续显示时间。 通过这种方式,可以保证时间的显示不会干扰前台程序的正常运行。同时,辅助程序会定时更新时间的显示,确保时间的准确性。 总结起来,编写一个驻留程序可以通过以下步骤实现: 1. 编写一个中断程序,来获取系统时间并将其格式化为HH:MM:SS的形式。 2. 编写一个辅助程序,用于控制时间的显示,确保它不会影响前台程序的正常运行。 3. 在辅助程序中使用中断程序来实时更新时间的显示,并将其输出到屏幕窗口的右下角。 4. 确保辅助程序能够检测前台程序是否需要处理,并在需要处理时停止时间的显示。 通过以上步骤,就可以编写一个驻留程序,可以在屏幕窗口的右下角显示当前的时间,而不会影响前台程序的正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值