微型计算机课程设计:基于8255A的简易计算器实现
2026/9/18 14:39:05 网站建设 项目流程

简介:这是一份微型计算机技术及应用课程的设计报告,由李智完成,主题是基于DOSBox环境实现简易计算器。报告面向计算机及相关专业学生,可作为课程设计、实验项目或汇编语言与接口技术学习的参考资料。资源为单个PDF文件,大小423KB,共347人浏览学习。内容覆盖设计目的与任务、DOSBox与中断基础知识、总体方案与原理框图、核心程序代码以及系统模块详细调试过程。其中包含加法、减法、乘法、除法等基本运算的实现思路,并展示了从ASCII码转换到二进制、再输出十进制结果的完整流程。读者可借助报告中的代码片段与调试说明,理解微型计算机中断机制、屏幕显示设置及键盘输入处理等关键知识点,适合需要完成类似课程设计或希望巩固微机原理的初学者。

1. 微型计算机课程设计里的简易计算器:一份PDF要解决的三个问题

在高校计算机、电子与自动化专业的培养计划里,“微型计算机课程设计”几乎是一门必开课,而“简易计算器”是出现频率最高的题目之一。这个题目看起来简单,实际上要求完成三件事:用汇编语言驱动CPU、通过8255A类并行接口扩展外部设备、组出一个能连续完成加减乘除的闭环系统。它和用Python写一个计算器完全不同,难点全在硬件时序与软件状态的配合上。

如果你手头只有一份课程设计报告PDF,这份文档的价值不只是“答案”,而是一张可以反向复现的电路与程序地图。下面顺着“设计一个能用于课堂验收的简易计算器”这条主线,把硬件接线、键盘扫描、运算状态机和调试方法串起来,适合正要动手搭相似系统的同学,也适合想快速读懂他人报告里关键代码的工程人员。

2. 方案选型:简易计算器的8255A接口与三个选型问题

2.1 为什么用8255A展开IO,而不是直接把外设挂在总线上

微型计算机课程的实验平台通常是8086 CPU加EPROM、RAM、锁存器、地址译码器、8255A、数码管和矩阵键盘的组合。8255A在这里不是用来“加速计算”,它的核心作用是解决CPU引脚与外设信号不匹配的问题。8086的地址线、数据线在物理上不能直接连一个机械键盘矩阵,因为总线没有锁存能力,键盘也没有三态缓冲,读写时序对不上。8255A的三个8位端口分别承担段码输出、位选输出和键盘行列读写,正好覆盖一台简单计算器需要的全部外设类型。

选型时先回答三个问题。第一,键盘有多少个键:4×4矩阵共16个键刚好覆盖0-9、加、减、乘、除、等号、清零,一个不多一个不少。若要加开根号、正负号、退格,就要改5×4矩阵,或者用第二片8255A。第二,显示用几位数码管:8位足够同时显示中间结果和最终结果,4位则需要提前约定运算模式,比如按完运算符后立刻清显示,否则用户看不到自己输入到第几位。第三,是否需要中断:本场景用轮询扫描完全够用,不必要引入8259A;只有当CPU还要并行处理定时刷新、外部告警等任务时,中断式键盘输入才有意义。

2.2 端口地址的计算方法与控制字选择

实验箱的8255A片选通常挂在74LS138译码器的某个输出端上,地址线A1、A0接到8255A的端口选择端,A2以上的高位地址参与译码。假定某实验箱把译码输出分配给8255A,基址为200H,那么四个端口地址就固定成下面的对应关系。注意8086访问8位外设时用偶地址,所以相邻端口间隔是2而不是1。

端口示例地址读写用途
A口200H写数码管段码
B口202H写数码管位选
C口204H低4位读键盘行,高4位写键盘列
控制口206H写工作方式控制字

工作方式控制字推荐写成81H,也就是二进制的10000001B。每位含义如下:D7=1表示这是方式字;D6D5=00表示A组方式0;D4=0表示A口输出;D3=0表示C口高4位输出;D2=0表示B组方式0;D1=0表示B口输出;D0=1表示C口低4位输入。这个组合正好对应“A口送段码、B口送位选、C口低4位读行、C口高4位写列”。控制字写错一位,键盘和显示的方向就会全部错乱,调试时先查这里。

2.3 连线前先固定一张信号约束表

动手连线之前,先画一张跨芯片的信号约束表,把每一个引脚的方向和电气含义固定下来,否则调试时会在“行线到底接高四位还是低四位”这种问题上反复折腾。参考接法如下:

