基于单片机的多功能计算器设计.docx
《基于单片机的多功能计算器设计.docx》由会员分享,可在线阅读,更多相关《基于单片机的多功能计算器设计.docx(23页珍藏版)》请在冰点文库上搜索。
![基于单片机的多功能计算器设计.docx](https://file1.bingdoc.com/fileroot1/2023-7/1/e135b3ca-f9ff-490b-8074-7d85f8913393/e135b3ca-f9ff-490b-8074-7d85f89133931.gif)
基于单片机的多功能计算器设计
工程设计训练
设计报告
课题名称基于单片机的多功能计算器设计
院系物理与电子工程学院
年级专业电子信息工程
班级学号
学生姓名任课教师
设计时间
目录
第一章概述
第二章硬件设计方案
第三章程序设计
第四章软件仿真调试
心得体会
参考文献
附录
工程设计训练—基于单片机的多功能计算器设计任务书
一、设计课题:
基于单片机的多功能计算器设计
二、设计目的:
运用已学课程的基本知识,在设计中加以应用,进而得到理解、巩固和提高发展,通过实践的过程学习掌握分析与解决实际问题的方法与手段,提高设计、编程与调试的实际动手能力,作为工程技术工作的一次基本训练。
三、设计任务:
使用AT89C51单片机设计一个多功能计算器,主要用到矩阵键盘,LCD液晶显示器。
要求进行硬件、软件系统设计。
四、主要任务:
1、在多功能计算器上能够显示所输入的表达式,例如:
(20+10)/10
2、在设计中,能进行加减乘除及优先级运算,例如:
2+6*2,并且有清除功能用C表示。
3、能够计算的最大数字位数是两位。
4、程序设计完过后,进行电路设计。
用protues软件进行仿真。
二,具体内容
I-硬件设计
单片机用AT89C51,4*4矩阵键盘,显示用LCD1602,上拉电阻,74HC21与门和一些外设设备(晶振,电容)
设置
1—AT89C51单片机
2--计算器的键盘布局:
计算器有16个键(0,1,2,3,4,5,6,7,8,9,/,*,+,-,=,ON/AC)组成,在单片机中正好有一个端口实现16个按键功能,这种形式在单片机系统中最常用是矩阵键盘。
矩阵式结构的键盘识别要复杂一些,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。
这样,当按键没有按下时,所有的输入端都是高电平,代表无键按下。
行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。
在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。
由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
<1>确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如上图所示键盘,介绍过程如下。
1、判断键盘中有无键按下将全部行线Y0-Y3置低电平,然后检测列线的状态。
只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。
若所有列线均为高电平,则键盘中无键按下。
2、判断闭合键所在的位置在确认有键按下后,即可进入确定具体闭合键的过程。
其方法是:
依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。
在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。
若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
<2>确定矩阵式键盘上何键被按下介绍一种“高低电平翻转法”。
首先让P1口高四位为1,低四位为0,。
若有按键按下,则高四位中会有一个1翻转为0,低四位不会变,此时即可确定被按下的键的行位置。
然后让P1口高四位为0,低四位为1,。
若有按键按下,则低四位中会有一个1翻转为0,高四位不会变,此时即可确定被按下的键的列位置。
最后将上述两者进行或运算即可确定被按下的键的位置。
本设计用第一种“行扫描法”。
键盘与单片机接口是P1^0=R1,P1^1=R2,P1^2=R3,P1^3=R4.P1^4=L1,
P1^5=L2,P1^6=L3,P1^7=L4
3--74HC21与门接线图
4--上拉电阻
作用是驱动LCD1602
5—LCD1602显示模块
本设计采用LCD液晶显示器来显示输出数据。
LCD的特性有:
1、+5V电压,对比可调度;2、内含复位电路;3、提供各种控制命令,如:
清屏、字符闪烁、光标闪烁、显示移位等多种功能;4、有80字节显示数据存储器DDRAM;5、内建有160个5X7点阵的字型的字符发生器CGROM;6、8个可由用户自定义的5X7的字符发生器CGRAM。
本设计通过D0-D7引脚向LCD写指令字或写数据以使LCD实现不同的功能或显示相应的数据。
接口电路如下:
II--软件设计
输入数据和表达式并显示表达式。
判断输入是否正确,如果输入错误显示”ERROR”,如果输入正确就进行分辨符号“*”,“/”,“+”,“-”然后按这样顺序(乘,除,加,减)进行运算
仿真用KeilUvision2软件和Proteus7软件
仿真结果
#include
//#include
#defineuintsignedint
#defineucharunsignedchar
#definefuhao_1-1//'/"除符号
#definefuhao_2-2//乘符号
#definefuhao_3-3//减符号
#definefuhao_4-4//加符号
sbitlcden=P3^5;//定义引脚E使能
sbitrs=P3^7;
sbitrw=P3^6;
sbitbusy=P0^7;
sbitp33=P3^3;
floatarry[20];
intarry_1[]={0x52,0x4f,0x52,0x52,0x45};//"ERROR'
longc;//结果
longq;//结果的绝对数
ucharerror;//错误标志
ucharm;//输入新表达式的标志
ucharok_flag;//输入完毕的标志
ucharfuhao;//符号标志
voiddelay(ucharz)//延迟函数
{uchary;
for(z;z>0;z--)
for(y=0;y<110;y++);
}
//*********************判断忙或空闲******************//
voidcheck()
{
do{
P0=0xFF;
rs=0;
rw=1;//读rsrw值为01时,忙标志和地址计数器读出
lcden=0;//E=0,禁止读写
delay
(1);//等待,液晶显示器处理数据
lcden=1;//E=1,允许读写
}while(busy==1);//判断是否为空闲,1为忙,0为空闲
}
//*********************写指令函数*****************//
voidwrite_com(ucharcom)
{
P0=com;//com指令付给P0口
rs=0;
rw=0;
lcden=0;
check();
lcden=1;
}
//**********************写数据函数*********************//
voidwrite_date(uchardate)
{
P0=date;
rs=1;
rw=0;
lcden=0;
check();
lcden=1;
}
voidinit()//初始化
{uchari;
lcden=1;//使能信号为高电平
write_com(0x38);//功能设置命令:
8位,2行DDRAM的地址
write_com(0x0e);//显示开,光标开,不闪烁
write_com(0x06);//地址计数器加1模式,显示屏不移位
write_com(0x80);//设置访问地址
for(i=0;i<20;i++)
{arry[i]=0;}
error=0;
ok_flag=0;
c=0;
q=0;//结果
fuhao=0;//fuhao表征按下的是哪个符号
}
//*****************键盘扫描程序**********************//
voidkeyscan(void)//键盘扫描程序
{uchartemp,i,num;
voidint0();
if(m==1)//输入新表达式
{
write_com(0x01);//清屏命令
for(i=0;i<20;i++)
{arry[i]=0;}
m=0;
ok_flag=0;
fuhao=0;
}
P1=0xfe;
if(P1!
=0xfe)//第1行有键按下
{
delay(20);//20ms
if(P1!
=0xfe)//第1行确实有键按下
{
temp=P1&0xf0;
switch(temp)
{
case0xe0:
num=0;//确定按键为第1行第1列,置标示符num
break;
case0xd0:
num=1;
break;
case0xb0:
num=2;
break;
case0x70:
num=3;
break;
}
}
while(P1!
=0xfe);
if(num==0)
{arry[2*fuhao]=10*(arry[2*fuhao])+7;write_date(0x30+7);}//第1行第1列键值7,存在数组arry[]
if(num==1)
{arry[2*fuhao]=10*(arry[2*fuhao])+8;write_date(0x30+8);}
if(num==2)
{arry[2*fuhao]=10*(arry[2*fuhao])+9;write_date(0x30+9);}
if(num==3)
{arry[2*fuhao+1]=fuhao_1;fuhao++;write_date(0x2f);}//第1行第4列键值"/",存在数组arry[]
}
P1=0xfd;
if(P1!
=0xfd)//第2行有键按下
{
delay(20);
if(P1!
=0xfd)//第2行确实有键按下
{
temp=P1&0xf0;
switch(temp)
{
case0xe0:
num=4;//确定按键为第2行第1列,置标示符num
break;
case0xd0:
num=5;
break;
case0xb0:
num=6;
break;
case0x70:
num=7;
break;
}
}
while(P1!
=0xfd);
if(num==4)
{arry[2*fuhao]=10*(arry[2*fuhao])+4;write_date(0x30+4);}//第2行第1列键值为4,存在数组arry[]
if(num==5)
{arry[2*fuhao]=10*(arry[2*fuhao])+5;write_date(0x30+5);}
if(num==6)
{arry[2*fuhao]=10*(arry[2*fuhao])+6;write_date(0x30+6);}
if(num==7)
{arry[2*fuhao+1]=fuhao_2;fuhao++;write_date(0x2a);}//第2行第4列键值为"*",存在数组arry[]
}
P1=0xfb;//第3行有键按下
if(P1!
=0xfb)
{
delay(20);
if(P1!
=0xfb)//第3行确实有键按下
{
temp=P1&0xf0;
switch(temp)
{
case0xe0:
num=8;//确定按键为第3行第1列,置标示符num
break;
case0xd0:
num=9;
break;
case0xb0:
num=10;
break;
case0x70:
num=11;
break;
}
}
while(P1!
=0xfb);
if(num==8)
{arry[2*fuhao]=10*(arry[2*fuhao])+1;write_date(0x30+1);}//第3行第1列键值为1,存在数组arry[]
if(num==9)
{arry[2*fuhao]=10*(arry[2*fuhao])+2;write_date(0x30+2);}
if(num==10)
{arry[2*fuhao]=10*(arry[2*fuhao])+3;write_date(0x30+3);}
if(num==11)
{arry[2*fuhao+1]=fuhao_3;fuhao++;write_date(0x2d);}//第3行第4列键值为"-",存在数组arry[]
}
P1=0xf7;
if(P1!
=0xf7)
{
delay(20);
if(P1!
=0xf7)
{
temp=P1&0xf0;
switch(temp)
{
case0xe0:
num=12;
break;
case0xd0:
num=13;
break;
case0xb0:
num=14;
break;
case0x70:
num=15;
break;
}
}
while(P1!
=0xf7);
if(num==12)//第4行第1列ON/C键,清屏
{
write_com(0x01);
for(i=0;i<20;i++)
{arry[i]=0;}
fuhao=0;
ok_flag=0;
}
if(num==13)
{arry[2*fuhao]=10*(arry[2*fuhao]);write_date(0x30);}//第4行第2列键值为0,存在数组arry[]
if(num==14)
{ok_flag=1;m=1;}//第4行第3列j键值"=",输入完毕,输入新表达式
if(num==15)
{arry[2*fuhao+1]=fuhao_4;fuhao++;write_date(0x2b);}////第2行第4列键值为"*",存在数组arry[]
}
P1=0xf0;//置第一行全部按下
}
//***********************条件运算条件*********************//
voidstop(void)
{uchark,h;
h=2*fuhao;
for(k=0;k<=h;k++)
{
if((arry[k])<0)
{if((arry[k+1])==0)
if(arry[k+2]<0)
error=1;}
if(arry[k]==fuhao_1)
{if(arry[k+1]==0)
error=1;}
}
}
//************************运算*********************//
voidprocess(void)
{ucharh,k,i,j;
for(k=0;k<=(2*fuhao);k++)
{
if(arry[k]==fuhao_2)//乘符号//
{
j=k-1;
h=2*fuhao-2;
arry[j]=arry[j]*arry[j+2];
for(i=(j+1);i<=h;i++)
{arry[i]=arry[i+2];}
fuhao=fuhao-1;
k=k-1;
}
}
for(k=0;k<=(2*fuhao);k++)
{
if(arry[k]==fuhao_1)//除符号//
{
j=k-1;
h=2*fuhao-2;
arry[j]=arry[j]/arry[j+2];
for(i=(j+1);i<=h;i++)
{arry[i]=arry[i+2];}
fuhao=fuhao-1;
k=k-1;
}
}
h=fuhao;
for(k=1;k<=h;k++)
{if(arry[1]==fuhao_3)//减符号//
{arry[0]=arry[0]-arry[2];
fuhao=fuhao-1;
for(i=1;i<=(2*fuhao);i++)
{arry[i]=arry[i+2];}
}
else
{if(arry[1]==fuhao_4)//加符号//
{arry[0]=arry[0]+arry[2];
fuhao=fuhao-1;
for(i=1;i<=(2*fuhao);i++)
{arry[i]=arry[i+2];}
}
//*******显示运算结果****************//
if(fuhao==0)
{c=arry[0];//小位数取三位//
write_com(0x80+0x4f);
//按下等于键,光标前进至第二行最后一个显示处//
write_com(0x04);
//设置从后住前写数据每写完一个数据,光标后退一格//
if(c<0)
{
q=0-c;
}
if(q>=1000)
{
i=0;
while(i<3)
{write_date(0x30+q%10);
q=q/10;
i++;
}
write_date(0x2e);//写小数符号"."
while(q!
=0)
{
write_date(0x30+q%10);
q=q/10;
}
}
if(c<0)
write_date(0x2d);//写"-"符号
write_date(0x3d);//再写"="符号
}
ok_flag=0;
}
//************************输入错误处理***************************//
voiderror_process(void)
{inti;
write_com(0x80+0x4f);
//按下等于键,光标前进至第二行最后一个显示处//
write_com(0x04);
//设置从后住前写数据,每写完一个数据,光标后退一格//
for(i=0;i<5;i++)
{write_date(arry_1[i]);
}
error=0;
for(i=0;i<20;i++)
{arry[i]=0;}
}
//**************************主函数************************//
voidmain(void)
{uchari;
init();
EX1=1;
EA=1;
IT1=1;
p33=1;
P1=0xf0;
while
(1)
{
if(p33==0)
{keyscan();}
if(ok_flag==1)
{
stop();
if(error==1)
{error_process();}
else
{process();
for(i=0;i<20;i++)
{arry[i]=0;}
}
ok_flag=0;
}
}
}
voidint0()interrupt2using1//中断
{
if(p33==1)
{
p33=0;
}
}
参考文献
教师评语:
工程设计成绩:
任课教师签名:
附录