《单片机课程设计报告---计算器.docx》由会员分享,可在线阅读,更多相关《单片机课程设计报告---计算器.docx(20页珍藏版)》请在课桌文档上搜索。
1、目录:1、 课题目标22、 系统总体设计方案规划与选定23、 硬件设计24、 软件设计31. 1主程序流程图44. 2键盘读取程序流程图55. 3显示函数流程图66. 4数值转换流程图65、 调试76、 新增功能及实现方法107、 小结与体会118、 参考文献129、 附录(源程序代码、电路图等)121 课程目标设计一个计算器,实现两个4位数(含整数和小数)的加减乘除,运算功能数据输入及运算结果显示与平时使用计算机相同。用8279接口实现,4*5键盘及8位LED灯显示。20个键包括09共10个数字键,+,共4个运算键,键,小数点键以及清零键,剩余3个键可以自由发挥。系统复位后,应在最右边LED
2、上显示0。2 .系统总体设计方案规划与选定由于本学期学习了C51单片机的课程,此次的单片机选择了AT89C51,同样因为前段时间的实验使用过LED,所以这次显示屏幕还是选择了LED的显示屏,方便操作和使用。接口部分课程规定要用8279,其功能十分强大,读取键盘等都十分便利,利于LED灯和键盘的扩展,其中还使用了74HC138,74LS373配合电路的实现和连接。3 .硬件设计AT89C51通过8279扩展键盘和LED灯,其中PO口作为单片机芯片与8279传递命令,状态,数据的端口,P2口通过P2.0的状态来区分8279是状态字传送还是数据传送。INTO与8279的IRQ连接,当有键按下时会产生
3、一个中断,从而执行中断程序。8279中的SL0,SLbSL2产用编码模式,通过一个74H的38可以控制8条线,其中4条线分别和键盘行线相连接,作为扫描线。同时8279中的RL04作为键盘的列线,当键盘上有键按下时,可以通过扫描值和返回值得到键的准确位置,从而根据位置执行不同的函数。8279的OUTA,OUTB共8个端口通过一个74LS373与LED相连,作为LED的数据线,而8个LED灯的片选端由8279的SL0,SLl,SL2控制。(详细电路图见附录一)4 .软件设计4.1主程序流程图4.4数字转换流程图5 .调试电路图调试:将程序放入单片机后,在实际运行的时候发现显示屏上出现了相同的乱码,
4、按下键盘不能改变显示。在检查了一遍连线后,我们对器件也进行了一次检查,发现我们在器材选择时选择了共阳极的LED灯,于是我们上网查了共阴极LED的编号并改了过来。但在运行时发现还是无法正常显示,我们决定一步一步执行来找到问题所在。我们在按下开关时,观察开关两端的电位变化发现无论开关按下与否,开关右侧始终显示高电平,导致键盘返回值一直是零而无法产生中断。我们尝试将电阻去掉后发现键盘的电位变化正常了。我们再次运行程序,发现键盘可以引起显示的变化,但是显示的全部都是乱码,与我们设想的不一样。我们首先检查了一遍键码表,发现没有问题后我们再次检查了连线,看各个端口的连接是否有问题。通过反登检查和8279功
5、能键的比对,我们发现OUTA,OUTB这两个口在作为输出口的时候是OUTA作为高4位的,我们连错了位置,结果导致显示结果出现了很大的偏差。电路图是修改程序的基础,只有在电路图正确的基础上我们才能准确的判断程序的正确性。经过多次的调试之后,电路图终于可以正常工作了。程序调试:整个程序比较长,因此我们将整个程序分成4个部分来编写和分析,包括键盘读取程序,显示程序,数值转化程序以及主程序和中断程序等连接程序。首先是对主程序和中断程序的检查,主要是状态字的书写时候正确,有没有正确清零LED灯:这部分的问题比较少,基本没有浪费太多时间。键盘读取程序:键盘读取程序的编写比较麻烦,需要考虑数字键和功能键的区
6、别。在实际运行过程中,当我们在按下功能键后发现不能对先前输入的数清除,当有数字键按下后会跟在原先的数字后显示出来。这应该是属于功能键部分的问题,我们通过检查发现我们在功能键部分忘了给它赋值。解决这个问题后我们又发现当我们按下清零键后,再按小数时小数位数会发生叠加的现象,我们不得不再次检查清零键部分,反复比对之后发现我们在清零之后没有对记录小数位数的变量清零,导致小数位数山错。在键盘读取程序中,我们还需要对输入的各个数字转化为能运算的数值,这个我们同样是通过一个小数点标志位来判断,对其进行不同的操作,达到运算的要求。其中运算同样是在这里完成,在完成运算后将结果作为返回值。显不程序:显示程序部分程
7、序比较短,主要是对有无负数,有没有无效零的判断。通过负数标志位来判断负数,通过从后向前循环查询的方式将数组中的无效零都清除,并改变数值的显示长度。运行时我们发现一旦出现了负号,我们在按下清零键之后发现不能将负号给清除。我们首先尝试了清空FlFo和显示RAM的操作,发现并没有能解决这一问题,后来我们又检查了一遍清零程序,发现我们漏掉了负号标志位的赋值。因为这是后来加上的功能,导致遗漏了这样一个小问题,让我们寻找了很长时间。数值转化程序:这部分是十分重要的一部分,需要将计算得出的结果转化成一个一个的数字才能实现LED的显示。数值转化过程我们用的大体思路是将结果都转化成小数,然后乘以10取整就能得到
8、一个一个数字了。这一部分其实并不是很难,但最关键的是在于小数位数的判断上。我们设计的小数位数标志位pointx和pointy来记录数字的小数位数,然后再根据它们所做的运算来确定小数位数,例如乘法的最大小数位数是POintX+pointy(若有无效零将在显示部分去除),而除法我们直接默认小数位数为8以提高准确性。在经过转化时会做出一定的调整,并在整数部分最后一个数加上小数点。这块内容给我们带来了很大的问题,让我们花费了很长的时间。主要问题还是处在小数位数的问题上,一开始当我们按下一个小数后,第二个数默认的就是和前一个数的小数位数相同,但这不是我们想要的结果,经过分析我们觉得可能还是小数标志位的问
9、题。在对其检查时发现我们在按下第二个数时没有考虑到前一个己经对标志位赋值因此影响了后一个数的输入,我们在其后加入了一个标志位清零语句,顺利解决了这个问题。但随之而来的问题是我们发现最后计算的结果总是和两个位数之和相同,虽然还是位数的问题但是这次不是标志位的问题,而是出在了函数参数的问题上,我们在定义那个参数时使用的不是全局变量导致前面程序执行中对其的赋值不能在这个函数内使用,结果每次都执行最开始的语句而不能执行下面的判断语句。重新定义之后这一问题也得到了很好的解决。这一部分的程序我们经过了多次的调整,修改了很多,终于能够实现基本的操作和数字的正常显示。6 .新增功能及实现方法这次因为时间的原因
10、,在功能扩展上做的并不多,主要是扩展了一个求和函数,主要实现对输入数字取整之后,从1加到这个数字为止的一个函数,另外则是平方函数和开方函数。求和函数先通过取整确保函数可加,然后利用一个简单的循环求的最终的答案。而另外两个函数则是直接调用的库函数,方便计算而已。程序的可扩展性较好,想添加新的功能只需要在功能键码表中增加相应的键码,在判断语句中增加相应的选项就可以了。7 .小结与体会这次课程设计对我们来说是一个不小的挑战,连接电路图,查找资料更加深入的学习8279的功能,重新学习C语言的知识。这次课程设计从开始连接到最终成功前后经历了一个多星期.在整个设计过程中,我们都跑到图书馆借书来学习,在网上
11、找资料学习,在整个课程设计的过程中学到了许多没学到的知识。在最初的设计中,发挥“三个臭皮匠,顶个诸葛亮”的作用,不懂的地方就请教同学。而在程序编写中,我们思路并不是很清晰,在这样的情况下编写的程序很难实现我们所需要的功能,反而在静下心来理清思路之后反而能更快的达到目的。在编写时往往一个很细小的错误就能让我们在那埋头苦思很长时间,原本只是一个很简单的问题可能就因为粗心造成了时间的浪费。这也让我们明白来/在编程时定要细心,同时也定要能静下心来,对于程序出现的错误要耐心的逐个解决,坚持不懈,不轻易放弃。这次编程,我体会到了条理的重要性,理解了耐心的作用,也打打提高了我的编程能力。总之,此次课设使我的
12、能力得到了全方位的提高,使得我的操作能力和专业技能都有了很大的提高。8 .参考文献单片机原理及应用张红润孙悦张亚凡编著单片机实用技术刘高主编崔华蔡炎光编著80C51单片机原理,开发与应用实例于晓东主编附录一电路图吴博秦柏附录二程序清单狄海延编著*include4include*includeSdefineUCharunsignedcharMefineulongunsignedlongWdefineadrlXBYTEOx7fffdefineadr2XBYTE0x7effchartabflOl=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f)LE
13、D显示数组ucharxianshi8=0),b;XianShi是结果存放的数组,b表示结果的小数最大位数floatx=0,y=0z=0c=l:ucharflagl=0flag2=O*flag3三0h.cflagl小数点标志位,flag2运算符标志位,flag3等号标志位,h,w是运算符选择位ucharflag4=l:/flag4负数标志位Uchurpoinlx=O,POinty=0;/POintX表示第一个数字的小数位数,POinty表示第二个数字的小数位数uchartranslate(fIoata,ucharh):将结果转化为可在LED上显示的编码函数voiddir(uchar*datap,
14、uchurweishu);将结果输出到LED上的函数floatkeyscan(ucharkey);读取键盘按键的函数voidmainOucharkcy=0xff,m=0:adrl=0xdl;清零操作,设置参数whiled)ACC=adrl:if(AC=O)break;等待清零操作完成)adrl=0x2a;adrl=0x10;adrl=0x90:adr2=0xbf:EA=1;开中断EXO=I:ITO=I;WhiIQ(1);等待中断)intOinterrupt0(ucharkey=0xff,weishu;floata=0:adrl=OX40;读RAM命令key=adr2:a=keyscan(key
15、);WeiShU=IranSIaIe(a,w);dir(xianshi,weish):floatkeyscan(ucharkey)(uchari,a=99;floatn=0;uchartab110=0xd8,OxdO,Oxd1,0xd2,0xc8,0xc9,Oxca,OxcO,Oxc1,0xc2);数字键码表uchartab2110=(0xd9.0xda.0xdb,0xcb,0xcc,0xd3,0xd4.0xdc.0xc3.0xc4:功能键键码表for(i=0;iIO;i+)查表是否有功能键按下if(key=tab2i)a=i:switch(a)case0:小数点flagl=1:if(flag
16、2=0)n=x;elsen=y;break:case1:平方z=x*x;W=5;poinlx=2*poinlx;flag2=l;break;case2:/清零c=l;pointx=0:pointy=0;break;case3:力Pflag1=0;flag2=l:c=l;h=3;W=3;break;case4:减号flag1=0:flag2=l:c=l:h=4;w=4;break;case5:乘号flag1=0;flag2=l:c=l:h=5;w=5:break;case6:/除号flag1=0:flag2=l:c=l;h=6;r=6:break:case7:等号flag1=0:flag2=0:
17、flag3=l;switch(h)case3:z=x+y:break;case4:z=x-y:if(z0:i-)z=z+i;flag1=0;pointx=0;flag2=l;break:for(i=0;i10;i+)查表是否为数字if(flag2=0)if(key=tabli)(if(fIagl=O)(x=x*10+i:else(c=c*O.1;x=x+i*c:pointx+n=x;获得第一个数的数值break:)elseif(flag2=l)(if(key=tabli)(if(fIagl=O)(y=y*l+i;)else(c=c*0.1;y=y+i*C;pointy+;n=y;获得第二个数的
18、数值break:)return(n);uchartranslate(floata.ucharW)ucharf=0:U鼠fM加=1)/按完等号后对末尾的无效零清除uchare;e=al;if(e=0)(xianshif=0x3f:f=l;)b=poinlx;/确定小数的位数if(flag2=l)b=pointy;if(flag3=l)(if(w=311w=411w=5)(b=pointx+pointy;if(w=6)b=8;r=0;if(a=l;i+)a=a10;b=b+i;for(m=0f0.7)xianshif-l=tabe+l;return(f);)voiddir(uchardatap,ucharweishu)(uchar*s:uchari:adrI=Oxdl;adr1=0x90;if(flag4-l)adr2=0x40:s=p+weishu-l;while(*s=0x3f)weishu-:s=p+weishu-1:)for(i=Ojiweishu;i+)显示结果(adr2=*p;P+: