微机系统串行口内环测试:基于8250与中断的查询-中断混合编程实践

微机系统串行口内环测试:基于8250与中断的查询-中断混合编程实践 1. 8250芯片与串行通信基础第一次接触8250芯片时我和很多同学一样被密密麻麻的寄存器搞得头晕。这块看起来不起眼的芯片其实是串行通信的核心大脑。简单来说它就像个尽职的邮差负责把并行数据打包成串行信号发送出去再把接收到的串行信号拆包还原。8250芯片最神奇的地方在于它的波特率发生器。通过设置除数寄存器我们可以自由调整通信速率。记得当时做实验我特意尝试了从110bps到9600bps的不同速率看着屏幕上字符像打字机一样逐个跳出来突然就理解了波特率这个抽象概念。这里有个小技巧除数寄存器的高8位和低8位要分开写入而且必须先设置DLAB位为1这个细节我当初就漏掉过调试了半天才发现问题。芯片的线路控制寄存器LCR是配置通信格式的关键。我的实验记录本上还留着这样的配置8位数据位、1位停止位、无校验位03H。这种配置兼容性最好适合大多数ASCII字符传输。而Modem控制寄存器MCR的D4位特别有趣——把它置1就进入内环测试模式这时发送端和接收端在芯片内部直接连通非常适合调试。2. 混合编程模式实战解析查询发送和中断接收的混合模式就像餐厅里点餐和上菜的分工。发送端查询像服务员主动询问厨房准备好新订单了吗检查THR空标志而接收端中断则像厨师长菜做好了就主动敲铃通知触发中断。在代码中发送部分的核心循环是这样的SCANT: MOV DX,2FDH ; 线路状态寄存器 IN AL,DX TEST AL,20H ; 检查THR空标志位 JZ SCANT ; 未就绪则继续查询这个循环会持续检查bit5THR空标志直到8250准备好接收新数据。我实测发现在1200bps下这个等待通常不超过1ms。中断接收则复杂得多。首先要接管0BH中断向量这就像在学校的公告板上把自己的联系方式覆盖到快递通知栏目。关键是要保存原向量实验结束后必须恢复否则系统会崩溃。有次我忘记恢复就直接退出程序结果键盘突然失灵只能重启电脑这个教训至今记忆犹新。3. 初始化流程的魔鬼细节8250的初始化就像给新手机做设置漏掉任何步骤都会导致通信失败。根据我的踩坑经验必须严格按照这个顺序设置波特率MOV DX,2FBH ; LCR地址 MOV AL,80H ; 置DLAB1 OUT DX,AL MOV DX,2F9H ; 除数高8位 MOV AL,0 OUT DX,AL MOV DX,2F8H ; 除数低8位(1200bps) MOV AL,60H OUT DX,AL配置通信格式MOV DX,2FBH MOV AL,03H ; 8N1格式 OUT DX,AL启用FIFO和中断MOV DX,2F9H MOV AL,01H ; 允许接收中断 OUT DX,AL MOV DX,2FCH ; Modem控制寄存器 MOV AL,00011000B ; 内环模式中断使能 OUT DX,AL最容易出错的是最后一步的Modem控制寄存器。有次我把D3位OUT2设错了导致中断根本无法传递到8259调试了整整两小时才发现。建议用二进制直接写值比十六进制更直观。4. 中断服务程序的精妙设计中断服务程序ISR就像个身手敏捷的消防员必须快进快出。我的RECEIVE子程序最初没注意保护现场导致系统随机崩溃。后来改成这样RECEIVE PROC PUSH AX ; 保护现场 PUSH DX PUSH DS MOV AX,DATA ; 设置数据段 MOV DS,AX MOV DX,2F8H ; 接收缓冲区 IN AL,DX ; 读取数据 AND AL,7FH ; 屏蔽最高位 CMP AL,0DH ; 检查回车键 JE NEXT MOV AH,2 ; 显示字符 MOV DL,AL INT 21H JMP EXIT NEXT: MOV FLAG,-1 ; 设置结束标志 EXIT: MOV AL,20H ; 发送EOI OUT 20H,AL POP DS ; 恢复现场 POP DX POP AX IRET ; 中断返回 RECEIVE ENDP这里有个关键技巧中断返回前必须向8259发送EOI中断结束命令否则后续中断会被屏蔽。我曾在中断里加了延时想观察现象结果导致系统卡死这就是中断服务必须精简的原因。5. 调试技巧与常见问题调试串口程序时我总结了几条实用经验内环测试先于外环先用自发自收模式验证基本功能再连接外部设备。有次我直接接串口线测试结果因为电平问题折腾半天其实芯片本身工作正常。状态寄存器是救星线路状态寄存器LSR的每个位都值得关注。当通信异常时bit4帧错误、bit3奇偶校验错、bit1溢出错误能快速定位问题。建议在查询循环中加入错误检测MOV DX,2FDH IN AL,DX TEST AL,1EH ; 检查所有错误位 JNZ ERROR_HANDLER中断向量陷阱在实模式下中断向量表位于内存0000:0000处。我遇到过向量置换成功但中断不触发的情况最后发现是DS寄存器没设置正确。建议在调试时用DEBUG查看中断向量是否真正修改。波特率容错当收发双方波特率偏差超过3%时通信就会出错。我曾用示波器测量过发现实验室某些计算机的基准时钟有约1.5%的偏差这在长距离通信时需要特别注意。6. 键盘与显示的实时交互这个实验最有趣的部分是实时交互的实现。当你在键盘输入时程序要同时处理三个任务检测键盘输入、管理串口发送、响应接收中断。这就像边做饭边接电话需要很好的多任务协调能力。我的解决方案是用标志位轮询MAIN_LOOP: CMP FLAG,-1 ; 检查结束标志 JE EXIT_PROGRAM CALL CHECK_KEYBOARD CALL SEND_DATA JMP MAIN_LOOPCHECK_KEYBOARD子程序用INT 16H的非阻塞调用AH1检查键盘缓冲区避免程序卡住。而发送部分则要确保前一字符完全送出后才能发送下一个这就需要检查LSR的bit6发送移位寄存器空TWAIT: MOV DX,2FDH IN AL,DX TEST AL,40H ; 检查THRE JZ TWAIT7. 从实验室到工程实践做完这个实验后我在参加电子设计竞赛时真的用上了这些知识。当时需要让STM32和PC通信我直接借鉴了8250的编程思路。虽然现代UART更先进但基本框架惊人地相似。几个值得记录的工程经验工业环境中电磁干扰大建议在串口线上加磁环长距离传输时RS-232最多15米而RS-485可达1200米Linux下的串口设备需要设置termios属性比DOS复杂但原理相通遇到通信乱码时先检查地线连接再确认波特率记得有次调试一个二手设备对方使用非标准的7位数据位偶校验就是通过不断修改LCR配置最终试出来的。这种实战经验是单纯看理论永远学不到的。