8255A引脚方向外部器件备注
PA0-PA6输出数码管a-g段PA7可接小数点
PB0-PB7输出位选三极管共阳数码管低电平点亮
PC0-PC3输入键盘行线必须加上拉电阻
PC4-PC7输出键盘列线扫描时轮流输出低电平

提示:不同实验箱的行列分配可能完全相反,报告里的原理图才是唯一依据。表格的作用是让代码里的掩码、控制字和实际接线一一对应,报告评阅老师通常会顺着这张表看你能不能自圆其说。

3. 键盘扫描与键值映射:简易计算器里用轮询替代中断的路径

3.1 4×4矩阵键盘的“逐列拉低、逐行读入”

在8086教学平台上做键盘输入,最稳定、最容易解释给老师听的方案是逐列拉低、逐行读入。算法思想是:每次只把某一列线置为低电平,其余列线保持高电平,然后读入行线状态;如果某一行变成低电平,说明该行与当前列交叉处的按键被按下。读完一列没有按键,就把低电平移到下一列继续扫,四轮都扫完没有键则回到第一列。

用汇编实现的扫描骨架如下。地址部分按上一章的200H-206H示例编写,实际使用时以实验箱原理图标注的地址为准。

; 键盘扫描,返回键值在AL,无按键时返回0FFH KEY_SCAN PROC NEAR MOV DX, 0206H ; 8255A控制口 MOV AL, 10000001B ; 方式字:C口高4位输出、低4位输入 OUT DX, AL SCAN_NEXT: MOV BL, 0 ; BL作列计数器,0~3 MOV AL, 11101111B ; 初始掩码:PC4拉低,其余列线为高 NEXT_COL: MOV DX, 0204H OUT DX, AL ; 把列掩码写到C口 MOV CL, AL ; 暂存当前列掩码 IN AL, DX ; 读C口引脚电平 AND AL, 00001111B ; 只保留行线对应的低4位 CMP AL, 00001111B JNE GOT_KEY ; 读到的行值不是全1,说明有键按下 MOV AL, CL ROL AL, 1 ; 把唯一的0左移一位,切换下一列 INC BL CMP BL, 4 JE NO_KEY JMP NEXT_COL GOT_KEY: ; 此刻BL是列号,AL低4位中0所在的位置就是行号 ; 把行值1110B/1101B/1011B/0111B换算成0~3的行索引 ; 最终键索引 = 行号 * 4 + 列号,再用查表得到键值 ... RET NO_KEY: MOV AL, 0FFH RET KEY_SCAN ENDP

代码里的关键点有三个:一是先写控制字再扫描,否则C口方向没设对,读到的行值永远是输入引脚的电平,和列输出无关;二是ROL AL, 1让列掩码按0EFH、0DFH、0BFH、07FH的顺序循环,四次覆盖全部列线;三是GOT_KEY分支里拿到的是行线原始电平,必须把它换算成0~3的行号,最常见的写法是逐位测试或查一个4字节的小表。无按键时返回0FFH,主循环据此决定是否进入按键处理。

3.2 20毫秒去抖与等待释放,顺序不能反

课程设计翻车最多的地方不是扫描逻辑本身,而是按一次键被识别成两次。机械按键在按下和释放的瞬间都有大约5到15毫秒的抖动波形,CPU扫描频率远高于这个速度,同一个键会被连续捕捉到多次。解决办法是检测到某行被拉低后,先延时20毫秒,再读一次确认仍然处于按下状态,才认定按键有效。

; 约20毫秒延时,主频按5MHz估算 DELAY_20MS PROC NEAR PUSH CX MOV CX, 5000 DELAY_REP: NOP NOP LOOP DELAY_REP POP CX RET DELAY_20MS ENDP

这段循环的延时参数是这样估出来的:8086在5MHz下,LOOP指令大约需要16个时钟周期,加上两条NOP,一轮循环约20个时钟周期,即4微秒。5000轮就是20毫秒,正好落在机械按键抖动窗口之外。如果你用的实验箱主频不同,把CX的值按比例调整即可,不必改用定时器。

按键处理完还必须等待释放。若漏掉这一步,用户按住等号键0.5秒,程序会认为连续按了几十次等号,结果反复累加。正确顺序是:扫描到按键,去抖确认,处理按键功能,然后进入一个小循环反复读行值直到全部恢复为高电平,最后才回到主扫描。

3.3 键值表与查表映射的实际写法

