You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带键盘/屏幕/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], cs
    
  • PIC中断掩码错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:50:33