设计题目:激光计数器
小组成员:
基本要求:
通过阻挡激光照射接收器记一次数
基本框图:
发射激光 产生数字信号 中断接收数字信号
阻挡干扰 驱动数码管显示
图1-1
设计思路:
激光计数器原理主要是利用51单片机接收集成激光接收模块发出的数字信号,采用中断计数,然后驱动数码管显示
原理描述:
电路的指导思想是利用激光发射器发射激光,集成激光接收器接收此激光,并将其放大、整流形成高电平信号。当有人或物挡住激光时,接收器没有接收到激光,接收器将输出低电平。这个便是外部计数脉冲信号。这个计数脉冲信号送入AT89C51单片机中进行计数控制,在经过扩展、显示驱动完成最后的显示过程。
原理图设计:
主模块包括单片机最小系统和电源滤波
按键复位模块
USB供电模块 激光接收器接入模块
数码管显示驱动模块
PCB图
相关代码:
#include "reg52.h"
unsigned int led[4]={0,0,0,0};
unsigned int num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned int count=0;
void delay(unsigned int time)
{
unsigned int i;
for(;time>0;time--)
for(i=0;i<60;i++);
}
void Display()
{
P2=0x08;
P0=num[led[0]];
delay(10);
P2=0x04;
P0=num[led[1]];
delay(10);
P2=0x02;
P0=num[led[2]];
delay(10);
P2=0x01;
P0=num[led[3]];
delay(10);
}
void main()
{
delay(200);
P0=0xff;//初始化端口
P2=0xff;
IT0=1;//初始化外部中断0
EX0=1;
EA=1;//开总中断
while(1)
{
Display();
}
}
void fndIorn(void) interrupt 0
{
EX0=0;
count++;
led[0]=count/1000;
led[1]=(count%1000)/100;
led[2]=(count%100)/10;
led[3]=count%10;
EX0=1;
}
器件清单:
软件清单:
Keil 、Altium Designer、STCISP
调试过程与结果
因为信号的产生于接收均采用的集成模块,硬件方面几乎没有调试过程,一次成功。软件方面主要是针对计数算法的设计和数码管的驱动。结果相当完美,能够实现0-99的计数,但是因为设计时候,数码管驱动没有三极管,所以数码管的显示有点瑕疵。
感想:本次设计在最开始的时候,因为没有理解清楚题目,对激光计数概念模糊,导致进度一度落后,后来经过老师提醒,明白了其基本原理和光电计数器原理相似,只需要将信号的采集接收转换为激光模块。后期设计因为初次PCB布线导致电路板略大,浪费材料,不符合工程设计。在以后的学习制作过程中我们将深深吸取教训!
第二篇:基于51单片机的计算器
单片机原理及应用实验基于51单片机的计算器
设计性实验
2008112020338王加元电子信息科学与技术物理与电子科学学院20xx年6月20日
实验基于51单片机的计算器
一、实验目的
1、
2、学会用程序来检测4×5矩阵键盘,并且在仿真软件中实现。学会处理按键数据,以及数据显示,数据的小数点问题。
二、实验环境
Keil软件和protus软件
三、实验内容
计算器中存在很多数据,数据的输入需要很多按键,那么这就要涉及到按键的检测问题,同时产生的数据要送到单片机中进行处理,处理完的数据要送到数码管上显示出来。
实验仿真图如下:
图1实验仿真图
(由于我的开发板上面P2^3脚接的蜂鸣器,仿真图中就没有用到
P2^3)
实验代码如下:
#include<reg52.h>
#include<stdlib.h>
#include<math.h>
#defineucharunsignedchar
#defineuintunsignedint
ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};ucharcodeled[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};ucharxx[8];
sbitdula=P2^6;
sbitwela=P2^7;
voiddisplaypro(doubleh)
{
ucharpoint=8,m;
bitsymbol;
chari;
doubleproh;
symbol=0;
if(h<0)
{
symbol=1;
h=-h;
}
if(h>=0&&h<10){point=1;proh=h*10000000;}
if(h>=10&&h<100){point=2;proh=h*1000000;}
if(h>=100&&h<1000){point=3;proh=h*100000;}
if(h>=1000&&h<10000){point=4;proh=h*10000;}
if(h>=10000&&h<100000){point=5;proh=h*1000;}
if(h>=100000&&h<1000000){point=6;proh=h*100;}
if(h>=1000000&&h<10000000){point=7;proh=h*10;}
if(h>=10000000&&h<100000000){point=8;proh=h;}
if(h<100000000)
{
for(i=7;i>=0;i--)
{
m=proh/pow(10,i);
xx[7-i]=table[m];
proh=proh-(m*pow(10,i));
if(proh<0)
proh=0;
}
if(h>=1)//由于keil中单精度和双精度是一样的,只能表示六位数,如不把后面两位清零,将会出现乱码。{
xx[6]=0x3f;
xx[7]=0x3f;
}
elsexx[7]=0x3f;
xx[point-1]+=128;//显示小数点
}
else
{
for(i=6;i>=0;i--)
xx[i]=0x00;
xx[7]=0x79;
}
while(xx[7]==0x3f)//去除0.0000000显示的问题,即把0.0000000显示成0.
{
for(i=7;i>0;i--)
xx[i]=xx[i-1];
xx[0]=0x00;
}
if(symbol==1)//若为负数时,将数组中的数据后移
{
for(i=6;i>=0;i--)
{
if(xx[i]==0x00)
{
xx[i]=0x40;
break;
}
}
}
}
voiddelay(unsignedcharx)
{
unsignedchari,j;
for(i=0;i<x;i++)
for(j=0;j<x;j++);
}
unsignedcharkeyscan()//key为按键返回值
{
uchartemp,row=0,col=0,key;
uintadd;
P2&=0xe8;
P1|=0x1f;//超过八位数时,计算器报错显示E
temp=P1;
temp|=0xe0;
if(temp!=0xff)
{
delay(15);
temp=P1;
temp|=0xe0;
if(temp!=0xff)
{
row=P1;
P2|=0x17;
P1&=0xe0;
col=P2;
col|=0xe8;
add=row*256+col;
switch(add)
{
case0xfefe:key=0;break;case0xfdfe:key=1;break;case0xfbfe:key=2;break;case0xf7fe:key=3;break;case0xeffe:key=10;break;case0xfefd:key=4;break;case0xfdfd:key=5;break;case0xfbfd:key=6;break;case0xf7fd:key=7;break;case0xeffd:key=11;break;case0xfefb:key=8;break;case0xfdfb:key=9;break;case0xfbfb:key=15;break;case0xf7fb:key=14;break;case0xeffb:key=12;break;case0xfeef:key=16;break;case0xfdef:key=17;break;case0xfbef:key=18;break;case0xf7ef:key=19;break;case0xefef:key=13;break;default:key=20;break;}
returnkey;
}
elsereturn20;
}
elsereturn20;
}
voidmain()
{
uchark,i,hand,h2;
bitxsd=0;
chardatae;
doubledatatemp,h1=0,h3=0,h4=0;displaypro(0);
while(1)
{
k=keyscan();
if(k==20)
hand=0;
for(i=0;i<8;i++)
{
wela=1;
P0=led[i];
wela=0;
P0=0xff;
dula=1;
P0=xx[i];
dula=0;
delay(20);
P0=0xff;
}
switch(k)
{
case20:break;
case0:
case1:
case2:
case3:
case4:
case5:
case6:
case7:
case8:
case9:if(hand==0)
{
h4=0;
if(h2==0)
{
if(xsd==0)
{
if(h1>=0)h1=h1*10+k;elseh1=h1*10-k;}
if(xsd==1)
{
e--;
temp=pow(10,e);
if(h1>=0)h1=h1+k*temp;elseh1=h1-k*temp;}
displaypro(h1);
}
else
{
if(xsd==0)
{
if(h3>=0)h3=h3*10+k;elseh3=h3*10-k;}
if(xsd==1)
{
e--;
temp=pow(10,e);
if(h3>=0)h3=h3+k*temp;elseh3=h3-k*temp;}
displaypro(h3);
}
}
hand++;
break;
case10:if(hand==0)//加号
{
if(h4!=0)
{
h1=h4;
h4=0;
}
switch(h2)
{
case0:h2=1;break;
case1:h1=h1+h3;h2=1;h3=0;displaypro(h1);break;case2:h1=h1-h3;h2=1;h3=0;displaypro(h1);break;case3:h1=h1*h3;h2=1;h3=0;displaypro(h1);break;case4:h1=h1/h3;h2=1;h3=0;displaypro(h1);break;}
xsd=0;e=0;
}
hand++;
break;
case11:if(hand==0)//减号
{
if(h4!=0)
{
h1=h4;
h4=0;
}
switch(h2)
{
case0:h2=2;break;
case1:h1=h1+h3;h2=2;h3=0;displaypro(h1);break;case2:h1=h1-h3;h2=2;h3=0;displaypro(h1);break;case3:h1=h1*h3;h2=2;h3=0;displaypro(h1);break;case4:h1=h1/h3;h2=2;h3=0;displaypro(h1);break;}
xsd=0;e=0;
}
hand++;
break;
case12:if(hand==0)//乘号
{
if(h4!=0)
{
h1=h4;
h4=0;
}
switch(h2)
{
case0:h2=3;break;
case1:h1=h1+h3;h2=3;h3=0;displaypro(h1);break;case2:h1=h1-h3;h2=3;h3=0;displaypro(h1);break;case3:h1=h1*h3;h2=3;h3=0;displaypro(h1);break;case4:h1=h1/h3;h2=3;h3=0;displaypro(h1);break;
}
xsd=0;e=0;
}
hand++;
break;
case13:if(hand==0)//除号
{
if(h4!=0)
{
h1=h4;
h4=0;
}
switch(h2)
{
case0:h2=4;break;
case1:h1=h1+h3;h2=4;h3=0;displaypro(h1);break;case2:h1=h1-h3;h2=4;h3=0;displaypro(h1);break;case3:h1=h1*h3;h2=4;h3=0;displaypro(h1);break;case4:h1=h1/h3;h2=4;h3=0;displaypro(h1);break;}
xsd=0;e=0;
}
hand++;
break;
case14:if(hand==0)//负号或正号
{
if(h2==0)
{
h1=-h1;
displaypro(h1);
}
else
{
h3=-h3;
displaypro(h3);
}
}
hand++;
break;
case15:if(hand==0)//开方
{
if(h4!=0)
{
h1=h4;
h4=0;
}
if(h2==0)
{
h1=sqrt(h1);
displaypro(h1);
}
else
if(h3==0)
{
h1=sqrt(h1);
displaypro(h1);
h2=0;
}
else
{
h3=sqrt(h3);
displaypro(h3);
}
xsd=0;e=0;
}
hand++;
break;
case16:if(hand==0)//小数点
{
xsd=1;
}
hand++;
break;
case17:if(hand==0)//1/x
{
if(h4!=0)
{
h1=h4;
h4=0;
}
if(h2==0)
{
h1=1/h1;
displaypro(h1);
}
else
if(h3==0)
{
h1=1/h1;
displaypro(h1);
h2=0;
}
else
{
h3=1/h3;
displaypro(h3);
}
xsd=0;e=0;
}
hand++;
break;
case18:if(hand==0)//全部清除
{
h1=0;
h2=0;
h3=0;
xsd=0;
e=0;
displaypro(0);
}
hand++;
break;
case19:if(hand==0)//等于号
{
switch(h2)
{
case0:break;
case1:h4=h1+h3;h1=0;h2=0;h3=0;displaypro(h4);break;
case2:h4=h1-h3;h1=0;h2=0;h3=0;displaypro(h4);break;
case3:h4=h1*h3;h1=0;h2=0;h3=0;displaypro(h4);break;
case4:h4=h1/h3;h1=0;h2=0;h3=0;displaypro(h4);break;
}
xsd=0;e=0;
}
}
}
}
四、实验结果
实验结果达到了预期的效果,但是由于单片机中只有单精度数据,我用的是双精度,出来的还是单精度,以至于计算数据出现了六
位数据以上时,后面的数据就会默认零,如果不默认为零,出现的就是乱码。
下面是实验仿真截取的图片,以12
的开方为例:
五、经验总结
在做这个计算器的过程中,遇到了很多棘手的问题,其中最大的问题有如何把数据储存到数组中以便送到数码管显示,如何把小数点显示所需要显示的位置上。在完善她的时候,出现了按键检测到有效果,但是数码管却没有反应,当时找了很长时间,最后却发现是因为调用按键检测函数的时候,把她写在while(1)的外面了。通过这个实验让我明白了,遇到问题时,要静下心来,一个个去解决她。要知道,如果你做一件事,总是一帆风顺,那么只能说明这个事机器也能做的了!