按键行列号最终要映射成数字、运算符和功能码。我用一张16字节的表来做这件事,下标就是行列索引。以按钮布局为7、8、9、除号在第一行,4、5、6、乘号在第二行,1、2、3、减号在第三行,C、0、等号、加号在第四行为例:

KEY_MAP DB '7','8','9','/' DB '4','5','6','*' DB '1','2','3','-' DB 'C','0','=','+'

行列索引的计算方式是:行号乘4加列号。比如第三行第二列(数字3)的索引是2×4+1=9,对应表中第10个元素。扫描代码里算出行列索引后,用MOV AL, KEY_MAP[BX]一次查表得到键值。如果更换实验箱后接线顺序变了,只需要改这张表的排列,扫描函数主体完全不动。

提示:行线接PC0-PC3时,必须保证这4个引脚在空闲状态下读到高电平,否则按键没有按下也可能被误判。大多数实验箱已经在主板上配了上拉电阻,如果是自己搭面包板,要在每根行线上接10kΩ上拉。

4. 运算状态机与BCD码计算:加减乘除的简单代码实现

4.1 四状态主循环:等待输入、读操作数、读运算符、再读操作数

计算器主循环不依赖操作系统,而是围绕一个四状态的状态机转动。四个状态是:ST_INIT等待第一个操作数,ST_NUM1输入第一个操作数,ST_OP等待运算符,ST_NUM2输入第二个操作数。主循环读键后先判断是不是数字、运算符、等号或清零键,再按当前状态决定怎么处理。

// 用于理解汇编主循环的结构,实际实现时是CMP/JMP跳转链 while (1) { key = scan_key(); if (key == 'C') { reset_all(); continue; } if (key >= '0' && key <= '9') { if (state == ST_OP) { op1 = 0; // 按下运算符后开始输入新操作数 state = ST_NUM2; } push_digit(key - '0'); update_display(); } if (is_operator(key)) { if (state == ST_NUM2) { // 连续运算:先把上一步结果算出来作为op1 op1 = execute(op1, op2, current_op); display(op1); } current_op = key; state = ST_OP; } if (key == '=') { op1 = execute(op1, op2, current_op); display(op1); state = ST_INIT; // 等号后按运算符可继续算 } }

这段逻辑里最容易被忽略的是连续运算:用户输入2+3+4再按等号,第二个加号出现时,程序应当先把2+3的结果5算出来作为第一个操作数,再进入等待下一轮输入。如果不做这一步,运算结果会一直停留在最近一次等号触发时,中间的运算符全部丢失。汇编实现时,每个分支开头都要先判断当前状态,状态错一位就会出现“按完运算符再按数字把显示清了但状态没切换”的典型bug。

4.2 用BCD码做加减法,DAA与DAS的调整原理

课程设计里常用压缩BCD码存数,一个字节表示两位十进制数,高4位是十位,低4位是个位。选BCD而不是纯二进制的直接理由是显示方便:BCD的每一位正好对应数码管一位,转段码时不需要反复除以10取余。加减法在AL上配合DAA或DAS做十进制修正,代码量很小。

; 两个压缩BCD字节相加:NUM_A + NUM_B -> SUM ADD_BCD: MOV AL, NUM_A ADD AL, NUM_B DAA ; 十进制加法调整 MOV SUM, AL RET

DAA的调整依据是AL的低4位是否大于9或辅助进位AF是否为1,以及高4位是否大于9或进位CF是否为1。例如0x08加0x09,二进制相加得到0x11,低4位运算时产生了辅助进位,AF置1,DAA把AL加上0x06得到0x17,正好是BCD的17。减法用DAS做同样的反向调整,规则判断的是借位标志。

乘法和除法没有对应的BCD修正指令,常见做法是把操作数转成普通二进制,算完再转回BCD。对于0到99的两位输入范围,二进制运算后循环除以10取余即可恢复BCD编码。8086的字节除法DIV在计算一位数除法时,商放AL、余数放AH,天然对应“商和余数”两个结果,处理除法显示时直接利用这一点,不需要额外写取余逻辑。

4.3 8位数码管动态扫描:段码与位选的时序细节

显示模块由PA口送段码、PB口送位选。动态扫描的核心是一次只点亮一位数码管,8位轮流点亮,人眼视觉暂留会把分时信号合成连续图像。每位点亮约2毫秒,完整循环16毫秒,刷新率约60Hz,观感不闪烁。

