电子计算器课程设计报告.doc
单片机原理与应用课程设计报告书 课题名称:电子计算器*姓名:*学号:*学院:*专业:*方向:*指导教师: 2014年5月30日 目录设计要求3设计过程3一、系统总体设计方案规划与选定3二、硬件设计3 1、硬件组成3 2、硬件连接6三、软件设计7四、调试7 1、软件调试步骤7 2、具体调试过程8五、新增功能及实现方法8六、小结与体会9七、参考文献10八、附录(程序、电路图)10 1、附录一 程序10 2、附录二 连接图20 设计要求: 1.设计一个电子计算器,实现两个4位数(包括整数和小数)的加、减、乘、除运算功能。 2.要求数据的输入及运算结果的显示与我们平时使用的计数器相同; 3.采用8279接口4*6键盘及8位LED显示器。 4.可以用汇编语言或是c语言 5.鼓励创新,增添附加功能一、系统总体设计方案规划与选定 1、8279的功能是:对键盘进行管理控制,自动扫描键盘;对LED显示器进行控制、对显示数据、显示方式进行管理。 8279芯片对键盘进行扫描,当有按键按下时,数据被写入FIFO,产生中断,数据送单片机进行运算,运算结果回馈8279,8279控制数据显示到LED数码管。 2、(1)初始化8279及清零:选择键盘和显示方式,根据外接的CLK频率选定定标值,使内部时钟为100kHz,选择写显示RAM方式,选择读FIFO RAM方式。 (2)键盘程序:当有键被按下时,8279通过粗扫描感知到,然后通过细扫描确定被按下的键码,然后产生中断。 (3)显示程序:只需将字形码输出到数据口,8279即会按规定的方式写入显示RAM,并通过动态扫描进行动态显示。二、硬件设计1、硬件组成 1、单片机采用89C51,本次课设用到的管脚及其功能解析如下 Vcc:接+5V电源Vss:接地端ALE:与8279的CLK引脚相连,使8279和系统时钟同步P0-P7口:输入、输出口, 作地址、数据总线2、8279 8279是一款由+5V电源供电的可编程键盘显示接口芯片。RD、WR、CS分别与单片机的对应接口相连,AD0.7与单片机的P0-P7相连,RL0.7接键盘的列,OUT_A0-OUT_A3及OUT_B0OUT_B3是输出,接八位数码管的段选。其功能是:对键盘进行管理控制;对LED显示器进行控制、对显示数据、显示方式进行管理3、74HC138译码器 A,B,C分别接8279的SL0SL2,Y0Y7连接锁存器后对键盘进行行扫描,并控制八位数码管的位选。4、74HC373锁存器 将译码结果锁存在Q端,使信号暂时不受D端信号的影响,将扫描信号由Q端送入键盘和显示器。5、键盘 选用4×6键盘,行线连接8279 SL端经译码输出信号进行行扫描,列线连接8279的SL端。有键被按下时,通过行列扫描,确定是哪个键被按下。6、八位共阴极LED数码管左侧八个接口连接段选,右端八个接口连接位选。2、硬件连接 将单片机的P0口连接到8279的AD端,8279的OUT_B和OUT_A通过一个74HC373接到LED显示器的段选。8279的CS端和51的P2.7相接;A0与P2.0相接;RD和WR分别与51单片机相接;IRQ通过一个非门与51的INT1相接以产生外部中断;CLK与51的ALE相接以采用相同的时钟频率。RES隔电容接高电平,隔电阻接地。74HC138的E1接高电平,E2和E3接地。74HC373的LE接高电平,OE接地。键盘由4*6的开关阵组成,显示采用8位共阴极LED显示器,并都采用74HC373来提高驱动能力。将8279的扫描信号输出端通过三八译码器分别接到显示器的片选线和按键矩阵的每一行上。按键矩阵的每一列都连接到8279的RL输入端。三、软件设计 (1) 初始化8279:选择键盘和显示方式,键盘采用中断方式,对单片机开中断。根据外接的CLK频率选定定标值,使内部时钟为100kHz,选择写显示RAM方式,选择读FIFO RAM方式,并通过控制口向8279发送读键码指令。 (2) 结果显示:只需将字形码输出到数据口,8279即会按规定的方式写入显示RAM,并通过动态扫描进行动态显示到八位LED数码管。 整数部分:根据整数的位数,把待显示数除以10的倍数并取整,即得到每一位的值,然后查出每一位的字形码,依次写显示RAM即可在LED上显示得数。 小数部分:根据小数的位数,把待显示数除以0.1的倍数并取整即得到每一位的小数值,然后查出每一位的字形码,依次写显示RAM即可在LED上显示得数。(小数部分默认显示7位,然后通过从后往前查询最后一位是否是0,然后将末尾的0删掉,只显示非0部分) (3) 键盘程序:采用中断方式,当有键按下时,产生中断,在中断服务中读取按键数据,经过查键功能表,即可查得此键功能.如果按下的是数字键,会将此数字存储到一个数组中,同时将这个数字显示出来。如果按下的是运算符键,将把此运算符记下并将运算符前的数求出来,然后清除显示。如果按下等号键,会将运算符后面的数求出来并且根据运算符将运算结果算出来并显示出来。如果按下清零键,会将数字数组、显示、符号位等等都清零,即最右端显示0。四、调试一软件调试步骤: 1、新建工程:打开Keil软件,在Project菜单中选择New Project命令,建立一个新项目,然后存盘并输入工程文件名(不用写文件格式)。2、新建文件:新建文件,输入源程序代码,保存文件并令文件格式为.c3、把源文件添加到工程中:鼠标右键选中Source Group 1,然后添加文件到工程中,选择要添加的文件(即刚才的.c文件)4、设置对象选项:点击“Options for Target”,设置Output、Target、Debug选项5、编译:对项目文件进行编译。若出现errors、warnings时,按照指示,检查出错原因。6、用Proteus仿真软件画出电路图,点击AT89C51,添加.hex文件,点击开始进行仿真。7.对仿真的计算器进行操作,选择典型计算方式及典型数据进行计算,验证显示结果是不是自己的设计初衷。二、具体调试过程 由于第一次接触Keil和Proteus,感觉生疏异常,于是,上网百度找教程,最后终于弄清了Keil和Proteus的使用步骤。 在51里烧进程序后,一经运行,八位数码管就显示8个8,经过多番尝试及请教高人,最后在仔细研究电路图后,终于发现了问题所在,原来是引出8279的一根粗线没有贴标签。贴上标签后,立马一切正常了。五、新增功能及实现方法1、开平方运算:X(1/2)实现方法:输入一个数后,内部程序会进行求数运算,并显示该数,按下该键后, 由自带函数sqrt求得开方,按下等号后显示计算结果。 2、取倒数运算:X(-1)按下第一个数后,将其值算出并显示,按下改键后,求1/X运算,并将结果显示。3、清除键:Clear按下改键后,将执行清除命令。4、求阶乘:!执输入一个整数X后,按下该键,会执行X*(X1)*(X2)*(X3)*1运算,并将结果显示。5、求平方:X2按下一个数字X后,按下改键,便会执行X*X运算,按下等号后,将结果显示。6、求立平:X3按下一个数字X后,按下改键,便会执行X*X*X运算,按下等号后,会将结果显示。7、求N次方:XN按下一个数字X后,按下该键,再按下数字N,便会执行一个循环命令,求出XN,并显示。六、小结与体会 本次课程设计的要求是设计一个电子计算器,实现两个4位数(包括整数和小数)的加、减、乘、除运算功能。刚看到设计题目及要求时,顿觉非常困惑,感觉这要求超出了我的能力范围、无从下手。但是,随着翻看的有关单片机的教材及课程设计实例的增加以及跟同组及其他组同学多次的探讨研究,慢慢地,感觉逐渐对8279及51的各个接口及中断有了大体的概念,并且,逐渐地,课设的思路不知不觉间在大脑中慢慢形成。 当课设真正进行的时候,豁然发现,头脑中的念相与实际能够做出来的差距是何等的大。在设计过程中,遇到很多的困难,如Keil及Proteus软件的安装,以前学过UG,感觉UG软件很难安装,没想到,Proteus安装起来也是很不简单的,再比如程序的调试,辛辛苦苦写的程序,编译时显示大量的errors、warnings确实是一件极其痛苦的事情,但是历经审查、修改,最后程序完全正确了,烧入单片机后,可以按照要求进行运行了,那种快乐也是无法用三言两语形容的。 在本次课程设计中,控制电路选取AT89C51单片机,同时选取能够对键盘和LED实现控制和管理的8279芯片,它能自动扫描行列值,控制LED的显示,使得控制便利化,可通过软件实现实时控制,大大提高CPU的工作效率。键盘方面使用4×6键盘,分别对不同的键赋予功能,而显示器采用动态显示。由于感觉本软件用汇编语言会比较困难,因此采用C语言编程,其中由于编程不熟练遇到了很多新的难题,通过查找C语言课本复习了C语言的语法,把困难一一解决了(感觉自己的C语言水平又上升了数个台阶)。 通过这次课设,我认识到只有书本知识是万万不够的,我们还要多动手,多实际操作,让知识从实践中来,到实践中去。通过实践,不仅可以检验自己所学、所理解的知识是不是正确的,是不是可以带动生产力进步的,而且可以加深对知识的掌握,进而可以为学好新知识打下良好基础,更好地去学习新知识。 通过这次课程设计,我更加认识到合作的重要性,自己解决不了的问题,通过与同学探讨,往往可以轻而易举地把问题解决,毕竟,群众的力量是无穷的。 七、参考文献1、单片机原理、接口及应用(第二版) 肖看 李群芳 编著2、单片微型计算机原理及应用 张毅坤 西电3、Keil Cx51 V7.0单片机高级语言编程与uVision2应用技术 徐爱钧 电子工业出版社4、80C51单片机原理与应用技术 吴炳胜等编著八、附录(程序、电路图)附录一 程序 #include<reg51.h>#include<math.h>#include<.absacch>#define uint unsigned int#define unch unsigned char#define D8279 XBYTE0x7EFF#define CTRL8279 XBYTE0x7FFFuint a10=0; /参与计算的数uint jieshou; /8279返回值unch i; /数组的第i位数uint led10=0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F;unch geshu; /输入的数字和符号的个数unch shuru; /表示输入的数字unch shuzigeshu; /输入的数字的个数unch zhengshugeshu;/小数计算,整数的位数float shuq; / 参与计算的第一个数float shuw;/参与计算的第二个数unch jisuanfangshi; /要使用的计算方式unch xiaoshudian; /是否使用小数点unch key; /表示按键所代表的意义unch Q; /表示小数点前的led显示的数void clear() /总清除CTRL8279=0xd1; jieshou=CTRL8279; jieshou&=0x80;/读出8279的状态寄存器中显示的状态,读DU位 while(jieshou=0x80)/确认清除完毕 jieshou=CTRL8279; jieshou&=0x80; void chushihua() /初始化 CTRL8279=0x90; /写显示RAM,地址自动加一/ CTRL8279=0x34;/定标/ CTRL8279=0x10;/8个字符显示右边输入,编码扫描,键盘锁定/void shuzuqingchu()for(i=0;i<10;i+) ai=0;i=0;void yunsuanqingchu() xiaoshudian=0; zhengshugeshu=0; shuzuqingchu();void scan() /清零 geshu=0;/记录数字个数的变量清0shuzigeshu=0;/记录数字和符号个数的变量清0 shuw=0;shuq=0;shuru=0 ; zhengshugeshu=0;jisuanfangshi=0;xiaoshudian=0; clear(); D8279=0xbf;void jisuan1() uint j;float middle=0.1; shuq=0; if(xiaoshudian=0) zhengshugeshu=shuzigeshu; for(j=0;j<zhengshugeshu;j+) shuq=aj+shuq*10;if(xiaoshudian=1) shuq=1.0*shuq;for(j=zhengshugeshu;j<shuzigeshu;j+)shuq=shuq+aj*middle;middle=middle*0.1;geshu=0;shuzigeshu=0;void jisuan2() unch j;float middle=0.1; shuw=0; if(xiaoshudian=0) zhengshugeshu=shuzigeshu; for(j=0;j<zhengshugeshu;j+) shuw=aj+shuw*10;if(xiaoshudian=1) shuw=1.0*shuw;for(j=zhengshugeshu;j<shuzigeshu;j+) shuw=shuw+aj*middle;middle=middle*0.1;geshu=0; shuzigeshu=0;void suanshufangshi() float m ; chushihua(); shuq=shuq*1.0 ; shuw=shuw*1.0; if(jisuanfangshi=1) shuq=shuq+shuw; if(jisuanfangshi=2) shuq=shuq-shuw; if(jisuanfangshi=3) shuq=shuq*shuw; if(jisuanfangshi=4) shuq=1.0*shuq/shuw; if(jisuanfangshi=5) m=shuq; shuq=1; for(;m>0;m-) shuq=shuq*m; if(jisuanfangshi=6) shuq=shuq*shuq; if(jisuanfangshi=7) for(;shuw>0;shuw-) shuq=shuq*shuq; if(jisuanfangshi=8) shuq=1/shuq;void xianshijieguo(float xianshishu)uint j; /循环次数计量uint n; /整数个数uint m;/整数输出float y; /复杂小数的整数部分uint k;/复杂小数的循环次数float r; /复杂小数的小数部分unch z9; /小数输出uint zhongjianliang; chushihua(); if(xianshishu=(long)xianshishu) /整数的显示 n=(long)(log10(xianshishu)+1; for(j=0;j<n;j+) m=xianshishu; xianshishu=(long)(xianshishu/10);m=m-xianshishu*10; zj=m; for(j=0;j<n;j+) aj=zn-j-1; for(j=0;j<n;j+) D8279=ledaj; j=0; m=0; for(j=0;j<n;j+) zj=0; aj=0; else /计算小数 if (long)xianshishu=0) /计算简单小数 D8279=0xbf; for(j=0;j<6;j+) m=(long)(xianshishu*10); xianshishu=xianshishu*10-m; D8279=ledm; m=0; j=0; else /计算复杂小数 y=(long)(xianshishu); n=(long)(log10(xianshishu)+1 ; for(j=0;j<n;j+) m=y; y=(long)(y/10); m=m-y*10; zj=m; for(j=0;j<n;j+) aj=zn-j-1; for(j=0;j<n;j+) if(j<n-1) D8279=ledaj; if(j=n-1) D8279=ledaj|0x80; r=xianshishu-(long)xianshishu; for(k=0;k<(8-n);k+) r=r*10; zk=(long)r; r=r-zk; while(zk=0) k-; zhongjianliang=k+1; for(k=0;k<zhongjianliang;k+) D8279=ledzk; y=0; n=0; k=0; i=0; for(k=0;k<8;k+) zk=0; int1( ) interrupt 2 /计算器矩阵键盘扫描中断函数,从左到右,从上到下 if(geshu=0) /没输入数字时,进行初始化 chushihua(); CTRL8279=0x40;/发送读FIFO/RAM命令/ shuru=D8279; switch(shuru) case 0x04: key=0; ai=0;i+;geshu+;shuzigeshu+;D8279=0x3f;break; case 0x0c: key=1; ai=1;i+;geshu+;shuzigeshu+;D8279=0x06;break; case 0x0b:key=2; ai=2;i+;geshu+;shuzigeshu+;D8279=0x5b;break; case 0x0a:key=3; ai=3;i+;geshu+;shuzigeshu+;D8279=0x4f;break;case 0x14:key=4; ai=4;i+;geshu+;shuzigeshu+;D8279=0x66;break;case 0x13:key=5; ai=5;i+;geshu+;shuzigeshu+;D8279=0x6d;break;case 0x12:key=6; ai=6;i+;geshu+;shuzigeshu+;D8279=0x7d;break;case 0x1c:key=7; ai=7;i+;geshu+;shuzigeshu+;D8279=0x07;break;case 0x1b:key=8; ai=8;i+;geshu+;shuzigeshu+;D8279=0x7f;break;case 0x1a:key=9; ai=9;i+;geshu+;shuzigeshu+;D8279=0x6f;break;case 0x03: key='.' geshu+; zhengshugeshu=shuzigeshu; CTRL8279=0x60+zhengshugeshu-1; Q=D8279; CTRL8279=0x80+zhengshugeshu-1; D8279=Q|0x80; xiaoshudian=1; CTRL8279=0x90+zhengshugeshu; break; case 0x02: key='=' jisuan2(); suanshufangshi(); xianshijieguo(shuq); break; case 0x19: key='+'jisuanfangshi=1;jisuan1();yunsuanqingchu();clear();chushihua(); break; case 0x11: key='-' jisuanfangshi=2;jisuan1();yunsuanqingchu();clear();chushihua(); break; case 0x09: key='*' jisuanfangshi=3;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x01: key='/' ; jisuanfangshi=4;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x18: key='!' jisuanfangshi=5;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x10: key='p' ; jisuanfangshi=6;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x08: key='' jisuanfangshi=7;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x00: key='d' jisuanfangshi=8;jisuan1();yunsuanqingchu();clear();chushihua(); break;case 0x1d: clear(); chushihua(); shuzuqingchu(); yunsuanqingchu(); scan(); break;case 0x15: break;case 0x0d: break;case 0x05: break; void main()clear(); /总清除chushihua(); /8279初始化scan(); IT1=0; /设置INT1中断方式为低电平EX1=1; /允许INT1中断EA=1; /CPU允许中断while(1); /等待中断 附录二 硬件连接图