在嵌入式系统开发的入门阶段,用8086处理器配合汇编语言实现计算器功能是个经典练手项目。这个看似简单的任务实际上涵盖了处理器架构、I/O控制、显示驱动、键盘扫描等核心知识点。我最近用Proteus 8.9和Masm 2015完整实现了这个系统,支持加减乘除四则运算和四位七段数码管显示,过程中积累了不少实战经验。
这个项目的独特之处在于完全使用汇编语言开发,相比高级语言项目,需要开发者直接操作硬件寄存器,处理底层时序问题。系统硬件核心采用8086 CPU搭配8255A并行接口芯片,通过8255的PA口控制数码管段选,PB口控制位选,PC口接4x4矩阵键盘。软件层面需要解决三个关键问题:键盘输入消抖处理、运算逻辑实现和数码管动态扫描显示。
在Proteus中搭建电路时,关键是要正确配置8086的最小系统。我的设计中使用了一片74HC373作为地址锁存器,一片8284A时钟发生器提供4MHz时钟信号。特别注意8086的MN/MX引脚需要接地,设置为最小模式工作。8255A的片选信号连接至地址线A10,因此其端口基地址为0x0600,具体端口分配如下:
数码管选用四位共阴型,每个段通过74HC245缓冲器连接8255的PA口,位选信号通过PNP三极管驱动。这种设计保证了足够的驱动电流,避免仿真时出现显示暗淡的问题。
8255A是系统的关键外设,需要正确初始化其工作模式。通过向控制寄存器(0x0606)写入0x81,将PA、PB口设置为模式0输出,PC口上半部输入、下半部输出。对应的汇编代码如下:
assembly复制MOV AL, 81H ; 控制字:PA/PB模式0输出,PC上半输入下半输出
MOV DX, CTRL ; CTRL=0606H
OUT DX, AL
这个配置完美适配我们的硬件设计:PA/PB用于数码管驱动,PC口高四位输出键盘扫描信号,低四位读取按键状态。
矩阵键盘扫描采用行反转法,相比逐行扫描更高效。核心思路是:
具体实现时需要注意按键消抖,我的经验是20ms延时效果最佳:
assembly复制SCAN_KEY:
MOV AL, 0F0H
OUT PORT_C, AL ; 高四位输出0,低四位输入
IN AL, PORT_C
AND AL, 0FH ; 取低四位
CMP AL, 0FH
JE NO_KEY ; 无按键
CALL DELAY_20MS ; 关键消抖延时
; 行反转检测
MOV AL, 0FH
OUT PORT_C, AL ; 低四位输出0,高四位输入
IN AL, PORT_C
AND AL, 0F0H ; 取高四位
; 组合高低四位结果确定键值
...
运算处理需要维护三个核心变量:
assembly复制NUM_BUFF DB 8 DUP(0) ; 输入缓冲区(ASCII码)
OPERAND1 DW 0 ; 第一操作数(二进制)
OPERATOR DB ? ; 运算符(+,-,*,/)
当用户按下数字键时,将ASCII码存入NUM_BUFF;按下运算符时,将NUM_BUFF转换为二进制存入OPERAND1,并记录OPERATOR;按下等号时,执行对应运算。特别注意除零错误的处理:
assembly复制DIVIDE:
CMP BX, 0
JNZ DO_DIV
MOV ERROR_FLAG, 1 ; 设置错误标志
RET
DO_DIV:
XOR DX, DX ; 清空DX(被除数高16位)
DIV BX ; AX=DX:AX/BX, DX=余数
MOV RESULT, AX ; 保存商
MOV REMAINDER, DX ; 保存余数
四位一体数码管采用动态扫描方式显示,通过快速轮流点亮每位实现视觉暂留效果。核心要点:
我的实现使用8253定时器产生2ms中断,在中断服务程序中切换显示位:
assembly复制DISPLAY_ISR:
PUSH AX
MOV AL, [DISPLAY_DATA+SI] ; 取当前位数据
OUT PORT_A, AL ; 送段码
MOV AL, BIT_MASK[SI] ; 位选信号
OUT PORT_B, AL ; 选通当前位
INC SI ; 指向下一位
AND SI, 03H ; 循环0-3
POP AX
IRET
在调试过程中发现几个关键差异点:
建议在仿真稳定后,先用示波器检查实际硬件的关键信号时序,特别是数码管扫描频率和键盘消抖时间。
虽然8086处理简单运算绰绰有余,但通过优化仍可提升响应速度:
例如数码管段码表优化:
assembly复制SEG_TABLE DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH ; 0-9段码
项目中实现的几个实用隐藏功能:
这些功能通过扩展键盘处理程序实现,增加了系统的实用性和趣味性。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 某段常亮 | 段驱动短路 | 检查74HC245输出 |
| 显示数字错误 | 段码表错误 | 核对SEG_TABLE数据 |
| 亮度不均 | 扫描时间不一致 | 确保每位置显示时间相同 |
| 全不亮 | 位选信号异常 | 检查PB口输出和PNP三极管 |
键盘无响应或误触发通常由以下原因导致:
16位二进制运算的精度限制:
建议在用户输入时进行范围检查,避免运算溢出导致错误结果。
在现有基础上,可以考虑以下增强功能:
硬件层面可以考虑:
这个8086计算器项目虽然基础,但涵盖了微机原理的核心知识点。通过完整实现,我对处理器架构、汇编编程和硬件调试有了更深入的理解。最大的收获是认识到仿真环境与真实硬件的差异,这提醒我在未来项目中要尽早进行硬件验证。