简单计算器Word文档格式.docx
《简单计算器Word文档格式.docx》由会员分享,可在线阅读,更多相关《简单计算器Word文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
1.1课程说明
本次课程设计的任务就是要以51系列单片机为控制元件,设计实现一个简易的计算器,它的结构非常简单,外部主要由4*4矩阵键盘和一个液晶显示屏构成,内部由一块AT89C51单片机构成,再加上为系统供电的电源电路、单片机内部振荡的晶振电路、以及手动复位电路构成计算器的整个系统电路。
通过软件编程可实现简单加减乘除的功能,六位数范围内的基本四则运算,并在LCD上显示相应的结果。
软件方面使用C语言编程,并用PROTUES仿真。
1.2设计要求
本系统选用AT89C51单片机为主控机。
通过扩展必要的外围接口电路,实现对计算器的设计,具体设计如下:
(1)由于设计的计算器要进行四则运算,为了得到较好的显示效果,经综合分析后,最后采用LCD显示数据和结果。
(2)采用键盘输入方式,键盘包括数字键(0~9)、符号键(+、-、×
、÷
)、清除键(on\c)和等号键(=),故只需要16个按键即可。
(3)在执行过程中,开机等待键入数值,当键入数字,通过LCD显示出来,当键入+、-、*、/运算符,计算器在内部执行数值转换和存储,并等待再次键入数值,当再键入数值后将显示键入的数值,按等号就会在LCD上输出运算结果。
(4)计算出结果后按清除键(on\c)等待下次执行键入。
第2章方案论证与流程图
(一)、按键模块
本系统的目的是完简单计算器的设计,键盘是最常用的单片机输入设备,因此我们通过键盘中按键的按下来产生相应输入,通常键盘可以分为独立连接式键盘和矩阵式连接键盘。
方案一:
独立式连接键盘。
这种连接方式是最简单的键盘电路,每个键独立接入一根数据线。
所以这种键盘结构简单,使用方便,但是通常占用的I/O口线较多。
而本次任务所要求的是多个音阶,需要的按键数量较多,则需要占用大量的I/O口线,过于繁琐。
方案二:
矩阵式连接键盘。
这种键盘将I/O口线的一部分作为行线,另一部分作为列线,按键位于行列的交叉点上,行列式键盘可节省I/O口,适合按键数较多的场合。
因此选择矩阵式键盘。
(二)显示模块
1)LCD显示电路
LCD1602作为一个成熟的产品,使用简单,模式固定,便于移植到各种类型的程序,但是初学者往往要注意结合LCD本身的时序图来完善初始化程序。
又以其微功耗、体积小、显示内容丰富、超薄轻巧的诸多优点,故采用LCD.
2.1系统框图
2.2系统总流程图
3.1设计电路图
3.2各部分电路介绍
3.2.1晶振电路
晶振电路采用内部时钟方式,单片机中晶振频率一般取值均为12MHz,电路如图所示。
晶振电路
图中电容C1和C2与晶振连接成并联型晶体振荡电路,C1和C2与晶体中的C0并联,总容值Cx大于C0,约等于(C1*C2)/(C1+C2)+C0,其中取C1=C2,根据晶振内部电路,取C1、C2标称值22pF。
3.2.2复位电路
复位是单片机的初始化操作,单片机启动运行时需要先复位使系统中所有部件处于确定的初始状态,然后开始工作。
STC89C52的复位引脚是第9脚,当此引脚连接高电平超过2个机器周期,即可产生复位的动作。
复位电路是利用RC充电来实现的,电路如图3-2所示。
复位电路
对于12MHz的时钟脉冲,每个时钟脉冲为12/12MHz=1us,两个机器周期则为2us,因此,在第9脚上连接一个2us以上的高电平脉冲,即可产生复位的动作。
电源接上瞬间,电容C3上没有电荷,相当于短路,所以第9脚直接连接到VCC,随着电容的逐步充电,充电电流减小,RST上的电位逐渐下降,当第9脚上的电压降至低电平时,单片机恢复正常状态。
上电复位所需的最短时间是振荡器建立时间加上两个机器周期。
—般VCC的上升时间不超过1ms,振荡器建立时间不超过10ms。
经过多次尝试取值,最终发现当电容C3取10μF,R1取10KΩ时,时间常数:
,足以满足要求。
但为防止电路在运行过程中需要临时复位,因此采用手动复位电路。
在单片机启动后,电容C两端的电压持续充电为5V,这是时候电阻两端的电压接近于0V,RST处于低电平所以系统正常工作。
当按键按下的时候,电容两端形成了一个回路,电容被短路,电容开始释放之前充的电量。
电容的电压从5V逐渐释放到变为了1.5V,甚至更小。
此时10K电阻两端的电压为3.5V,甚至更大,所以RST引脚又接收到高电平,单片机复。
3.2.3按键模块
上述论证键盘采用矩阵式键盘:
矩阵键盘布局图
矩阵键盘内部电路图如图2所示:
4.1系统仿真
在Proteus界面画出电路图,导入程序,依次按下十六个按键,键入相应的数字或符号,实现计算器的计算过程。
系统仿真如图所示
加法计算:
减法计算:
乘法计算:
除法计算:
4.2硬件调试
首先要保证板子上线路和原理图完全一致,其次,在上电前,要确保电路不在断路或短路情况,利用万用表来检测电路,尤其注意各焊点之间,确保焊点没有短接在一起,也没有虚焊的现象出现。
这一工作是整个调试工作的第一步,也是非常重要的一个步骤。
在确保硬件电路正常,无异常情况(断路或短路)方可上电调试,主要看单片机、键盘控制部分和液晶显示器是否正常工作。
硬件刚做出来时,液晶显示无法显示,测得各管交界线之间都存在电压,最后检查按键找出错误。
5.1心得体会
我的题目是基于单片机设计简易计算器,对于我们这些实践中的新手来说,这是一次考验。
这次课程设计我们学到很多很多的东西,学会了怎么在遇到问题时去解决问题。
不仅巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识,掌握了一种系统的研究方法,可以进行一些简单的编程。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从而提高自己的实际动手能力和独立思考的能力。
同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
这次课程设计通过我们小组的努力终于顺利完成了,在设计中遇到了很多问题,最后在王本有老师的辛勤指导下,终于迎刃而解,在此我们表示感谢!
【参考文献】
1、《例说51单片机(C语言版)》张义和、王敏男等人民邮电出版社
2、《单片机原理与接口技术》(第3版)李朝青北京航空航天大学出版社
3、《单片机课程设计指导》杨居义清华大学出版社
4、《单片机原理及其接口技术》胡汉才清华大学出版社
5、《8051单片机实践与应用》吴金戎沈庆国郭庭吉清华大学出版社
6、《单片机实验与实践教程》万光毅严义邢春香北航出版社
7、《单片机原理及应用技术》范力昱电子工业出版社
附录
以下为程序:
#include<
reg51.h>
math.h>
#defineuncharunsignedchar
#defineunintunsignedint
#definePi3.141596
sbitrs=P2^0;
sbitrw=P2^1;
sbiten=P2^2;
sbitbusy=P0^7;
chari,j,flag,fuhao,y,r,z;
chars[30];
uncharnum,temp;
longa,b,c;
uncharcodetable[]={7,8,9,0,//内部运算用
4,5,6,0,
1,2,3,0,
0,0,0,0,
0,0,0,0};
uncharcodetable1[]={7,8,9,0x2f-0x30,//显示用7,8,9,/,//后面加了0x30,所以这里减掉
4,5,6,0x2a-0x30,//4,5,6,*
1,2,3,0x2d-0x30,//1,2,3,-
0x01-0x30,0,0x3d-0x30,0x2b-0x30,//ON/C,0,=,+
0x02-0x30,0x03-0x30,0x04-0x30};
//2转10,10转2,10转16,16转10
voiddelay(uncharz)
{
uncharx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
}
voidcheckbusy()
{
while(busy==1)//P0^7最高位为1为忙,0为闲
{
P0=0xff;
rs=0;
rw=1;
en=0;
//禁止读写
delay(20);
en=1;
}
voidwrite_com(uncharcom)//写指令
rs=0;
rw=0;
en=0;
checkbusy();
P0=com;
delay(5);
en=1;
voidwrite_date(unchardate)//写函数
rs=1;
P0=date;
voidinit()
write_date(0);
delay(50);
write_com(0x38);
//16*2显示,5*7点阵,8位数据接口
write_com(0x0c);
//开显示关光标和闪烁
write_com(0x06);
//地址向后移
write_com(0x80);
//光标初始地址
write_com(0x01);
//清屏
write_com(0x0e);
i=0;
flag=0;
//赋初值flag表示按符号键后的输入值,默认为没按之前的输入
fuhao=0;
a=0;
b=0;
c=0;
voidlcd_clean()//清屏
delay(20);
voidkeyscan()
//**************P3口的键盘检测
P3=0xfe;
temp=P3;
temp=temp&
0xf0;
if(temp!
=0xf0)
{delay(10);
temp=P3;
temp=temp&
if(temp!
{
temp=P3;
switch(temp)
{
case0xee:
num=0;
break;
case0xde:
num=1;
case0xbe:
num=2;
case0x7e:
num=3;
}
}
while(P3!
=0xfe);
if(num==0||num==1||num==2)
{
if(flag==0)
a=a*10+table[num];
//a是在没按符号键之前输入的值
if(flag==1)
b=b*10+table[num];
//b是按符号键后输入的值
}
if(num==3)//"
/"
除键
{
flag=1;
fuhao=4;
//"
}
i=table1[num];
//显示的值
write_date(0x30+i);
//十六进制表示的ASC码
P3=0xfd;
temp=P3;
temp=temp&
if(temp!
=0xf0)
{delay(5);
case0xed:
num=4;
case0xdd:
num=5;
case0xbd:
num=6;
case0x7d:
num=7;
}
=0xfd);
if(num==4||num==5||num==6)
if(flag==0)
a=a*10+table[num];
else
b=b*10+table[num];
if(num==7)//"
*"
乘
flag=1;
fuhao=3;
i=table1[num];
write_date(0x30+i);
P3=0xfb;
temp=P3;
temp=temp&
if(temp!
{delay(5);
case0xeb:
num=8;
case0xdb:
num=9;
case0xbb:
num=10;
case0x7b:
num=11;
}
while(P3!
=0xfb);
if(num==8||num==9||num==10)
{
if(flag==0)
{a=a*10+table[num];
else
{b=b*10+table[num];
}
}
if(num==11)//"
-"
减
fuhao=2;
}
P3=0xf7;
case0xe7:
num=12;
case0xd7:
num=13;
case0xb7:
num=14;
case0x77:
num=15;
}
=0xf7);
//松手检测,没有松手则保持显示的状态
switch(num)
case12:
lcd_clean();
a=0;
fuhao=0;
}break;
case13:
if(flag==0)
{
a=a*10;
write_date(0x30);
}
else
{
b=b*10;
write_date(0x30);
}
case14:
{//需要按"
="
的
if(fuhao==1)
{
write_com(0x80+0x0f);
//重新定位后再清屏
write_com(0x04);
c=a+b;
while(c!
=0)
{
write_date(0x30+c%10);
c=c/10;
}
write_date(0x3d);
//写"
a=0;
fuhao=0;
//清0
elseif(fuhao==2)
{
write_com(0x80+0x0f);
lcd_clean();
write_com(0x04);
if(a-b>
0)
c=a-b;
else
c=b-a;
while(c!
{
write_date(0x30+c%10);
c=c/10;
}
if(a-b<
write_date(0x2d);
elseif(fuhao==3)
write_com(0x80+0x0f);
lcd_clean();
write_com(0x04);
c=a*b;
elseif(fuhao==4)
i=0;
c=(long)(((float)a/b)*1000);
//化整后再加小数点
write_date(0x30+c%10);
c=c/10;
i++;
if(i==3)
write_date(0x2e);
//加小数点"
."
if(a/b<
write_date(0x30);
elseif(fuhao==5)
c=(long)(pow((float)a,(float)1/b)*1000);
i++;
if(i==3)
write_date(0x2e);
write_date(0x3d);
a=0;
elseif(fuhao==6)
c=pow((float)a,(float)b);
//c52内部的函数