摘要:计算器是我们生活中常用的工具,在我们生活中不可或缺。本次设计是设计一个算术型计算器,该计算器能够完成简单的四则运算,还可以实现连续运算。本次是以51单片机为运算核心,以LCD1602为显示的进行硬件上的设计,在软件上以Keil4进行软件编程,以Proteus进行仿真调试,设计出一个能够完成简单的四则运算,实现连续运算的小型算术型计算器。
正文:
一、设计概述
1. 课题意义
计算器有键盘部分、单片机、显示部分三部分组成,键盘部分主要完成输入功能;单片机主要完成数据处理功能,包括确定按键,完成运算,以及输出数据;显示器部分主要完成单片机输出的显示。基本掌握计算器的设计原理和LCD1602的显示原理,进而熟悉C51的编程和调试方法。
2. 系统功能
能够完成简单的四则运算,还可以实现连续运算的小型算术型计算器。
硬件设计上通过Proteus进行电路原理图和仿真运行图的设计,软件设计上以Keil4为基础进行软件编程,将编程生成的.hex文件放入在Proteus已画好的原理图中调试,观察设计结果,并对代码进行修改。
二、硬件设计
[size=9.0000pt] 图1 [size=9.0000pt]总原理图
1.按键设计
矩阵键盘的原理是见I/O口分为行线和列线,按键设置在跨接行线和列线的交点上,列线通过上拉电阻接正电源,进而形成基本的4x4行列式键盘。本次设计以矩阵键盘为基本的输入按键分别为1,2,3,+,4,5,6,-,7,8,9,x,0,CLR,=,/ 形成计算器对应的基本的数字键和功能键
显示设计
LCD1602是一种专门用来显示字母、数字、符号等的点阵型液晶模块,它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,因此它比较适合用在计算器的显示。
三、软件设计
1. 按键扫描
本次设计中在软件上使用了反转法进行按键的扫描,其过程为先让行输出全为0列输出全为1读取与按键相接的P1口的状态,读取按键的列值,然后让行输出全为1列输出全为0读取与按键相接的P1口的状态,读取按键的行值,根据行值和列值可知其键值。
[size=9.0000pt] 图4按键扫描流程图[size=9.0000pt]
2.显示设计
LCD1602是一个16字双行的显示模块,在使用LCD1602之前我们应该先对其进行初始化,其初始化的内容有光标设置、显示设置和清屏指令等。初始化完成后从其参考手册可知LCD1602中已经存储有基本字模数据,所以想要在LCD1602中显示字符,只需要对LCD1602写入该字符相对应的ASCII码即可显示出相应的字符。LCD1602的写入可分为写数据和写命令,当要写入数据时其对应的状态为RS=1,RW=0,E为下降沿,然后通过单片机I/O口写入相应的数据。当要写入命令时其对应的状态为RS=0,RW=0,E为下降沿,然后通过单片机I/O口写入相应的命令。
[size=9.0000pt]图5 LCD1602写指令图
3.键值处理
首先我们初始化液晶显示器,然后显示出第一个被按下的数,并且使光标右移,如果有第二个数按下,则据继续显示,以此类推,然后把所有显示出来的数换算成一个数,如果按下“+”号,则显示出“+”,并且同理显示出“+”号后面按下的数字,然后调用加子程序,运算出结果,如果按下的是“-”,则调用减子程序,如果按下“*”,则调用乘子程序,如果按下“/”,则调用除子程序。然后再调用显示结果子程序,显示出结果。
图6键值运算流程图
四、系统测试
1.加法测试
2.减法测试
3.乘法测试
4.除法测试
5.连续运算测试
五、结论
经过调试可知此次设计已经基本达到要求,该计算器能够完成简单的四则运算,还可以实现连续运算。但只能进行整数的运算,无法进行浮点型数据运算,运算的连续运行需要一个个数的连续运算,无法做到一次性连续运算。
七、附录
1.系统电路图
2.实物运行图
单片机源程序如下:
- /* 实现两个数的运算,每个数的位数至少可以八位 */
- #include<reg52.h>
- #include<math.h>
- typedef unsigned char uint8;
- typedef unsigned int uint16;
- #define GPIO_KEY P1
- sbit rw=P2^5;
- sbit rs=P2^6;
- sbit e=P2^7;
- sbit k1=P3^0;
- uint8 num='N'; //键值
- uint16 k0,k2,k3; // 数组位
- uint8 fuhao; //定义具体的那个符号,是加减还是乘除。
- uint8 flag,r; //定义符号键标志位,小数点标志位和继续运算标志位 这个是统称
- float a,b,c,zheng,xiao; //定义运算数据的第一个和第二个及等于的数变量
- uint8 shuzi1[5]={0},shuzi2[5]={0},shuzi3[4]={0};
- uint8 code dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x78-0x30, 0,0x2e-0x30,0x3d-0x30,0xfd-0x30 };//保存显示的数据 123+ 456- 789* 0.CLR /
- void delay(uint16 i)
- { uint16 x,y;
- for(x=0;x<i;x++)
- for(y=0;y<114;y++);
- }
- void lcdcommand(uint8 m) //写命令
- {
- delay(1);
- rs=0;
- rw=0;
- e=0;
- P0=m;
- e=1;
- delay(1);
- e=0;
- }
- void lcddata(uint8 dat) //写数据
- {
- delay(1);
- rs=1;
- rw=0;
- e=0;
- P0=dat;
- e=1;
- delay(1);
- e=0;
- rs=0;
- }
- void lcdcsh() //初始化
- {
- delay(5);
- lcdcommand(0x38); //功能设定 8位总线 两行 5X7点阵
- delay(5);
- lcdcommand(0x38);
- lcdcommand(0x38);
- lcdcommand(0x0c); // 开显示 无光标
- lcdcommand(0x06); //光标左移
- lcdcommand(0x01); // 清屏
- lcdcommand(0x80);//数据从左上开始
- num='N';
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;;
- k0=0;k2=0;k3=0;
- }
- void shuchu(float e) //在屏幕上显示数值e
- {
- char shuzu[10];
- long z;
- int x=0;
- float f;
-
- (long)z=e; //整数处理
- if(z==0)
- lcddata('0');
- while(z!=0)
- { shuzu[x]=z%10;
- z=z/10;
- x++;
- }
- for(x=x-1;x>=0;x--)
- lcddata(shuzu[x]+0x30);
- (long)z=e; //小数处理
- (float)f=e-z;
- if(f>0.000)
- { x=0;
- lcddata('.');
- z=f*1000;
- while(z!=0)
- { shuzu[x]=z%10;
- z=z/10;
- x++;
- }
- for(x=x-1;x>=0;x--)
- lcddata(shuzu[x]+0x30);
- }
- }
- void fuzhi() // 显示与向数组赋值
- {
-
- if(flag==0) //是否按下符号键
- {
- delay(50);
- if(dat1[num]=='.')
- r=1;
- if((r==0)&&(k0<5))
- {
- shuzi1[k0]=dat1[num];
- k0++;
- lcddata(0x30+dat1[num]);
- }
- else if((r==1)&&(k3<4))
- {
-
- shuzi3[k3]=dat1[num];
- k3++;
- lcddata(0x30+dat1[num]);
- }
- }
- r=0;
- if(flag==1) //是否按下符号键
- {
- delay(50);
- if(dat1[num]=='.')
- r=1;
- if((r==0)&&(k2<5))
- {
- shuzi2[k2]=dat1[num];
- k2++;
- lcddata(0x30+dat1[num]);
- }
- else if((r==1)&&(k3<4))
- {
-
- shuzi3[k3]=dat1[num];
- k3++;
- lcddata(0x30+dat1[num]);
- }
- }
- }
- void sz(uint8 s[8],int x) //数组转为数值
- {
- int i,j;
- zheng=0;
- xiao=0;
- i=0; //整数
- while(x>0)
- {
- zheng=zheng*10+s[i];
- i++;
- x--;
- }
- i=1; //小数
- j=k3;
- while(j>0)
- {
- xiao=xiao*10+s[i];
- i++;
- j--;
- }
-
- for(;k3>0;k3--)
- xiao=xiao/10;
- zheng=zheng+xiao;
- k0=k2=k3=0;
- }
- void KeyDown(void)
- {
- char L=0;
- GPIO_KEY=0x0f;
- if(GPIO_KEY!=0x0f)//读取按键是否按下
- {
- delay(10);//延时10ms进行消抖
- if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
- {
- //测试列
- GPIO_KEY=0X0F;
- switch(GPIO_KEY)
- {
- case(0X07): num=0;break;
- case(0X0b): num=1;break;
- case(0X0d): num=2;break;
- case(0X0e): num=3;break;
- }
- //测试行
- GPIO_KEY=0XF0;
- switch(GPIO_KEY)
- {
- case(0X70): num=num;break;
- case(0Xb0): num=num+4;break;
- case(0Xd0): num=num+8;break;
- case(0Xe0): num=num+12;break;
- }
- while((L<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
- {
- delay(10);
- L++;
- }
- }
- }
- }
- void banduan()
- {
- switch(fuhao)
- {
- case 0:
- sz(shuzi1,k0);
- a=zheng;
- lcdcommand(0x01);
- lcdcommand(0x40+0x80);
- shuchu(a);
- b=0;
- flag=0;
- fuhao=0; //全部清除为0
- zheng=0;
- xiao=0;
- break;
- case 1:
-
- lcdcommand(0x40+0x80);
- c=a+b;
- lcddata(0x3d); //显示等于号=
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除为0
- zheng=0;
- xiao=0;
- break;
- case 2:
- lcdcommand(0x40+0x80);
-
- if(a>b)
- { c=a-b;
- lcddata(0x3d); //显示等于号=
- }
- else if(a<b)
- {
- c=b-a;
- lcddata(0x3d); //显示等于号=
- lcddata(0x2d); //显示负号-
- }
- if(a==b)
- c=0;
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除为0
- zheng=0;
- xiao=0;
- break;
- case 3:
- lcdcommand(0x40+0x80);
- c=a*b;
- lcddata(0x3d); //显示等于号=
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除为0
- zheng=0;
- xiao=0;
- break;
- case 4:
- lcdcommand(0x40+0x80);
- c=a/b;
- lcddata(0x3d); //显示等号
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除为0
- zheng=0;
- xiao=0;
-
- break;
- }
-
- }
- void main()
- {
-
-
-
- lcdcsh();
- while(1)
- { num='N';
- KeyDown();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- }
- while(1)
- {
- num='N';
- KeyDown();
- if(num==0||num==1||num==2||num==4||num==5||num==6||num==8||num==9||num==10||num==12||num==16) //1-9-0-.
- fuzhi();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- break;
- }
- if(num==3||num==7||num==11||num==15)
- {
-
- flag=1;
- switch(num)
- { case 3: fuhao=1; break;
- case 7: fuhao=2; break;
- case 11: fuhao=3; break;
- case 15: fuhao=4; break;
- }
- sz(shuzi1,k0);
- c=zheng;
- loop: a=c;
- lcdcommand(0x01);
- lcdcommand(0x80);
- shuchu(a);
- lcddata(0x30+dat1[num]);
- break;
- }
- }
-
- while(1)
- {
- num='N';
- KeyDown();
- if(num==0||num==1||num==2||num==4||num==5||num==6||num==8||num==9||num==10||num==12) //1-9-0
- fuzhi();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- break;
-
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有程序51hei提供下载:
1.c.zip
(2.41 KB, 下载次数: 129)
|