汇编语言:深入解析8251A串行通信的查询与中断模式编程
1. 8251A串行通信基础:从并行到串行的桥梁
当你用键盘敲击字母时,CPU接收到的实际上是8位并行数据。但如果你要通过电话线传输这些数据,就需要一位一位地发送——这就是串行通信的典型场景。8251A正是为解决这类问题而生的可编程芯片,它能在并行数据和串行数据之间架起转换的桥梁。
这个40引脚的双列直插式芯片内部藏着两个独立的世界:发送器和接收器。发送器把CPU送来的并行数据(比如8位ASCII码)转换成串行比特流,通过TXD引脚发送出去;接收器则从RXD引脚收集串行数据,攒够一个完整字符后通知CPU来取。我调试电路时曾犯过一个典型错误:忘记连接CTS(清除发送)引脚,导致数据永远卡在发送缓冲区。后来用示波器抓信号才发现,硬件流控制引脚的状态直接影响着数据流动。
方式控制字是8251A的"身份证",它决定了芯片的基本通信参数。假设我们要配置1200bps、7位数据、偶校验、1位停止位的异步模式,对应的二进制模式是01011010(0x5A)。这个值需要写入控制端口,但新手常困惑的是:为什么同样的地址既能写控制字又能写数据?秘密在于C/D(控制/数据)引脚——当它为高电平时写入的是控制信息,低电平时才是真实数据。
2. 查询模式编程:CPU的主动轮询
查询模式就像班主任课间检查作业——CPU不断查看8251A的状态寄存器,确认数据是否准备就绪。状态寄存器的第0位(TXRDY)为1表示发送缓冲区空,第1位(RXRDY)为1则表示收到新数据。这种模式下,典型的发送流程是这样的:
MOV DX, 2B9H ; 控制端口地址 WAIT_TX: IN AL, DX ; 读取状态 TEST AL, 01H ; 检查TXRDY位 JZ WAIT_TX ; 未就绪则继续等待 MOV AL, 'A' ; 准备发送字符'A' MOV DX, 2B8H ; 数据端口地址 OUT DX, AL ; 发送数据实测中发现一个坑:状态寄存器中的TXRDY和芯片引脚TXRDY不是一回事!前者仅表示缓冲区空,后者还需满足CTS有效且发送器使能的条件。我曾花了三小时排查为什么程序显示可以发送但实际无输出,最终发现是忘记在命令控制字中开启发送使能(TXEN位)。
在双机通信实验中,查询模式需要双方严格同步。建议在代码中加入超时机制,比如用8253定时器计数,超过500ms未收到响应就重发。这种模式虽然简单,但在传输大文件时会导致CPU利用率飙升——就像不断刷新邮箱页面等邮件,其他什么事都干不了。
3. 中断模式编程:高效的异步响应
中断模式则是让8251A主动敲门——当数据到达时通过IRQ引脚通知CPU。这需要配合8259中断控制器工作,配置过程就像设置智能门铃:
- 计算中断向量:假设使用IRQ3,对应的中断号是0Bh
- 编写中断服务程序(ISR),保存现场后读取数据
- 在8251A命令字中开启接收中断(RXE和RXIE位)
- 配置8259的IMR寄存器,开放相应中断
; 中断初始化 CLI MOV AL, 0Bh ; 中断号 MOV AH, 25H ; 设置中断向量功能号 MOV DX, OFFSET ISR ; ISR偏移地址 INT 21H ; 配置8251A MOV DX, 2B9H MOV AL, 00010101B ; 命令字:使能接收、发送、错误复位 OUT DX, AL STI ISR PROC FAR ; 中断服务程序 PUSH AX PUSH DX MOV DX, 2B8H IN AL, DX ; 读取数据 MOV [BUFFER], AL ; 存入缓冲区 MOV AL, 20H ; EOI信号 OUT 20H, AL POP DX POP AX IRET ISR ENDP调试中断程序时,逻辑分析仪是神器。我曾在示波器上抓到一个诡异现象:偶尔会丢失中断。后来发现是ISR执行时间过长,导致新的中断被淹没。解决方法是在ISR开头就发送EOI(中断结束)命令,或者改用中断嵌套。对于实时性要求高的场景(如工业控制),中断模式的响应速度能比查询模式快10倍以上。
4. 模式对比与实战选择指南
通过自发自收实验的数据对比,两种模式的差异一目了然:
| 指标 | 查询模式 | 中断模式 |
|---|---|---|
| CPU占用率 | 高达90% | 通常低于20% |
| 响应延迟 | 取决于轮询间隔 | 通常<100μs |
| 编程复杂度 | 简单 | 需处理中断嵌套 |
| 适用场景 | 低速单任务系统 | 多任务/实时系统 |
在智能家居网关项目中,我这样选择模式:温湿度传感器数据采用中断接收(事件驱动),而固件升级时的大文件传输改用查询模式。因为前者需要及时响应环境变化,后者则要保证连续传输不被打断。特别提醒:当波特率超过9600时,建议优先考虑中断模式,否则CPU可能来不及响应。
两种模式其实可以动态切换——初始化时配置好两种参数,通过软件开关选择。我在Linux串口驱动中就见过这种设计,通过ioctl命令切换轮询和中断模式。这给我们的启示是:硬件编程要留出软件弹性,就像8251A的方式字和命令字分离设计一样,预留扩展空间才能应对需求变化。
