基于单片机的简易计算器设计
一、设计任务和性能指标
1.1设计任务
利用单片机及外围接口电路(键盘接口和显示接口电路)设计制作一个计算器,用四位一体数码管显示计算数值及结果。要求用Protel 画出系统的电路原理图(要求以最少组件,实现系统设计所要求的功能),绘出程序流程图,并给出程序清单(要 求思路清晰,尽量简洁,主程序和子程序分开,使程序有较强的可读性)。
1.2性能指标
1加法:能够计算四位以内的数的加法。
2减法:能计算四位数以内的减法。
3乘法:能够计算两位数以内的乘法。
4除法:能够计算四位数的乘法
5有清零功能,能随时对运算结果和数字输入进行清零。
二、系统设计方案
按照系统设计的功能的要求,初步确定设计系统由单片机主控模块、四位一体数码管显示模块、键扫描接口电路共三个主要模块组成。主控芯片使用51系列AT89C51单片机,采用高性能的静态80C51设计,它由先进工艺制造,并带有非易失性Flash程序存储器。它是一种高性能、低功耗的8位COMS微处理芯片,市场应用最多。
键盘电路采用4*4矩阵键盘电路。
显示模块采用四位一体共阳极数码管和SN74LS244锁存芯片构成等器件构成。
三、硬件系统设计
1.单片机最小系统
单片机最小系统就是支持主芯片正常工作的最小电路部分,包括主控芯片、复位电路和晶振电路。
主控芯片选取STC89C51RC芯片,因其具有良好的性能及稳定性,价格便宜应用方便。
晶振选取11.0592MHz,晶振旁电容选取30pF。
采用按键复位电路,电阻分别选取100Ω和10K,电容选取10μF。
单片机最小系统硬件电路图如图(1)所示。
图(1) 单片机最小系统 2.键盘接口电路 计算器所需按键有: 数字键:’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’,’0’ 功能键:’+’, ’-‘, ’*’, ’/ ’ , ’ = ’, ’ C( 清零)’ 共计16个按键,采用4*4矩阵键盘,键盘的行和列之间都有公共端相连,四行采用端口P0.0~P0.3,四列采用端口P3.0~P3.3,通过8个端口的的高低电平完成对矩阵键盘的控制。通过对16个按键进行编码,从而得到键盘的口地址,对比P1口德扫描结果和各按键的地址,我们就可以得到是哪个键按下,从而完成键盘的功能。 3.数码管显示电路 采用4位一体的数码管对计算数据和结果进行显示,这里选取共阳数码管,利用NPN三极管对数码管进行驱动,为了节省I/O资源,采取动态显示的方法来显示计算数据及结果。 利用SN74LS244N锁存器来实现数码管的动态显示,P1口输出显示值,P2.0~P2.3为位选端口。通过锁存器对段选信号的锁存,最终得到对数码管输入数据的控制。 以下为数码显示电路的硬件电路图,左图为数码管驱动电路,右图为段选信号锁存电路。
四.软件设计部分 根据选题要求,系统编程如下所示: - #include "reg51.h"
- sbit P3_0=P3^0;
- sbit P3_1=P3^1;
- sbit P3_2=P3^2;
- sbit P3_3=P3^3;
- sbit P3_4=P3^4;
- sbit P3_5=P3^5;
- sbit P3_6=P3^6;
- sbit P3_7=P3^7;
- unsigned char sz[11],xs1[4],xs2[4],sj;
- int i,cs,bb,t1,t2,fh,s1,s2;
- void chushihua()
- {
- bb=1;
- xs1[0]=10;xs1[1]=10;xs1[2]=10;xs1[3]=10;
- xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
- t1=0;t2=0;s1=s2=0;
- fh=0;
- cs=1;
-
- }
- void xianshi(unsigned char xs[4])
- {
- int i,j;
- unsigned char zy;
- zy=0x08;
- for (i=0;i<4;i++)
- {
- P2=(0xff-zy);
- P1=sz[xs[i]];
- zy=(zy>>1);
- for (j=0;j<100;j++) ;
-
- }
- // for (i=0;i<100;i++);
- return;
- }
- unsigned char saomiao()
- {
- int i,j;
- unsigned char pp;
- for (i=0;i<1000;i++);
- P0=0xfe;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 7;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 8;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 9;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 11;}
- //==========1
- P0=0xfd;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 4;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 5;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 6;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 12;}
- //==========2
- P0=0xfb;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 1;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 2;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 3;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 13;}
- //==========3
- P0=0xf7;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 16;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 0;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 15;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 14;}
- //===========4
- return 10;
- }
- void chuli(unsigned char x)
- {
- int i;
- if (x==16)
- {
- cs=0;
- return ;
- }
- if (x>=0 && x<10)
- {
- if (bb==1)
- {
- if (s1= =4) {cs=0;return ;}
- else
- {
- for (i=3;i>0;i--)
- xs1[i]=xs1[i-1];
- xs1[0]=x;
- s1++;
- t1=t1*10+x;
- }
- }
- if (bb==2)
- {
- if (s2==4) {cs=0;return ;}
- else
- {
- for (i=3;i>0;i--)
- xs2[i]=xs2[i-1];
- xs2[0]=x;
- s2++;
- t2=t2*10+x;
- }
- }
- }
- if (x>10)
- {
- if (bb==1) {fh=x;bb=2;return;}
- if (bb==2)
- {
- if (fh==11) t1=t1/t2;
- if (fh==12) t1=t1*t2;
- if (fh==13) t1=t1-t2;
- if (fh==14) t1=t1+t2;
- if (t1>=10000) {cs=0;return;}
- else
- {
- if (t1>=0 && t1<10) {xs1[0]=t1;xs1[1]=10;xs1[2]=10;xs1[3]=10;}
- if (t1>=10 && t1<100) {xs1[0]=t1%10;xs1[1]=t1/10;xs1[2]=10;xs1[3]=10;}
- if (t1>=100 && t1<1000) {xs1[0]=t1%10;xs1[1]=(t1-(t1/100)*100)/10;xs1[2]=t1/100;xs1[3]=10;}
- if (t1>=1000 && t1<10000) {xs1[0]=t1%10;xs1[1]=t1%100/10;xs1[2]=(t1-(t1/1000)*1000)/100;xs1[3]=t1/1000;}
- bb=2;
- s2=0;
- t2=0;
- xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
- fh=x;
- }
- }
- }
- }
- void main()
- {
- sz[0]=0xfc;
- sz[1]=0x60;
- sz[2]=0xda;
- sz[3]=0xf2;
- sz[4]=0x66;
- sz[5]=0xb6;
- sz[6]=0xbe;
- sz[7]=0xe0;
- sz[8]=0xfe;
- sz[9]=0xf6;
- sz[10]=0x00;
- cs=0;
-
- for (;;)
- {
- if (cs==0) chushihua();
- if (cs==1) sj=saomiao();
- if (cs==1 && sj!=10) chuli(sj);
- if (cs==1 &&(bb==1 || bb==2 && s2==0)) xianshi(xs1);
- if (cs==1 &&(bb==2 && s2!=0)) xianshi(xs2);
-
- }
- }
- 软件设计好后,在KEIL上面进行仿真,把仿真得到的文件下载到Proteus里面进行仿真,得到Proteus仿真电路图如下所示:
-
- 图(2) 计算器Proteus仿真电路图
- 五.硬件电路焊接及调试
- 根据电路图纸,焊接好硬件电路,把程序下载到单片机芯片,接通好电源,进行调试。在焊接好器件后,先不要将芯片插在芯片座上,要先验证先板上电源是否好用,有无短路等。接上USB电源,用万用表测量个芯片座对应电源和地之间的电压值,观察电压值是否正常。一切正常后方可将芯片插入芯片座,以继续测试其他功能。
- 将芯片插上后,对各个模块进行调试,按键是否工作正常,数码管是否显示正常等。编写相关部分的测试程序对其进行测试。
- 各部分硬件检测无误后,下载程序进行整体调试,一切正常后,结束调试过程。
- 用所设计的单片机进行数字计算,显示结果与任务要求一致,焊接电路符合要求。
- 六.课程设计心得
- 两周的时间,终于把单片机课程设计搞完了。整个体会还是比较多的。首先是题目的选择,各方面的原因,自己还是想选个简单点的题目,不过最后选来选去,还是选择了计算器。由于自己对单片机编程还不是很熟悉,结果在设计的时候遇到了一系列问题,程序总是调试部处理,不过还好,最后在同学的帮助下终于把程序调试出来了,虽然程序设计实现的功能与老师要求的不尽相同,不过勉强还算可以。从这里我知道了基本知识的重要性。其实进行程序设计的时候主要是对各功能模块的把握。计算器里面最难的一部分是矩阵键盘的扫描和编码,那个费了很大力气。
- 另外一点就是硬件焊接调试部分。焊接的时候到时轻松,一个下午就焊接好了,然后是调试部分。调试花费的时间还是比较长的。不过有了上个学期数字电路焊接调试的经验,这次单片机调试还算是比较顺利。我也是从电路板的正负电源检测起,一步一步来,最终得到了想要的结果。调试的时候主要遇到了两个问题。一个是键盘总是没有反应,为了这个自己调试了很久,前前后后把电路板检查了几次,最后才发现是键盘本身的问题,和同学们换了个好键盘才行。另一个问题是总是显示不出来1、4、7这三个数字。检测来检测去,发现来是在测试最小系统时在一个位选端接了高电平,对位选信号产生了影响。当把那个高电平去掉后,终于得到了正确的结果。
- 总的来说这次课程设计达到了完成了基本任务,达到了基本要求。通过亲身对程序设计和电路焊接调试的体会,自己对单片机有了进一步的了解,单片机编程能力也得到了提高。电路板的焊接与调试,使自己电路调试的方法和思想进一步加强了。这次单片机课程设计应该说是比较成功的。
- 参考文献:
- 【1】徐维祥、刘旭敏:,《单片微型机原理及应用》,大连理工大学出版社,1996年。
- 【2】李光飞、楼然苗、胡佳文、谢象佐.,《单片机课程设计与实例指导.》, 北京航空航天大学出版社,2004年。
- 【3】余永权,《89系列FLASH单片机原理及应用.》,电子工业出版社,2002。
- 【4】杨恢先、黄辉先,《单片机原理及应用》,人民邮电出版社,2006年。
- 【5】常敏、王涵、范江波,《单片机应用程序开发与实践》,电子工业出版社,2009年。
- #include //头文件
- #define uint unsigned int //
- #define uchar unsigned char
-
- sbit lcden=P2^3; //定义引脚
- sbit rs=P2^4;
- sbit rw=P2^0;
- sbit busy=P0^7;
-
- char i,j,temp,num,num_1;
- long a,b,c; //a,第一个数 b,第二个数 c,得数
- float a_c,b_c;
- uchar flag,fuhao;//flag表示是否有符号键按下,fuhao表征按下的是哪个符号
-
- uchar code table[]={
- 7,8,9,0,
- 4,5,6,0,
- 1,2,3,0,
- 0,0,0,0};
- uchar code table1[]={
- 7,8,9,0x2f-0x30,
- 4,5,6,0x2a-0x30,
- 1,2,3,0x2d-0x30,
- 0x01-0x30,0,0x3d-0x30,0x2b-0x30};
-
- void delay(uchar z) // 延迟函数
- {
- uchar y;
- for(z;z>0;z--)
- for(y=0;y<110;y++);
- }
-
- void check() // 判断忙或空闲
- {
- do{
- P0=0xFF;
- rs=0; //指令
- rw=1; //读
- lcden=0; //禁止读写
- delay(1); //等待,液晶显示器处理数据
- lcden=1; //允许读写
- }while(busy==1); //判断是否为空闲,1为忙,0为空闲
- }
- void write_com(uchar com) // 写指令函数
- {
- P0=com; //com指令付给P0口
- rs=0;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void write_date(uchar date) // 写数据函数
- {
- P0=date;
- rs=1;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void init() //初始化
- {
- num=-1;
- lcden=1; //使能信号为高电平
- write_com(0x38); //8位,2行
- write_com(0x0c); //显示开,光标关,不闪烁*/
- write_com(0x06); //增量方式不移位 显竟獗暌贫 柚?
- write_com(0x80); //检测忙信号
- write_com(0x01); //显示开,光标关,不闪烁
- num_1=0;
- i=0;
- j=0;
- a=0; //第一个参与运算的数
- b=0; //第二个参与运算的数
- c=0;
- flag=0; //flag表示是否有符号键按下,
- fuhao=0; // fuhao表征按下的是哪个符号
- }
- void keyscan() // 键盘扫描程序
- {
-
- P3=0xfe;
- if(P3!=0xfe)
- {
- delay(20); 延迟20ms
- if(P3!=0xfe)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=0;
- break;
- case 0xd0:num=1;
- break;
- case 0xb0:num=2;
- break;
- case 0x70:num=3;
- break;
- }
- }
- while(P3!=0xfe);
- if(num==0||num==1||num==2)//如果按下的是'7','8'或'9
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- }
- else//如果按下的是'/'
- {
- flag=1;
- fuhao=4;//4表示除号已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfd;
- if(P3!=0xfd)
- {
- delay(5);
- if(P3!=0xfd)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=4;
- break;
-
- case 0xd0:num=5;
- break;
-
- case 0xb0:num=6;
- break;
-
- case 0x70:num=7;
- break;
- }
- }
- while(P3!=0xfd);
- if(num==4||num==5||num==6&&num!=7)//如果按下的是'4','5'或'6'
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- }
- else//如果按下的是'/'
- {
- flag=1;
- fuhao=3;//3表示乘号已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfb;
- if(P3!=0xfb)
- {
- delay(5);
- if(P3!=0xfb)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=8;
- break;
-
- case 0xd0:num=9;
- break;
-
- case 0xb0:num=10;
- break;
-
- case 0x70:num=11;
- break;
- }
- }
- while(P3!=0xfb);
- if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- }
- else if(num==11)//如果按下的是'-'
- {
- flag=1;
- fuhao=2;//2表示减号已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xf7;
- if(P3!=0xf7)
- {
- delay(5);
- if(P3!=0xf7)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=12;
- break;
-
- case 0xd0:num=13;
- break;
-
- case 0xb0:num=14;
- break;
-
- case 0x70:num=15;
- break;
- }
- }
- while(P3!=0xf7);
- switch(num)
- {
- case 12:{write_com(0x01);a=0;b=0;flag=0;fuhao=0;}//按下的是"清零"
- break;
- case 13:{ //按下的是"0"
- if(flag==0)//没有按过符号键
- {
- a=a*10;
- write_date(0x30);
- P1=0;
- }
- else if(flag==1)//如果按过符号键
- {
- b=b*10;
- write_date(0x30);
- }
- }
- break;
- case 14:{j=1;
- if(fuhao==1){write_com(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处
- write_com(0x04); //设置从后住前写数据,每写完一个数据,光标后退一格
- c=a+b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d); //再写"="
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==2){write_com(0x80+0x4f);//光标前进至第二行最后一个显示处
- write_com(0x04); //设置从后住前写数据,每写完一个数据,光标后退一格(这个照理说顺序不对,可显示和上段一样)
- if(a-b>0)
- c=a-b;
- else
- c=b-a;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a-b<0)
- write_date(0x2d);
- write_date(0x3d); //再写"="
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==3){write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==4){write_com(0x80+0x4f);
- write_com(0x04);
- i=0;
- c=(long)(((float)a/b)*1000);
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- i++;
- if(i==3)
- write_date(0x2e);
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- }
- break;
- case 15:{write_date(0x30+table1[num]);flag=1;fuhao=1;}
- break;
- }
- }
- }
-
- main()
- {
- init();
- ………余下代码请下载附件………
-
复制代码
完整的课程设计报告(论文)下载:
单片机计算器课程设计报告.doc
(154 KB, 下载次数: 82)
|