带键盘/屏幕/LED的单片机汇编代码故障:isr_freqtimer未执行求助
问题排查:按键触发status置1后定时器中断未生效
我们使用一款配备键盘、屏幕和LED的8086单片机,其中nokey表示无按键按下,ppi_pa3为扬声器接口,keybd为键盘接口。按下任意按键时,单片机可检测到并通过LED显示(对应代码第71行),此时status会被置1,理论上isr_freqtimer中断服务程序应执行,但实际未生效,以下是相关汇编代码及排查要点:
org 100h cpu 8086 jmp start ; Variablen status db 00000000b ; Statusbyte ; ^ ; | ; +-----> Ton (1, an) / (0, aus) ; Konstanten intab0 equ 20h ; Adresse Interrupttabelle PIT, Kanal 1 intab1 equ intab0 + 1 * 4 ; Adresse Interrupttabelle PIT, Kanal 2 intab7 equ intab0 + 7 * 4 ; Adresse Interrupttabelle Lichttaster eoi equ 20h ; End Of Interrupt (EOI) clrscr equ 0 ; Clear Screen getkey equ 1 ; Funktion auf Tastatureingabe warten ascii equ 2 ; Funktion ASCII-Zeichenausgabe hexbyte equ 4 ; HEX-Byte Ausgabe conin equ 5 ; Console IN conout equ 6 ; Console OUT pitc equ 0a6h ; Steuerkanal PIT pit1 equ 0a2h ; Counter 1 PIT pit2 equ 0a4h ; Counter 2 PIT ppi_ctl equ 0b6h ; Steuerkanal PPI (Parallelinterface) ppi_a equ 0b0h ; Kanal A PPI ppi_pa0 equ 1 ; LED 0 ppi_pa1 equ 2 ; LED 1 ppi_pa2 equ 4 ; LED 2 ppi_pa3 equ 8 ; Lautsprecher ppi_pa6 equ 1 << 6 ; Servomotor ppi_b equ 0b2h ; Kanal B PPI ppi_c equ 0b4h ; Kanal C PPI ocw_2_3 equ 0c0h ; PIC (Interruptcontroller), OCW2,3 ocw_1 equ 0c2h ; PIC (Interruptcontroller), OCW1 icw_1 equ 0c0h ; PIC (Interruptcontroller), ICW1 icw_2_4 equ 0c2h ; PIC (Interruptcontroller), ICW2,4 leds equ 0 ; LED Port schalter equ 0 ; Schalterport keybd equ 80h ; SBC-86 Tastatur gokey equ 11h ; Taste "GO" outkey equ 15h ; Taste "OUT" sseg7 equ 9eh ; Segmentanzeige 7 tcfreq equ 440 ; initiale Frequenz basefreq equ 1843200 ; Basistakt in Hz nokey equ 7 ; keine Taste gedrueckt start: ; Initialisierung mov ah, clrscr ; Anzeige aus int conout mov byte [status], 0 ; Init. Statusbyte und alle LEDs mov al, 0 out ppi_a, al out leds, al call init ; Controller und Interruptsystem scharfmachen ; Hintergrundprogramm (ist immer aktiv, wenn im Service nichts zu tun ist) ; Hier sollten Ausgaben auf das Display getätigt werden, Tastatureingaben, etc. again: ; Code des Hintergrundprogammes in al,keybd out 0,al mov ah,al and ah, nokey cmp ah,7 je silence or byte[status],1 jmp again silence: and byte[status], ~1 jmp again ; Initialisierung Controller und Interruptsystem init: cli ; Interrupts aus ; PIT-Init. ; Nichts zu tun, das macht die Main-Loop :-) ; mov al, 01110110b ; Kanal 1, Mode 3, 16-Bit ZK ; out pitc, al ; Steuerkanal ; mov al, tcfreq & 0ffh ; Low-Teil Zeitkonstante ; out pit1, al ; mov al, tcfreq >> 8 ; High-Teil Zeitkonstante ; out pit1, al ; PPI-Init. mov al, 10001011b ; PPI A/B/C Mode 0, A Output, sonst Input out ppi_ctl, al jmp short $+2 ; I/O-Delay mov al, 0 ; LED's aus (high aktiv) out ppi_a, al ; PIC-Init. mov al, 00010011b ; ICW1, ICW4 benoetigt, Bit 2 egal, ; Flankentriggerung out icw_1, al jmp short $+2 ; I/O-Delay mov al, 00001000b ; ICW2, auf INT 8 gemapped out icw_2_4, al jmp short $+2 ; I/O-Delay mov al, 00010001b ; ICW4, MCS-86, EOI, non-buffered, ; fully nested out icw_2_4, al jmp short $+2 ; I/O-Delay mov al, 11111110b ; Kanal 0, 1 + 7 am PIC demaskieren ; PIT K1 out ocw_1, al ; Interrupttabelle init. mov word [intab0], isr_freqtimer ; Interrupttabelle (Timer K1) ; initialisieren (Offset) mov [intab0 + 2], cs ; (Segmentadresse) sti ; ab jetzt Interrupts ret ;------------------------ Serviceroutine ----------------------------------- isr_freqtimer: ; Timer fuer Lautsprecher push ax test byte[status],1 jz isr_freqtimer_out in al, ppi_a xor al, ppi_pa3 out ppi_a,al ; Code der Serviceroutine fuer die Lautsprecherausgabe isr_freqtimer_out: ; Ausgang aus dem Service mov al, eoi ; EOI an PIC out ocw_2_3, al pop ax iret ;Frequenzen in zwei Oktaven von c4 bis b5 in Hertz (Hz) tonleiter: dw 262 ; c4 0 dw 277 ; c#4 1 dw 294 ; d4 2 dw 311 ; d#4 3 dw 329 ; e4 4 dw 349 ; f4 5 dw 370 ; f#4 6 dw 392 ; g4 7 dw 415 ; g#4 8 dw 440 ; a4 9 dw 466 ; a#4 10 dw 493 ; b4 11 dw 523 ; c5 12 dw 554 ; c#5 13 dw 587 ; d5 14 dw 622 ; d#5 15 dw 659 ; e5 16 dw 698 ; f5 17 dw 740 ; f#5 18 dw 784 ; g5 19 dw 830 ; g#5 20 dw 880 ; a5 21 dw 932 ; a#5 22 dw 987 ; b5 23
核心排查要点
PIT未完成初始化:代码中PIT计数器1的初始化代码被完全注释,导致定时器不会产生任何中断信号。必须取消注释这部分代码,并且修正时间常数计算:PIT Mode3(方波模式)下,分频值应为
basefreq/(2*tcfreq),而非直接写入tcfreq,正确代码示例:mov ax, basefreq mov bx, 2*tcfreq div bx mov al, ah ; 先写低字节 out pit1, al mov al, ah ; 再写高字节 out pit1, al中断向量表映射不匹配:PIC初始化时通过ICW2将中断映射到
INT8,但代码中将isr_freqtimer的地址写入了intab0(对应INT0)的向量位置,两者完全不对应。正确的中断向量地址应为intab0 + 8*4 = 40h,修改代码:mov word [intab0 + 8*4], isr_freqtimer mov [intab0 + 8*4 + 2], csPIC中断掩码错误:OCW1设置为
11111110b是允许IRQ0(对应PIT计数器0),若硬件上PIT计数器1连接的是IRQ1,则需要将掩码的第1位清零,改为11111101b:mov al, 11111101b out ocw_1, al主循环潜在干扰:主循环中
out 0,al指令向端口0输出数据,若端口0是关键硬件端口,可能干扰正常逻辑,建议暂时注释该指令排查。
内容的提问来源于stack exchange,提问作者Ahmed Kortas
相关产品推荐
相关产品推荐

