C语言实现 "软中断" 程序小结

参考网友帖子改写:呵呵!!!

 
  对于系统级语言设计之一的中断程序设计包括软中断和硬中断。后者设计到硬件端口的读写操作等等,应该用汇编实现比较好
。而前者用C实现就要方便得多的了。

 
  对于软中断程序应该有3部分组成:中断程序的编写、安装和使用.
  由于我们可以调用13号中断实现磁盘物理扇区操作,可有调用33H号中断在屏幕上设置显示光标等等。实际上我们只不过使用了
相对应的函数,这些函数的参数使用CPU中特殊的寄存器(CS和IP)传递的。因此我们就可以不用花大量时间去写操作硬件程序了,只要在自己的程序中设置好参数,再调用DOS或者BIOS中断服务程序就OK了。既然他是函数,我们也可以实现我们自己想要功能的函数,然后安装到中断向量表中也可以像系统提供的那样随意使用了。
  

      (一)编写:
  关键字:interrupt
  主要是使用这个关键字告诉编译器这个函数不一般,而且很牛。(this guy is a interrupt function)
  如:void interrupt function1(void)
      { puts("正执行这个中断函数!");}
  (二)安装:
  系统启动过程中一必须操作就是:(填中断向量表)
  首先:BIOS获得系统控制权,它将基本的中断填如中断向量表中。


  其次:DOS获得系统控制权,它也将一些中断填入中断向量表,同时也修改一步分BIOS的中断向量。其实就是像内存中的前1024字(地址为:0:0H-0:3FFH)中填数据(实际就是函数的地址),一共是256个中断向量。这种软中断方式使CPU可是实时响应外界的方法是DOS中断调用中的第三种也是级别最低的一种。她前面的两个哥哥是内中断(内部硬件干的)和外中断。一下是一些中断向量的功能:
  
(1)80x86中断向量
I/O ADDR
INT TYPE FUNCTION
00 ~ 03 0 除法溢出中断
04 ~ 07 1 单步(用于DEBUG)
08 ~ 0B 2 非屏蔽中断(NMI)
0C ~ 0F 3 断点中断(用于DEBUG)
10 ~ 13 4 溢出中断
14 ~ 17 5 打印屏幕
18 ~ 1F 6,7 保留

(2)8259中断向量
I/O ADDR INT TYPE FUNCTION
20 ~ 23 8 定时器 (IRQ0)
24 ~ 27 9 键盘 (IRQ1)
28 ~ 2B A 彩色/图形 (IRQ2)
2C ~ 2F B 串行通信COM2 (IRQ3)
30 ~ 33 C 串行通信COM1 (IRQ4)
34 ~ 37 D LPT2控制器中断 (IRQ5)
38 ~ 3B E 磁盘控制器中断 (IRQ6)
3C ~ 3F F LPT1控制器中断 (IRQ7)

(3)BIOS中断向量
I/O ADDR INT TYPE FUNCTION
40 ~43 10 视频显示 I/O
44 ~ 47 11 设备检验
48 ~ 4B 12 测定存储器容量
4C ~ 4F 13 磁盘 I/O
50 ~ 53 14 RS-232 串行口 I/O
54 ~ 57 15 系统描述表指针
58 ~ 5B 16 键盘 I/O
5C ~ 5F 17 打印机 I/O
60 ~ 63 18 ROM BASIC 入口代码
64 ~ 67 19 引导装入程序
68 ~ 6B 1A 日时钟
I/O ADDR INT TYPE FUNCTION
6C ~ 6F 1B Ctrl - Break 控制的软中断
70 ~ 73 1C 定时器控制的软中断
参数表指针
I/O ADDR INT TYPE FUNCTION
74 ~ 77 1D 视频参数块
78 ~ 7B 1E 软盘参数块
7C ~ 7F 1F 图形字符扩展码

(4)DOS中断向量
I/O ADDR INT TYPE FUNCTION
80 ~ 83 20 DOS 中断返回
84 ~ 87 21 DOS 系统功能调用
88 ~ 8B 22 程序中止时 DOS 返回地址(用户不能直接调用)
8C ~ 8F 23 Ctrl - Break 处理地址(用户不能直接调用)
90 ~ 93 24 严重错误处理(用户不能直接调用)
94 ~ 97 25 绝对磁盘读功能
98 ~ 9B 26 绝对磁盘写功能
9C ~ 9F 27 终止并驻留程序
A0 ~ A3 28 DOS安全使用
A4 ~ A7 29 快速写字符
A8 ~ AB 2A Microsoft 网络接口
B8 ~ BB 2E 基本 SHELL 程序装入
BC ~ BF 2F 多路服务中断
CC ~ CF 33 鼠标中断
104 ~ 107 41 硬盘参数块
118 ~ 11B 46 第二硬盘参数块
11C ~ 3FF 47 ~ FF BASIC 中断
  
  从上面可以查出那个中断号是系统给我们保留的,比如60H---67H号中断就是随便使用的。于是可以把写好的函数地址填到他们
