//******************************************************************************//
// 赛题:单片机多功能计算器 //
// 版本:2.0 //
// 作者:Ayuan //
// 日期:2010.03.17 //
//******************************************************************************//
#include<reg51.h> // 头文件
#define uint unsigned int //
#define uchar unsigned char
//***************************** 端口定义 ***********************************//
sbit rs = P2^0; // 定义引脚
sbit rw = P2^1; // 读写端口
sbit lcden = P2^2; // 使能端口
sbit busy = P0^7; // 忙碌判断端口
//***************************** 变量定义 ***********************************//
long a,b,c; // a,第一个数
uchar flag,symbol,egg; // flag表示是否有符号键按下,symbol 表征按下的是哪个符号
char i,j,temp,num; // j判断之前是否有运算过,num为table里的序号
int x;
uchar code table[]={ //
7,8,9,0,
4,5,6,0,
1,2,3,0,
0,0,0,0};
uchar code table1[]={
0x37, 0x38, 0x39, 0x2b,
0x34, 0x35, 0x36, 0x2d,
0x31, 0x32, 0x33, 0x2a,
0x30, 0x3d, 0x23, 0x2f};
uchar code logow[]={
0x20, 0x20, 0x20, 0x2e,
0x2e, 0x2e, 0x67, 0x6e,
0x69, 0x64, 0x61, 0x6f,
0x4c};
uchar code eggw[]={
0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x41, 0x79,
0x75, 0x61, 0x6e,
0x51, 0x51, 0x3a, 0x32,
0x35, 0x38, 0x33, 0x39,
0x31, 0x31, 0x35};
//***************************** 延时函数 ************************************//
void delay(uchar z) // 延迟函数, z 毫秒
{
uchar y;
for(z;z>0;z--)
for(y=0;y<110;y++);
}
void ldelay(uchar z)
{
uchar x,y;
for(z;z>0;z--)
for(x=0;x<110;x++)
for(y=0;y<110;y++);
}
//***************************** 清除函数 *************************************//
void clr(void)
{
a=0;
b=0;
flag=0;
symbol=0;
}
//***************************** 忙碌判断函数 **********************************//
void check() // 判断忙或空闲
{
do
{
P0=0xFF; // 11111111B,此时不接收外来指令
rs=0; // 选择指令寄存器
rw=1; // 选择读模式
lcden=0; // 禁止读写
delay(1); // 等待,液晶显示器处理数据
lcden=1; // 允许读写
}while(busy==1); // 判断是否为空闲,1 为忙, 0 为空闲
}
//***************************** 写指令函数 ***********************************//
void write_com(uchar com)
{
P0=com; // com指令付给 P2口
rs=0; // 选择指令寄存器
rw=0; // 选择写模式
lcden=0; // 禁止读写
check(); // 检查忙碌
lcden=1; // 允许读写
}
//***************************** 写数据函数 ***********************************//
void write_date(uchar date) //
{
P0=date; // com数据传给 P2口
rs=1; // 选择数据寄存器
rw=0; // 选择写模式
lcden=0; // 禁止读写
check(); // 检查忙碌
lcden=1; // 允许读写
}
//***************************** 屏幕初始化 ***********************************//
void init()
{
num=-1;
lcden=1; // 允许读写
write_com(0x38); // 00111000B,设置16*2显示,5*7点阵,8位数据接口
write_com(0x0c); // 00001100B,显示开,光标关,光标闪烁
write_com(0x06); // 00000110B,文字不动,光标自动右移
write_com(0x80); // 10000000B,检测忙信号
write_com(0x01); // 00000001B,显示开,光标关,不闪烁
i=0;
j=0;
a=0; // 第一个参与运算的数
b=0; // 第二个参与运算的数
c=0; // 运算结果
flag=0; // flag表示是否有符号键按下,
symbol=0; // symbol 表征按下的是哪个符号
// 0表示无符号输入,1为+,2为-,3为*,4为/,5为平方,6为开方,7清零
egg=0; // 彩蛋
}
//***************************** 彩蛋程序 **************************************//
void regg()
{
int t;
delay(5);
init();
delay(20);
write_com(0x80+0x40);
write_com(0x06);
for(t=0;t<=10;t++)
write_date(eggw[t]);
delay(5);
write_com(0x83);
write_com(0x06);
for(t=11;t<=21;t++)
{
write_date(eggw[t]);
ldelay(10);
}
ldelay(30);
init();
}
//***************************** 开平方函数 ******************************//
float sqrt(float n)
{
int t=0;
float x,x1; // 返回值
for(x1=n;;)
{
t++;
x=(1.0/2)*(x1+n/x1);
if((x>x1&&((x-x1)<(1.0e-10)))||(x1>x&&((x1-x)<(1.0e-10))))
break;
else if(t>=10)
{
break;
}
x1=x;
}
t=0;
return(x);
}
//***************************** 键盘扫描程序 ****************************//
void keyscan()
{
P3=0xfe; // 扫描第一行
if(P3!=0xfe) // 如果有电压变化,则执行
{
delay(20); // 延时20ms,消除震动
while(P3!=0xfe) // 再次判断
{
temp=P3&0xf0; // 将P3现有端口的电平与11110000B做与,并将值赋予temp
switch(temp) // 判断temp
{
case 0xe0:num=0; // 输入7
break;
case 0xd0:num=1; // 输入8
break;
case 0xb0:num=2; // 输入9
break;
case 0x70:num=3; // 输入+
break;
}
}
r1: if(num==0||num==1||num==2&&num!=3) // 如果按下的是'7','8'或'9'而不是'+'
{
if(j!=0)
{
write_com(0x01);
clr(); // 屏幕清零
j=0;
goto r1; // 运算判断清零
}
else
{
if(flag==0) // 如果没有按过符号键
a=a*10+table[num]; //
else // 如果按过符号键
b=b*10+table[num]; //
}
if(num==1&&egg==2)
egg=3;
else if(num==2&&egg==4)
egg=5;
}
else // 按下的是'+'
{
if(j!=0)
{
write_com(0x01);
clr(); // 屏幕清零
j=0;
goto r1; // 运算判断清零
}
else
{
flag=1;
symbol=1;
}
}
i=table1[num];
write_date(i);
}
P3=0xfd; // 扫描第二行
if(P3!=0xfd)
{
delay(5);
while(P3!=0Xfd)
{
temp=P3&0xf0;
switch(temp)
{
case 0xe0:num=4; // 输入4
break;
case 0xd0:num=5; // 输入5
break;
case 0xb0:num=6; // 输入6
break;
case 0x70:num=7; // 输入-
break;
}
}
r2: if(num==4||num==5||num==6&&num!=7)
{
if(j!=0)
{
write_com(0x01); // 清屏
j=0;
goto r2; // 跳转r2
}
else
{
if(flag==0) // 没有按过符号键
a=a*10+table[num];
else // 如果按过符号键
b=b*10+table[num];
}
if(num==5&&egg==1)
egg=2;
else if(num==5&&egg==7)
{
regg();
goto loop;
}
}
else
{
if(j!=0)
{
write_com(0x01);
clr(); // 屏幕清零
j=0;
goto r2; // 运算判断清零
}
else if(symbol==2)
{
flag=1;
symbol=1;
}
else
{
flag=1;
symbol=2;
}
}
i=table1[num];
write_date(i);
}
P3=0xfb; // 扫描第三行
if(P3!=0xfb)
{
delay(5);
while(P3!=0xfb)
{
temp=P3&0xf0;
switch(temp)
{
case 0xe0:num=8; // 数字'1'
break;
case 0xd0:num=9; // 数字'2'
break;
case 0xb0:num=10; // 数字'3'
break;
case 0x70:num=11; // 符号'*'
break;
}
}
r3: if(num==8||num==9||num==10&&num!=11) // 如果按下的是 '1','2'或'3'而不是 '*'
{
if(j!=0)
{
write_com(0x01); // 清屏
j=0;
goto r3;
}
else
{
if(flag==0) // 没有按过符号键
a=a*10+table[num];
else // 如果按过符号键
b=b*10+table[num];
}
if(num==9)
egg=1;