x86 16位汇编无BIOS中断14h初始化COM1串口报错求助
问题根因分析
你代码的核心错误是端口地址的定义和引用方式完全错误,其余为次要的隐患问题:
- 端口地址引用错误
你用com1: dw 0x3f8的方式定义串口端口,是将0x3f8作为数据存储在内存的com1地址处;而你调用outb宏时传入的[com1+1]是读取com1偏移1的内存地址里的随机值作为端口号,完全不是你预期的0x3f8+1=0x3f9串口寄存器端口。
这直接导致你之前outb [com1+3], 0x80根本没有正确设置DLAB位,后续往数据端口写值时操作的是错误的寄存器,自然会触发线路状态错误。 - 实模式运行环境初始化不完善
你开头只初始化了部分段寄存器,没有配置栈段和栈指针,16位实模式下运行时很容易出现不可预知的内存覆盖问题,属于潜在隐患。 - 笔误小问题
注释里的38440是笔误,正确波特率是38400。
修复方案
核心修改点
- 将
com1从内存变量改为编译期常量,用equ定义,调用outb时直接传常量表达式,不需要加内存引用的方括号 - 补全栈段、栈指针的初始化
- 修正端口引用的写法
修复后的完整代码
%macro outb 2 mov dx, %1 mov al, %2 out dx, al %endmacro %macro inb 1 mov dx, %1 in al, dx %endmacro bits 16 org 0x7c00 ;; 引导扇区加载地址 xor ax, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; 初始化栈段 mov sp, 0x7c00; 栈指针指向引导扇区开头,向下增长不会覆盖代码 serial_init: outb com1+1, 0x00 ;; 关闭所有串口中断 outb com1+3, 0x80 ;; 开启DLAB,设置波特率除数 outb com1+0, 0x03 ;; 除数低字节为3,对应38400波特 outb com1+1, 0x00 ;; 除数高字节为0 outb com1+3, 0x03 ;; 8数据位、无校验、1停止位 outb com1+2, 0xc7 ;; 开启FIFO、清空FIFO、设置14字节阈值 outb com1+4, 0x0b ;; 开启IRQ、设置RTS/DSR outb com1+4, 0x1e ;; 开启环回模式测试串口芯片 outb com1+0, 0xae ;; 写入测试字节 ;; 可选:添加测试逻辑,读回数据判断是否等于0xae确认硬件正常 ; inb com1+0 ; cmp al, 0xae ; jne serial_error hang: jmp hang com1 equ 0x3f8 ; 定义COM1端口为编译期常量 times 510-($-$$) db 0 dw 0xaa55
内容的提问来源于stack exchange,提问作者永劫回帰
相关产品推荐
相关产品推荐

