PC16550 UART接收中断处理完整示例代码

一个完整的PC16550 UART接收中断处理示例代码,包含中断触发和中断释放(EOI)的实现

cpp 复制代码
; =============================================
; PC16550 UART接收中断处理示例
; 功能: 接收字符并回显,显示中断触发与释放状态
; 硬件配置:
;   - UART基地址: 100H
;   - 8259 PIC端口: 400H(命令), 402H(数据)
;   - 中断请求线: IRQ1 (8259 IR1)
;   - 中断向量号: 21H
;   - 时钟频率: 18.432MHz
;   - 波特率: 9600 bps (除数78H)
; =============================================

ORG 100H
JMP INITIALIZATION      ; 跳过数据区到初始化代码

; 数据段定义
int_triggered DB 0      ; 中断触发标志
int_released DB 0       ; 中断释放标志
recv_char DB 0          ; 接收的字符

; 状态消息
trigger_msg DB 0Dh, 0Ah, '>>> Interrupt TRIGGERED', 0
release_msg DB 0Dh, 0Ah, '<<< Interrupt RELEASED (EOI sent)', 0
recv_msg    DB 0Dh, 0Ah, 'Received char: ', 0
start_msg   DB 0Dh, 0Ah, 'UART Interrupt Demo Started', 0Dh, 0Ah
            DB 'Send characters to test interrupt...', 0Dh, 0Ah, 0
end_msg     DB 0Dh, 0Ah, 'Program terminated.', 0Dh, 0Ah, 0

; 16550寄存器偏移
UART_BASE EQU 100H
RBR_THR EQU UART_BASE + 0  ; 接收缓冲/发送保持寄存器
IER     EQU UART_BASE + 1  ; 中断使能寄存器
IIR_FCR EQU UART_BASE + 2  ; 中断标识/FIFO控制寄存器
LCR     EQU UART_BASE + 3  ; 线路控制寄存器
MCR     EQU UART_BASE + 4  ; 调制解调器控制寄存器
LSR     EQU UART_BASE + 5  ; 线路状态寄存器
DLL     EQU UART_BASE + 0  ; 除数锁存低字节 (DLAB=1)
DLM     EQU UART_BASE + 1  ; 除数锁存高字节 (DLAB=1)

; 8259 PIC端口
PIC_CMD  EQU 400H
PIC_DATA EQU 402H

; 中断向量号
UART_IRQ EQU 21H        ; IRQ1对应中断21H

; =============================================
; UART初始化子程序
; =============================================
INIT_UART:
    ; 设置波特率除数 (9600 @ 18.432MHz)
    MOV DX, LCR
    MOV AL, 80H         ; 设置DLAB=1
    OUT DX, AL
    
    MOV DX, DLL         ; 除数锁存低字节
    MOV AL, 78H         ; 120 = 78H (18.432MHz / (16 * 9600))
    OUT DX, AL
    
    MOV DX, DLM         ; 除数锁存高字节
    MOV AL, 00H
    OUT DX, AL
    
    ; 设置线路参数: 8位数据, 1停止位, 无校验
    MOV DX, LCR
    MOV AL, 03H         ; 8N1, DLAB=0
    OUT DX, AL
    
    ; 启用并复位FIFO
    MOV DX, IIR_FCR
    MOV AL, 0C7H        ; 启用FIFO, 14字节触发点, 清除接收FIFO
    OUT DX, AL
    
    ; 设置调制解调器控制
    MOV DX, MCR
    MOV AL, 0BH         ; 启用OUT2(中断使能), RTS和DTR
    OUT DX, AL
    
    ; 启用接收数据中断
    MOV DX, IER
    MOV AL, 01H         ; 仅启用接收数据中断
    OUT DX, AL
    
    RET

; =============================================
; 8259 PIC初始化
; =============================================
INIT_PIC:
    ; 初始化8259
    MOV DX, PIC_CMD
    MOV AL, 17H         ; ICW1: 边沿触发, 级联, 需要ICW4
    OUT DX, AL
    
    MOV DX, PIC_DATA
    MOV AL, UART_IRQ-1    ; ICW2: 中断向量基值
    OUT DX, AL
    
    MOV AL, 01H         ; ICW4: 8086模式, 非缓冲, 正常EOI
    OUT DX, AL
    
    ; 允许IRQ1中断
    IN AL, DX
    AND AL, 0FDH        ; 清除IRQ1屏蔽位(11111101)
    OUT DX, AL
    
    RET

; =============================================
; 设置中断向量
; =============================================
SET_INTERRUPT_VECTOR:
    CLI                 ; 关中断
    XOR AX, AX
    MOV ES, AX          ; ES = 0 (中断向量表段地址)
    
    ; 计算中断向量位置 (中断号 * 4)
    MOV AX, UART_IRQ
    SHL AX, 2           ; 乘以4
    
    ; 设置中断向量
    MOV DI, AX
    MOV AX, OFFSET UART_ISR
    CLD
    STOSW               ; 存储偏移地址
    MOV AX, CS
    STOSW               ; 存储段地址
    STI                 ; 开中断
    RET

