汇编语言(英語:assembly language):是任何一种用于电子计算机、微处理器、微控制器,或其他可编程器件的低级语言。 在不同的设备中,汇编语言对应着不同的机器语言指令集。 一种汇编语言专用于某种计算机系统结构,而不像许多高级语言,可以在不同系统平台之间移植。
Keil: 是美国Keil软件公司出品的支持8051系列单片机架构的一款IDE(集成开发环境)。
AT89C51:是一种带4K字节FLASH存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压、高性能CMOS 8位微处理器,俗称单片机。
普中开发版原理图:
题目:电子计算器 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,设计电子计算器。 功能要求:(1)实现十进制 3 位以上的加减乘除功能;(2)实现正负数计算; (3)连续计算,即在前一次计算结果的基础上继续进行四则运算。
一、小组成员分工
分工情况:该设计主要由我和其他小组成员合作完成,我负责硬件的显示功能、按键的判断、各个模块的逻辑、所有模块的拼接组合,我的队友负责加减乘除算法,及总体框架构思。
二、设计要求
实验目的:设计一个电子计算器,实现十进制3位以上的加减乘除功能,实现正负数运算和连续运算。
设计要求:基于51开发板,利用矩阵键盘作为按键输入,将数码管作为显示输出
《汇编语言程序设计实践》是为汇编语言程序设计课程而独立开设的实践性课程。对于巩固和加深理解汇编语言程序设计,加强学生的实际动手能力和提高学生综合素质十分必要。通过一周的学习和设计,使学生掌握汇编语言程序设计、单片机应用开发的基本方法,从而获得开发基于汇编语言的单片机系统的基本能力。
(1)掌握汇编指令系统和语法,具备汇编语言程序设计开发能力。面向复杂工程问题,能够使用汇编语言,设计开发相应的功能模块。
(2)掌握单片机的结构和工作机理,基于单片机硬件体系,能够开发满足工厂应用需求的单元模块。
(3)具备基于单片机硬件,利用汇编语言设计实现相关应用开发的能力。能够采用软硬件结合的方法,针对计算机领域的复杂工程问题进行研究,设计合理的实验方案。
三、设计思路
3.1总体框架
流程图:
图3-1 流程图
①矩阵键盘模块
构成:该模块由16个轻触按钮构成,其中同一行的按钮的一端都相连,同一列的按钮的一端也相连。
主要用途:根据用户使用的按键情况完成相应的操作,即输入操作数和运算符。
图3-2 矩阵按键原理图
此外特别说明下矩阵键盘布局。此次矩阵键盘共有16个键,其中10个为数字键入键,另外6为功能键,下面对其各自用图进行说明。
计算器按键分布:
图3-3 按键布局
1.0~9:数字键。按下该键后,数字输入到计算器
2.CL:全部清零键。按下该键后,计算器将清零一切信息。
3."=":等于号。按下该键后,单片机将会执行运算并显示结果。
4.”+”:加法键。按下该键后,单片机将会保存第一个操作数,并在记录下加法操作。
4.”-”:减法键。按下该键后,单片机将会保存第一个操作数,并在记录下减法操作。
4.”*”:乘法键。按下该键后,单片机将会保存第一个操作数,并在记录下乘法操作。
4.”/”:除法键。按下该键后,单片机将会保存第一个操作数,并在记录下除法操作。
②数码管显示模块
构成:该模块由八个的七段共阴极数码管构成。
图3-3 动态数码管原理图
主要用途:是用于显示矩阵键盘所按下的键值,以及最后计算的结果。
③独立键盘退格模块(扩展模块)
构成:该模块由一个独立键盘构成。
图3-5 独立按键原理图
主要用途:是用于回退用户上次按下的数字键并且可以重新输入。
④独立键盘负号模块
构成:该模块由一个独立键盘构成。
主要用途:是用于输入负数。
3.3程序清单
表3.1 程序清单表
4.功能模块函数设计
①加法:
将指针指向两个操作数最低位地址,进行加法运算,如果结果为10,保留进位cy=1的结果,将0存入结果地址,不为10则将原结果存入保留结果地址,指针加一指向下一个操作位,进行下一位的带符号的加法运算,循环次过程直到两个操作数的四位结果都运算完成
②减法:
先将指针指向两个操作数的最高位,从操作数的最高位到最低位进行依次判断,比较减数和被减数的大小,如果减数大于被减数,负号标志位置1,则交换减数和被减数运算位置,如果减数不大于被减数,则不改变两个操作数位置,接着指针指回操作数的最高位,从最高位到最低位进行带符号的减法操作,将结果存入目标地址
流程图:
①加法:
图4-1 加法流程图
②减法:
图4-2 减法流程图
③乘法:
乘法的本质是一个数n自加m次,所以记作n*m,所以我们的想法是从单片机获取两个操作数,第一个操作数n自加第二个操作数m次,并且利用操作码DA来直接实现十进制 乘法。
④除法(内含除法余数扩展):
在进行除法时,我们从单片机获取两个操作数,并且进行两个寄存器与两个两个寄存器之间的除法,因此需要向左移动16次,在被除数寄存器前在放两个寄存器,将第一个操作数进行左移,左移进入被除数寄存器前的两个寄存器,在将两个寄存器里的值减去除数,,如果cy等于0,说明能够进行减法,这时被除数和商都要左移,商要加一,并且将余数放在这两个寄存器中,如果cy=1,说明不够减,这是这时被除数和商都要左移,但商不要加一,如此循环16次。将商存放在目的地址中。
流程图:
③乘法:
图4-3 乘法流程图
④除法:
图4-4 除法流程图
四、实现效果
数码管前四位为第一个操作数,数码管后四位为第二个操作数。
如图为加法运算:
求和 11+22=33
图4-5 实现效果图1
图4-6 实现效果图2
当出现负数运算时,LED数码管第一位为符号位显示负号
如图为减法运算:
求差 33-66=-33
图4-7 实现效果图3
图4-8 实现效果图4
当进行连续运算时,位于数码管后四位的前一次运算结果移至数码管前四位作为第一个操作数,后四位进行下一个操作数的输入
如图为连续的乘法运算:
求积 -33*11=-363
图4-9 实现效果图5
图4-10 实现效果图6
在进行除法运算时,数码管的后四位显示除法运算的商,数码管的前四位显示余数。
如图为连续的除法运算:
求商 -363/66=5 求余数-363%66=-33
图4-11 实现效果图7
图4-12 实现效果图8
五、 总结
① 学会如何将用户输入转变成十进制进行运算,以及利用十进制进行输出显示。
② 掌握3位以上的四则运算,使用十进制进行加减乘除。
③ 学会如何在程序中加上测试代码,以便找出程序中的bug(例如在判断是否进入某个子程序,可以在子程序中改变49H~53H中的值,使得数码管输出相应的结果,以此判断bug的位置)
④ 利用最初学习加减乘除运算的本质,将加减乘除运算转变成加减操作,实现汇编语言十进制三位以上操作数的四则运算。
⑤ 对于寄存器内部的运作方式有了更深一步的了解,更加明白直接寻址和间接寻址之间的区别以及对于汇编指令的运用更加熟练。
⑥ 也发现了还有很多不足,如对于单片机内部结构还不够熟悉,对于如何将数字灵活的在单片机数码管上显示还不够熟练。
实验中遇到的问题:
①问题:如何实现十进制计算器的乘除运算,是直接用十进制进行运算还是将十进制转化成十六进制运算再转化成十进制输出?
解决方法:由于将十进制转化成十六进制,并且运算时要克服寄存器只能放0~255范围的数据,相对于直接用十进制运算更复杂,经过尝试我们最后只实现了4位数的十进制与十六进制之间来回转换,所以最后决定采用十进制进行乘法运算,因为四位数乘四位数最多可以到八位,超过了我们转换的能力,而采用十六进制进行除法,因为四位除以四位计算结果最多四位,符合我们的转换能力。
②问题:如何实现OP操作后的跳转选择函数?
解决方法:刚开始使用了一个寄存器存放按键的值,根据按键的值跳转不同的运算函数,但是实现后发现,其他代码并没有使用该寄存器,寄存器的值却会发生改变,于是改用片内的存储地址存放按键值,当要选择运算函数的时候,再从地址中取出来放在寄存器进行判断,就能够正确实现函数跳转。
③问题:如何实现负数的乘除运算?
解决方法:采用一个额外地址空间来进行标记,并把这个地址内容初始化为0,每输入一次负的操作数,这个地址空间就加1,当要显示计算结果时如果这个地址空间的内容是奇数那么它就是负数,如果是偶数它就是正数。
④问题:如何实现连续计算。
解决办法:在思考时我们就发现加法和乘法计算的结果可能会超出四位,由于我们设计的是四位数计算器,故这不在我们的考虑范围。我们考虑四位及以内计算结果的连续计算,在进行连续运算时把上一次计算结果前移到前四个数码管,并保存数据到相应的地址,作为第一个操作数,然后再输入第二个操作数的即可。
⑤问题:在进行代码测试时得不到预期的结果
解决办法:再代码测试时,出现问题,难以判断错误位置,我们只能进行推断,可能是某个标志位的值不对也可能是其他原因,但这个推断我们无法在keil中的到验证,后来我们发现可以把推测的变量输入到数码管中显示,就可以判断与预期的差异,更好的发现错误