简易计算器
设计基本要求:
(1)系统开机能够一位数倒计时
(2)设计简易的计算机,能够进行1位数的加减乘除计算,液晶屏上可以显示最长5个数字的表达式参与运算。例如:X1+X2-X3*X4/X5
(3)可以将计算的结果存储,并利用按键可以读取,至少存储10次表达式的计算结果:
这是用protues画的图:
#include"reg51.h"
#include"stdio.h"#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit E=P2^4;
sbit W=P2^5;
sbit R=P2^6;
sbit H=P3^2;
int KeyValue;
void DelayMS(uintxms)//延时函数
{
uchar i,j,k;
i=57;j=27;k=112;
do
{
do
{
while(--k);
}
while(--j);
}
while(--i);
}
//按键子程序
uchar anjian_new(void)
{
char x,a=0;
P1=0x0f; //测试列
switch(P1)
{
case(0x07): KeyValue=0;break;
case(0x0b): KeyValue=4;break;
case(0x0d): KeyValue=8;break;
case(0x0e): KeyValue=12;break;
}
P1=0xf0; //测试行
switch(P1)
{
case(0x70): KeyValue=KeyValue+3;break;
case(0xb0): KeyValue=KeyValue+2;break;
case(0xd0): KeyValue=KeyValue+1;break;
case(0xe0): KeyValue=KeyValue;break;
}
while((a<50)&&(P1!=0xf0)) //按键松手检测
{
DelayMS(1);
a++;
}
switch(KeyValue)
{
case 0:x=14;break;
case 1:x=0;break;
case 2:x=15;break;
case 3:x=13;break;
case 4:x=1;break;
case 5:x=2;break;
case 6:x=3;break;
case 7:x=12;break;
case 8:x=4;break;
case 9:x=5;break;
case 10:x=6;break;
case 11:x=11;break;
case 12:x=7;break;
case 13:x=8;break;
case 14:x=9;break;
case 15:x=10;break;
}
return x;
}
void write_com_1602(uchar command) //写命令
{
E=0;
R=0;
W=0;
P0=command;
DelayMS(2);
E=1;
DelayMS(4);
E=0;
}
//LCD1602显示屏
void init() //LCD初始化
{
E=0;
W=0;
write_com_1602(0x38); //数据位为8位,显示2行字符,5*7点阵字符体
write_com_1602(0x0f); //开显示,光标消失,不闪烁
write_com_1602(0x06); //光标右移,AC递增
write_com_1602(0x01); //清屏
write_com_1602(0x80); //给AC送值
}
void write_data_1602(uchar datum) //写数据
{
E=0;
W=0;
R=1;
P0=datum;
DelayMS(2);
E=1;
DelayMS(4);
E=0;
}
void desplay(uint a) //一位数输出显示
{
uchar b;
b=a+0x30;
write_data_1602(b);
}
void show(ulong x) //LCD多位数显示
{
uint num,c,j;
ulong a=1,k;
uchar table[]={"0123456789"};
uchar y;
num=0;
write_com_1602(0x80+0x41);
k=x;
while(k!=0)
{
num++;
k=k/10;
}
for(j=1;j<num;j++)
{
a=a*10;
}
while(num)
{
c=x/a;
x=x%a;
a=a/10;
y=table[c];
num--;
write_data_1602(y);
}
}
//计算函数(判定符号,计算,左移)
ulong js(void)
{
ulong x,i,j,a[9];
for(i=1;i<9;i+=2)
{
if(a[i]==12||a[i]==13)
{
if(a[i]==12)
{
a[i-1]=a[i-1]*a[i+1];
for(j=i;j<9;j++)
a[j]=a[j+2];
a[7]=0;
a[8]=0;
}
if(a[i]==13)
{
a[i-1]=a[i-1]/a[i+1];
for(j=i;j<9;j++)
a[j]=a[j+2];
a[7]=0;
a[8]=0;
}
i=-1;
}
}
for(i=1;i<9;i+=2)
{
if(a[i]==10||a[i]==11)
{
if(a[i]==10)
{
a[i-1]=a[i-1]+a[i+1];
for(j=i;j<9;j++)
a[j]=a[j+2];
a[7]=0;
a[8]=0;
}
if(a[i]==11)
{
a[i-1]=a[i-1]-a[i+1];
for(j=i;j<9;j++)
a[j]=a[j+2];
a[7]=0;
a[8]=0;
}
i=-1;
}
}
x=a[0];
return x;
}
//回读函数
void int0() interrupt 0
{
uint num,c,j,t,du[9];
ulong a=1,k;
uchar table[]={"0123456789"};
char y;
num=0;
write_com_1602(0x80+0x41);
k=du[t];
write_com_1602(0x01);
while(k!=0)
{
num++;
k=k/10;
}
for(j=1;j<num;j++)
{
a=a*10;
}
while(num)
{
c=du[t]/a;
du[t]=du[t]%a;
a=a/10;
y=table[c];
num--;
write_data_1602(y);
}
t--;
H=1;
}
//中断函数
void time0() interrupt 1
{
uint p,time;
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
p++;
if(p==20)
{
write_com_1602(0x01);
write_data_1602(time+0x30);
time--; //倒计时变量自减
p=0;
}
} //主函数
void main()
{
ulong x,i,j,t,r,time,p,key,a[9],du[9];
_nop_();
init();
t=0;j=0;r=0;
P1=0xF0; //P1赋值以后,矩阵键盘开启
time=9; //倒计时初值,在定时函数里进行自减
p=0;
IT0=1; //选择外部中断0为跳沿触发方式
TMOD=0x01;
ET0=1; //定时器中断允许
EA=1;
EX0=1; //外中断0允许
H=1;
TH0=(65535-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
while(time==-2?0:1); //倒计时归零判断
TR0=0;
write_com_1602(0X01); //清屏
while(1)
{
while(P1==0xf0);
key=anjian_new(); //按键输入
if(key<=9&&key>=0) //判定键值
{
a[j]=key; //数字键值,显示数字
desplay(key);
j++;
while(P1!=0xf0);
DelayMS(30);
}
else if(key<=13&&key>=10) //符号键值,显示加减乘除符号
{
switch(key)
{
case 10:write_data_1602('+');a[j]=10;j++;break;
case 11:write_data_1602('-');a[j]=11;j++;break;
case 12:write_data_1602('*');a[j]=12;j++;break;
case 13:write_data_1602('/');a[j]=13;j++;break;
default:break;
DelayMS(130);
}
DelayMS(130);
}
else if(key==15) //等号键值
{
write_com_1602(0x80+0x40); //给AC送值
write_data_1602('=');
x=js();
du[r]=x;
t=r;
r++;
show(x);
}
else if(key==14) //清零键值
{
write_com_1602(0x01); //清屏
write_com_1602(0x80); //给AC送值
for(i=0;i<9;i++)
a[i]=0;
j=0;
}
}
}
我的程序在keil4运行后会显示如下结果:
Build target 'Target 1'
compiling 111.c...
linking...
BL51 BANKED LINKER/LOCATER V6.22 - SN: Eval Version
COPYRIGHT KEIL ELEKTRONIK GmbH 1987 - 2009
"111.obj"
TO "123"
*** WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_DELAYMS?111
CALLER1: ?PR?INT0?111
CALLER2: ?PR?TIME0?111
*** WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_DELAYMS?111
CALLER1: ?PR?TIME0?111
CALLER2: ?C_C51STARTUP
*** ERROR L114: SEGMENT DOES NOT FIT
SPACE: DATA
SEGMENT: _DATA_GROUP_
BASE: 0000H
LENGTH: 00C7H
******************************************************************************
* RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 0A37H BYTE (127%) *
******************************************************************************
Program Size: data=210.0 xdata=0 code=3298
LINK/LOCATE RUN COMPLETE. 2 WARNING(S), 1 ERROR(S)
*** WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_DELAYMS?111
CALLER1: ?PR?INT0?111
CALLER2: ?PR?TIME0?111
*** WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?_DELAYMS?111
CALLER1: ?PR?TIME0?111
CALLER2: ?C_C51STARTUP
*** ERROR L114: SEGMENT DOES NOT FIT
SPACE: DATA
SEGMENT: _DATA_GROUP_
BASE: 0000H
LENGTH: 0018H
*** FATAL ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED
MODULE: C:\KEIL\C51\LIB\C51S.LIB (-----)
LIMIT: 0800H BYTES
Target not created