; =============================================
; UART中断服务程序 (IRQ1)
; 演示中断触发和释放过程
; =============================================
UART_ISR PROC FAR
    ; 保存寄存器
    PUSH AX
    PUSH DX
    PUSH DS
    
    ; 设置DS为当前数据段
    MOV AX, CS
    MOV DS, AX
    
    ; 设置中断触发标志
    MOV [int_triggered], 1
    
    ; 发送中断触发消息
    MOV SI, OFFSET trigger_msg
    CALL SEND_STRING
    
ISR_LOOP:
    ; 检查中断源
    MOV DX, IIR_FCR
    IN AL, DX
    TEST AL, 01H        ; 检查是否有待处理中断 (bit0=1表示无中断)
    JNZ ISR_EXIT        ; 无中断则退出
    
    ; 检查是否为接收数据中断
    TEST AL, 04H        ; 检查中断类型位 (bit1-2)
    JNZ CHECK_OTHER     ; 不是接收中断则检查其他
    
    ; 处理接收数据中断
    MOV DX, RBR_THR
    IN AL, DX           ; 读取接收到的字符
    MOV [recv_char], AL ; 保存字符
    
    ; 发送接收消息
    MOV SI, OFFSET recv_msg
    CALL SEND_STRING
    MOV AL, [recv_char]
    CALL SEND_CHAR
    
    ; 继续检查其他中断
    JMP ISR_LOOP
    
CHECK_OTHER:
    ; 可以添加其他中断类型的处理
    ; ...
    
ISR_EXIT:
    ; 发送中断释放消息
    MOV SI, OFFSET release_msg
    CALL SEND_STRING
    
    ; 发送EOI到8259
    MOV AL, 20H
    MOV DX, PIC_CMD
    OUT DX, AL
    
    ; 设置中断释放标志
    MOV [int_released], 1
    
    ; 恢复寄存器
    POP DS
    POP DX
    POP AX
    IRET
UART_ISR ENDP

; =============================================
; 串口发送字符子程序
; 输入: AL = 要发送的字符
; =============================================
SEND_CHAR:
    PUSH AX
    PUSH DX
    
    ; 保存字符
    MOV AH, AL
    
SEND_WAIT:
    ; 检查发送保持寄存器是否为空
    MOV DX, LSR
    IN AL, DX
    TEST AL, 20H        ; 检查THRE位(bit5)
    JZ SEND_WAIT        ; 不为空则等待
    
    ; 发送字符
    MOV DX, RBR_THR
    MOV AL, AH
    OUT DX, AL
    
    POP DX
    POP AX
    RET

; =============================================
; 串口发送字符串
; 输入: SI = 字符串偏移地址
; =============================================
SEND_STRING:
    PUSH AX
    PUSH SI
    
SEND_STR_LOOP:
    LODSB               ; 加载字符到AL
    OR AL, AL           ; 检查是否结束(0)
    JZ SEND_STR_DONE    ; 是则结束
    
    CALL SEND_CHAR      ; 发送字符
    JMP SEND_STR_LOOP   ; 继续发送
    
SEND_STR_DONE:
    POP SI
    POP AX
    RET

; =============================================
; 主初始化程序
; =============================================
INITIALIZATION:
    ; 初始化标志
    MOV [int_triggered], 0
    MOV [int_released], 0
    
    ; 初始化UART
    CALL INIT_UART
    
    ; 初始化8259 PIC
    CALL INIT_PIC
    
    ; 设置中断向量
    CALL SET_INTERRUPT_VECTOR
    
    ; 通过串口发送启动消息
    MOV SI, OFFSET start_msg
    CALL SEND_STRING

; =============================================
; 主程序循环
; =============================================
MAIN_LOOP:
    ; 可以在这里添加其他任务
    ; 例如: 检查中断标志状态等
    
    ; 简单的延时循环
    MOV CX, 0FFFFH
DELAY_LOOP:
    LOOP DELAY_LOOP
    
    ; 检查退出条件(可选)
    ; ...
    
    JMP MAIN_LOOP        
    
    
    
    DB  55H,55H,55H,55H,55H

; =============================================
; 退出程序(可选)
; =============================================
; 此示例程序将无限运行
; 在实际应用中可添加退出逻辑
相关推荐
张朝阳的博客5 分钟前
哈夫曼树Python实现
开发语言·python
dujunqiu6 分钟前
S32DS上进行S32K328的时钟配置,LPUART时钟配置步骤详解
单片机·mcu
阑梦清川7 分钟前
C#建立与数据库连接(版本问题的解决方案)踩坑总结
开发语言·数据库·c#
听风lighting33 分钟前
1. C++ WebServer项目分享
linux·c语言·c++·设计模式·嵌入式·webserver
药95533 分钟前
数据结构 4 (栈和队列)
java·开发语言·数据结构
smileNicky38 分钟前
Java实现Excel图片URL筛选与大小检测
java·开发语言·excel
code_li1 小时前
C#实现语音预处理:降噪/静音检测/自动增益
开发语言·c#
2401_858286111 小时前
CD45.【C++ Dev】STL库的list的使用
开发语言·数据结构·c++·list
int型码农1 小时前
数据结构第八章(五)-外部排序和败者树
c语言·数据结构·算法·排序算法
面朝大海,春不暖,花不开2 小时前
Java服务提供者模式实现指南
java·开发语言·python