里面就OK了。
  主要使用的函数:
  setvect(中断号,函数入口地址):安装函数地址到中断向量表。
  interrupt* getvect(中断号):接收中断号返回服务程序地址。
  如可以如此实现安装函数:
  
  void install (void interrupt (*fadd)(),int num)        /*安装中断*/
           {
                      disable();                                        /*关闭中断*/
                      setvect(num, fadd);                         /*设置中断*/
                 enable();                                        /*开中断*/        
          }        
         主函数中:
                 void   interrupt(*oldfunction)();  /*保留原中断向量表地址*/
                    oldfunction=getvect(0x60);
                    install(funcion,0x60);
                     .........(程序体......)
                     setvect(0x60,oldfunction);                /*还原原中断向量*/
  (三)使用:
  可以分两种:
  一是人工触发中断,函数为:geninterrupt(中断号)。
  二是系统自动触发,我们只要改写了系统的中断向量后系统就会自动调用我们自己写的函数了,但是一定要最后还原原系统的中

断向量。否则除非重新启动才可以恢复原状态。如:系统每55ms都会触发0x1c号中断。于是就可以改写1C号中断,使系统没55ms调

用一下我们自己写的函数,这样就可以实现实时时钟功能了。
  如:
  (1)手动调用:
  
    #include
            #include
  
           void interrupt function ()                               /*中断服务函数*/
        {
          puts("This is an example");
        }

    void install (void interrupt (*fadd)(),int num)        /*安装中断*/
       {        
            disable();                                   /*关闭中断*/
            setvect(num, fadd);                    /*设置中断*/
            enable();                                     /*开放中断*/
        }

    void main()
        {
    void   interrupt(*oldfunction)();          /*保留原中断向量表地址*/
           oldfunction=getvect(0x60);

           install (function,0x60);                   /*将int60函数安装到0x60中断*/

           geninterrupt (0x60);                     /*人为产生0x60号中断*/
     setvect(0x60,oldfunction);              /*恢复中断向量表中原值*/

     getchar();                    /*暂停屏幕,按任意键再退出程序*/
        }

   (2)系统自动调用:
  #include              #include
  #define    TIME     0x1c
    #define      MAX    100                                        /*显示100秒*/

 

  
      int  count;                                                       /*计数器*/
           void interrupt function ()                                    /*中断服务函数*/
        {
          cout++;
        }

    void install (void interrupt (*fadd)(),int num)        /*安装中断*/
       {        
            disable();                                   /*关闭中断*/
            setvect(num, fadd);                    /*设置中断*/
            enable();                                     /*开放中断*/
        }

    void main()
        {
       char  time[9]={'0','0',':','0','0',':''0','0',0};
       int  timer;
       int   temp1,temp2;
       timer=(count*10)/182;
       int hour,min,second;
       hour=min=sec=0;
       void   interrupt   (*oldfunction)();   /*保留原中断向量表地址*/
             oldfunction=getvect(TIME);
  
             install (function,TIME);      /*将int60函数安装到0x60中断*/

             while(timer<=MAX)         /*MAX为设置显示的最大秒数*/
                {
                  sec/60;
                  min=timer/3600;
                  hour=timer/(60*60*60);
                  temp1=second/10;
                  temp2=senond%10;
                  time[9]+=temp2;
                  time[8]+=temp1;
        
                  temp1=min/10;
                  temp2=min%10;
                  time[6]+=temp2;
                  time[5]+=temp1;
  
                  temp1=hour/10;
                  temp2=hour%10;
                  time[2]+=temp2;
                  time[1]+=temp1;
                
                 puts(time);
             }
        setvect(TIME,oldfunction);              /*恢复中断向量表中原值*/

        getchar();                        /*暂停屏幕,按任意键再退出程序*/
        }
 

你可能感兴趣的:(C语言实现 "软中断" 程序小结)