DATA SEGMENT
       INT_OFF1  DW 0               ; 存储主片原来中断向量的偏移地址
       INT_SEG1  DW 0               ; 存储主片原来中断向量的段地址
       INT_OFF2  DW 0               ; 存储从片原来中断向量的偏移地址
       INT_SEG2  DW 0               ; 存储从片原来中断向量的段地址
       LED_STATE DW 00000001B       ; 0|xxx|0(B组0方式)|000(指定PC0引脚)|1(置位)
DATA ENDS

STACK SEGMENT
             DW 100 DUP (0)       ; 定义堆栈段,大小为100字节
STACK ENDS

CODE SEGMENT
              ASSUME CS:CODE, DS:DATA, SS:STACK
       START: 
              MOV    AX, DATA                         ; 将数据段地址存入AX寄存器
              MOV    DS, AX                           ; 将AX中的值装载到DS寄存器
              MOV    ES, AX                           ; 将AX中的值装载到ES寄存器
              MOV    AX, STACK                        ; 将堆栈段地址存入AX寄存器
              MOV    SS, AX                           ; 将AX中的值装载到SS寄存器

              CLI                                     ; 清除中断标志,禁止中断,防止在修改中断向量表过程中有中断触发
       ; 保存主片原来的中断向量
              MOV    AX, 350BH                        ; 获取原来的中断号为0BH的中断向量
              INT    21H                              ; 将中断向量的偏移地址存在BX,段地址存在ES
              MOV    INT_OFF1, BX                     ; 分别将原来中断向量的偏移地址和段地址保存
              MOV    BX, ES
              MOV    INT_SEG1, BX

       ; 向主片装填新的中断向量
              MOV    DX, SEG SW_INT                   ; 将主片新中断向量的段地址存入DX
              MOV    DS, DX                           ; 再装到DS
              MOV    DX, OFFSET SW_INT                ; 将主片新中断向量的偏移地址存入DX
              MOV    AX, 250BH                        ; 装填到中断向量表里中断号为0BH的中断向量
              INT    21H
              MOV    AX, DATA                         ; 重新加载数据段地址
              MOV    DS, AX

       ; 保存从片原来的中断向量
              MOV    AX, 3572H                        ; 获取原来的中断号为72H的中断向量
              INT    21H                              ; 将中断向量的偏移地址存在BX,段地址存在ES
              MOV    INT_OFF2, BX                     ; 分别将原来中断向量的偏移地址和段地址保存
              MOV    BX, ES
              MOV    INT_SEG2, BX

       ; 向从片装填新的中断向量
              MOV    DX, SEG SW_INT                   ; 将从片新中断向量的段地址存入DX
              MOV    DS, DX                           ; 再装到DS
              MOV    DX, OFFSET SW_INT                ; 将从片新中断向量的偏移地址存入DX
              MOV    AX, 2572H                        ; 装填到中断向量表里中断号为72H的中断向量
              INT    21H
              MOV    AX, DATA                         ; 重新加载数据段地址
              MOV    DS, AX

       ; 取消主片MIRQ3的中断屏蔽
              IN     AL, 21H                          ; 读取主片中断屏蔽寄存器
              AND    AL, 11110111B                    ; 将第3位设置为0
              OUT    21H, AL                          ; 将修改后的值写入主片中断屏蔽寄存器

       ; 取消从片SIRQ10的中断屏蔽
              IN     AL, 0A1H                         ; 读取从片中断屏蔽寄存器
              AND    AL, 11111011B                    ; 将第2位设置为0
              OUT    0A1H, AL                         ; 将修改后的值写入从片中断屏蔽寄存器

       ; 主程序
              MOV    DX, 283H                         ; 8255芯片的命令口
              MOV    AL, 10000000B                    ; 1|00(A组0方式)|0(PA输出)|0(PC4-7输出)|0(B组0方式)|0(PB输出)|0(PC0-3输出)
              OUT    DX, AL
              MOV    DX, 283H                         ; 8255芯片的命令口
              MOV    AX, LED_STATE                    ; 输出控制LED的状态
              OUT    DX, AL

              XOR    DX, DX                           ; 将DX置0
       L1:    STI                                     ; 设置中断标志
              CMP    DX, 10                           ; 判断中断是否已触发了10次
              JNE    L1

              CLI                                     ; 清除中断标志,禁止中断,防止在修改中断向量表过程中有中断触发
       ; 恢复主片原来的中断向量
              MOV    DX, INT_SEG1                     ; 将主片原中断向量的段地址存入DX
              MOV    DS, DX                           ; 再装到DS
              MOV    DX, INT_OFF1                     ; 将主片原中断向量的偏移地址存入DX
              MOV    AX, 250BH                        ; 装填到中断向量表里中断号为0BH的中断向量
              INT    21H
              MOV    AX, DATA                         ; 重新加载数据段地址
              MOV    DS, AX
    
       ; 恢复从片原来的中断向量
              MOV    DX, INT_SEG2                     ; 将从片原中断向量的段地址存入DX
              MOV    DS, DX                           ; 再装到DS
              MOV    DX, INT_OFF2                     ; 将从片原中断向量的偏移地址存入DX
              MOV    AX, 2572H                        ; 装填到中断向量表里中断号为72H的中断向量
              INT    21H
              MOV    AX, DATA                         ; 重新加载数据段地址
              MOV    DS, AX

       ; 设置主片的中断屏蔽
              IN     AL, 21H                          ; 读取主片中断屏蔽寄存器
              OR     AL, 00001000B                    ; 将第3位设置为1
              OUT    21H, AL                          ; 将修改后的值写入主片中断屏蔽寄存器

       ; 设置从片的中断屏蔽
              IN     AL, 0A1H                         ; 读取从片中断屏蔽寄存器
              OR     AL, 00000100B                    ; 将第2位设置为1
              OUT    0A1H, AL                         ; 将修改后的值写入从片中断屏蔽寄存器
              STI                                     ; 设置中断标志

       ; 返回DOS
              MOV    AX, 4C00H
              INT    21H
    
       ; 中断服务程序
SW_INT PROC NEAR
              PUSH   AX                               ; 保护主程序运行状态
              CLI                                     ; 清除中断标志,禁止中断程序执行过程中跳转到其他中断程序
              INC    DX                               ; 触发计数加1

              PUSH   DX                               ; 保护DX
              MOV    AX, LED_STATE
              ADD    AX, DX                           ; DX的末位会随着其增加交替为0和1
              AND    AX, 00000001B                    ; 取末位控制PC0为0或1
              MOV    DX, 283H                         ; 从而实现灯的亮灭交替
              OUT    DX, AL
              POP    DX                               ; 恢复DX

              MOV    AL, 20H                          ; 向主片发送EOI指令
              OUT    20H, AL
              MOV    AL, 62H                          ; 向从片发送EOI指令
              OUT    0A0H, AL
              STI                                     ; 设置中断标志,允许跳转到中断程序
              POP    AX                               ; 恢复主程序运行状态
              IRET
SW_INT ENDP

CODE ENDS
END START