8086汇编:如何让定时触发int 4ah中断生效?问题求助
Let's break down why your INT 4AH isn't triggering after 5 seconds—there are three critical fixes needed in your code:
1. You're Not Handling Seconds Carryover
When you add 5 to the seconds register (DH), you don't account for values that exceed 59. If the current seconds are 56 or higher, adding 5 will result in an invalid second count (61-64), and the BIOS alarm function ignores invalid times. Here's how to fix the carryover:
add dh, 5 ; Add 5 seconds cmp dh, 60 jb no_sec_carry ; If <60, no carry needed sub dh, 60 ; Wrap around seconds to 0-59 inc cl ; Carry over to minutes cmp cl, 60 jb no_min_carry ; Handle minute carry if needed (rare for 5s, but safe) sub cl, 60 inc ch ; Carry over to hours (optional, but complete) no_min_carry: no_sec_carry:
2. Interrupt Vector Setup Needs Proper Interrupt Locking
When modifying the interrupt vector table, you must disable interrupts (CLI) first to prevent a race condition where an interrupt fires mid-modification, corrupting the vector. You had this code commented out—uncomment it to ensure the vector is set safely:
create_interrupt proc far push 0 pop es pushf cli ; Disable interrupts during vector write mov word ptr es:[4ah*4],offset int_handler mov word ptr es:[4ah*4+2],seg int_handler sti ; Re-enable interrupts popf iret create_interrupt endp
3. Your Interrupt Handler Doesn't Preserve Registers
DOS and BIOS expect interrupt handlers to preserve all registers they modify. Your int_handler changes AX and DX without saving them, which can corrupt the system state and prevent the handler from executing correctly. Fix this by pushing registers to the stack before modifying them, then popping them back:
int_handler proc far push ax ; Save registers we'll modify push dx push ds mov ax,DSEG mov ds,ax ; Set DS to our data segment (you had this commented out—critical!) mov ah,09h mov dx,offset mess2 int 21h pop ds ; Restore registers in reverse order pop dx pop ax iret int_handler endp
Modified Full Code
Here's the complete fixed code incorporating all these changes:
SSEG segment stack db 256 dup(0) SSEG ends DSEG segment mess db 'Hello',0dh,0ah,'$' mess2 db 'Hello from handler!',0dh,0ah,'$' mess3 db 'Ассемблер это жопа, я уже устал','$' DSEG ends CSEG segment assume cs:CSEG,ds:DSEG,ss:SSEG begin: mov ax, DSEG mov ds,ax mov ah,09h mov dx,offset mess int 21h call far ptr create_interrupt call far ptr alarm mov ah,01h int 21h mov ah,4ch int 21h create_interrupt proc far push 0 pop es pushf cli ; Lock interrupts during vector setup mov word ptr es:[4ah*4],offset int_handler mov word ptr es:[4ah*4+2],seg int_handler sti ; Unlock interrupts popf iret create_interrupt endp alarm proc far pushf mov ah,02h ; Get current system time int 1ah ; Calculate target time (current +5 seconds) add dh, 5 cmp dh, 60 jb no_sec_carry sub dh, 60 inc cl cmp cl, 60 jb no_min_carry sub cl, 60 inc ch no_min_carry: no_sec_carry: mov ah,06h ; Set alarm to target time int 1ah popf iret alarm endp int_handler proc far push ax push dx push ds mov ax,DSEG mov ds,ax mov ah,09h mov dx,offset mess2 int 21h pop ds pop dx pop ax iret int_handler endp CSEG ends end begin
One More Note
The BIOS INT 1AH AH=06h function triggers INT 4AH only once when the target time is reached. If you wanted a repeating alarm, you'd need to re-set the alarm inside the handler, but your code is set up for a single 5-second delay which this fix addresses.
内容的提问来源于stack exchange,提问作者Klepov Aleksandr