; 动态扫描一轮,DISP_BUF保存8个已转换好的段码 DISP_LOOP: MOV BX, OFFSET DISP_BUF MOV DI, 0 ; 位索引 MOV CL, 8 ; 8位数码管 DISP_NEXT: MOV DX, 0202H MOV AL, OFF_MASK ; 先关闭全部位选,消除重影 OUT DX, AL MOV AL, [BX] MOV DX, 0200H OUT DX, AL ; 写段码 MOV AL, BIT_SEL[DI] ; 查表得到当前位的位选码 MOV DX, 0202H OUT DX, AL ; 打开当前位 CALL SHORT_DELAY ; 约2毫秒 INC BX INC DI DEC CL JNZ DISP_NEXT RET

段码和位选的先后顺序很关键:必须先关掉前一位的位选,再更新段码,最后打开新一位,否则前一位的数字会以新段码的笔划亮一小段时间,肉眼看到的就是“重影”或“残影”。位选码表BIT_SEL的具体值与数码管共阴共阳有关,共阳接法低电平点亮时,位选码依次为0FEH、0FDH、0FBH、0F7H、0EFH、0DFH、0BFH、07FH。显示循环必须放在主循环里周期执行,每完成一轮顺便调用一次键盘扫描,否则数码管点亮期间CPU完全被占住,按键响应会慢到不可用。

4.4 负号、溢出与除零三个边界问题的处理方式

这些边界问题是评阅老师最常追着问的,也是课程设计报告里最容易被忽略的部分。负数处理:两数相减前先比较大小,若被减数小于减数,交换两数再相减,同时置负号标志,显示时在最左位输出“−”的段码,并保证后续数字不会覆盖这个负号位。若报告里没有这一步,代码一跑负号就会出现乱码。

溢出处理:两位数输入的算式,99+99已经等于198,超过两位范围。8位数码管能显示三位以上,但8086寄存器宽度有限,设计时要明确显示位数上限,超过上限就显示“E”并停止运算,必须按C才恢复。不要在溢出后继续执行运算,否则后续BCD转换会得出完全不可预期的值。

除零处理:执行除法前先检查除数是否为0,为0就跳过除法子程序,直接显示“E”。8086的DIV指令对被零除会引发#DE异常,在实模式下如果实验箱没有安装对应中断处理程序,程序可能直接挂起或跑飞,这个问题必须靠软件提前拦掉。验收时主动演示一次除零显示错误码,比等老师问到再解释要主动得多。

5. 从PDF反推实现:三种值得试的验证路径与提交细节

5.1 从原理图反查端口方向与控制字

拿到课程设计PDF,先看原理图和接线图,再读程序。重点核对8255A的C口和键盘行、列的实际连接:报告正文说PC0-PC3是行输入,但原理图可能把行列画反,程序里的控制字和掩码就要跟着调整。把PDF中初始化代码写的控制字与C口方向对照一遍,能快速发现这类不一致。自己写代码时也按这个顺序走:先确认端口地址,写一个只向A口送段码的小测试程序,看到数码管亮了再继续写键盘扫描,避免一次性调一大段汇编。

5.2 三种不需要完整硬件环境的调试手段

第一种是EMU8086或DOSBox加MASM的纯软件模拟,验证状态机转移和运算结果是否偏离。第二种是实验箱自检程序:把PA口接8个LED,按下按键时直接观察LED上呈现的二进制键值,能直观看出扫描和行列索引是否映射正确。第三种是逻辑分析仪抓行线和列线波形,按下按键时对应行、列同时出现低电平脉冲,这是判断去抖参数和扫描顺序是否正确的最可靠手段。没有逻辑分析仪时,把扫描延时临时改成0.5秒,用电表量引脚电平也能判断通路是否正常。

5.3 报告撰写中容易失分的三个细节与最小验收序列

报告评审通常看重三处:键盘扫描要有流程图或状态转移表,不能只贴汇编;运算部分要写明为什么用BCD以及DAA/DAS的调整条件;清零键和等号键的释放时序要说明,是按下去就清还是释放后再清,连按会不会误触发。

现场验收建议跑两条最小序列。序列一:按1、2、3、+、4、5、6、=,显示579;再按C清零,显示0。序列二:按3、5、-、8、0、=,显示-45。两条序列分别覆盖正数运算、负数显示和清零复位。稳定跑完这两组,键盘扫描、运算状态机、动态显示三条链路都已闭环,剩下的只是运算符扩展和报告润色工作。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询