求助,关于AT89C51单片机简易计算器设计的程序,最好是关于C语言的。谢谢哈。

这是我设计的原理图,供参考,想实现两位数的加减乘除,请高手帮帮忙,我感激不尽。

下面是我用STC89C52单片机编的程序,采用4*4矩阵键盘,键盘接P3口,采用六位数码管(共阴极)显示,数码管位选和片选信号分别通过两个锁存器接P0口,位选所存端接P^7口,段选所存端接P2^6口。矩阵键盘的具体接法和各位表示的含义楼主可以从程序里看的出来,楼主可以根据自己的硬件对我的程序加以修改应该就会好使,下面的程序是我自己设计的,并且用硬件检验过好使,可以实现两个整数的加减乘除,和平方,祝你成功!
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;
sbit wela=P2^7;
void display(long z);
long k, temp,num,num1,num2,num3,num4,f,f1,f2,f3,swan,wan,qian,bai,shi,ge,equ,biao;
/*f1=1 :有键按下.f=1 f2=1:有符号键按下.f3=0/1:输入第一个数/输入第二个数,biao=1/2/3/4:加减乘除
equ=1:按下等于号,num:keyscan中键值num1:得到连续输入的值num2:第一次输入的值,num3:第二次输入
的值,num4:被显示的值*/
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0};//数码管段选代码
uchar code table1[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};//数码管位选代码
void delay(uint z)//延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
long keyscan()//键盘扫描函数
{
P3=0xfe;
temp=P3&0xf0;
while(temp!=0xf0)
{
delay(10);
temp=P3&0xf0;
while(temp!=0xf0)//键盘去抖
{
temp=P3;
switch(temp)
{
case 0xee:num=7;f1=1;f2=0;break;
case 0xde:num=8;f1=1;f2=0;break;
case 0xbe:num=9;f1=1;f2=0;break;
case 0x7e:num='/';f1=1;f=1;f2=1;f3=1;biao=4;break;
}
while(temp!=0xf0)//松手检测
{
temp=P3;
temp&=0xf0;

display(num4);
}
}
}
P3=0xfd;
temp=P3&0xf0;
while(temp!=0xf0)
{
delay(10);
temp=P3&0xf0;
while(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xed:num=4;f1=1;f2=0;break;
case 0xdd:num=5;f1=1;f2=0;break;
case 0xbd:num=6;f1=1;f2=0;break;
case 0x7d:num='*';f1=1;f=1;f2=1;f3=1;biao=3;break;
}
while(temp!=0xf0)
{
temp=P3;
temp&=0xf0;

display(num4);
}
}
}
P3=0xfb;
temp=P3&0xf0;
while(temp!=0xf0)
{
delay(10);
temp=P3&0xf0;
while(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xeb:num=1;f1=1;f2=0;break;
case 0xdb:num=2;f1=1;f2=0;break;
case 0xbb:num=3;f1=1;f2=0;break;
case 0x7b:num='-';f1=1;f=1;f2=1;f3=1;biao=2;break;
}
while(temp!=0xf0)
{
temp=P3;
temp&=0xf0;
display(num4);
}
}
}
P3=0xf7;
temp=P3&0xf0;
while(temp!=0xf0)
{
delay(100);
temp=P3&0xf0;
while(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xe7:num='c';f1=1;f2=1;biao=5;equ=1;break;
case 0xd7:num=0;f1=1;f2=0;break;
case 0xb7:num='=';f1=1; f=1;f2=1;equ=1;break;
case 0x77:num='+';f1=1; f=1;f2=1;f3=1;biao=1;break;
}
while(temp!=0xf0)
{
temp=P3;
temp&=0xf0;
display(num4);
}
}
}
return num;
}
void display(long z)//显示函数
{
swan=z/100000;
wan=z%100000/10000;
qian=z%10000/1000;
bai=z%1000/100;
shi=z%100/10;
ge=z%10;

if(swan==0)//数码管最高位为0则不现实
{
P0=table1[0];
wela=1;
wela=0;
P0=table[16];
dula=1;
dula=0;
}
else
{
P0=table1[0];
wela=1;
wela=0;
P0=table[swan];
dula=1;
dula=0;
delay(2);
}
if(!(swan||wan))//前两位都为0则不现实(后面类似)
{
P0=table1[1];
wela=1;
wela=0;
P0=table[16];
dula=1;
dula=0;
}
else
{
P0=table1[1];
wela=1;
wela=0;
P0=table[wan];
dula=1;
dula=0;
delay(2);
}
if(!(swan||wan||qian))
{
P0=table1[2];
wela=1;
wela=0;
P0=table[16];
dula=1;
dula=0;
}
else
{
P0=table1[2];
wela=1;
wela=0;
P0=table[qian];
dula=1;
dula=0;
delay(2);
}

if(!(swan||wan||qian||bai))
{
P0=table1[3];
wela=1;
wela=0;
P0=table[16];
dula=1;
dula=0;
}
else
{
P0=table1[3];
wela=1;
wela=0;
P0=table[bai];
dula=1;
dula=0;
delay(2);
}

if(!(swan||wan||qian||bai||shi))
{
P0=table1[4];
wela=1;
wela=0;
P0=table[16];
dula=1;
dula=0;
}
else
{
P0=table1[4];
wela=1;
wela=0;
P0=table[shi];
dula=1;
dula=0;
delay(2);
}

P0=table1[5];
wela=1;
wela=0;
P0=table[ge];
dula=1;
dula=0;
delay(2);

}
void jisuan()//连续按键时计算出按的值(如按1计算出为1再按2计算出12再按3计算出123)
{
k=keyscan();
if(f1==1)//有键按下
{
f1=0;
if(f==1)//有符号键按下
{
f=0;
num1=0;
}
else
num1=10*num1+k;
if(f2==0)//有数字键按下
{
if(f3==0)
{
num2=num1;
num4=num2;
}
else
{
num3=num1;
num4=num3;
}
}

}
}
void jieguo()//按等号时进行相应的计算并将结果计算出来
{
if(equ==1)
{
switch(biao)
{
case 1:num4=num2+num3;break;
case 2:num4=num2-num3;break;
case 3:num4=num2*num3;break;
case 4:num4=num2/num3;break;
case 5:num4=num2*num2;break;

}
}
}

void main()
{

while(1)
{
jisuan();
jieguo();
display(num4);
}
}
温馨提示:答案为网友推荐,仅供参考
第1个回答  2011-01-19
OUTBIT EQU 8002H ;端口地址初始化
OUTSEG EQU 8004H
HIN EQU 8001H
LEDBUF EQU 30H
ORG 0000H
LJMP START
ORG 0100H
LEDMAP: ;短码表
DB 3FH,06H,5BH,4FH
DB 66H,6DH,7DH,07H
DB 7FH,6FH,77H,7CH
DB 39H,5EH,79H,71H
DELAY: MOV 19H,#10
DEY1: MOV 18H,#50 ;延蔇EY2: DJNZ 18H,DEY2
DJNZ 19H,DEY1
RET
DISPLAY: ;显示子程序
MOV DPTR,#OUTBIT
MOV A,#0
MOVX @DPTR,A
MOV A,R5 ;R4--段码
MOV DPTR,#OUTSEG
MOVX @DPTR,A
MOV DPTR,#OUTBIT
MOV A,R2 ;R2--位码
MOVX @DPTR,A
ACALL DELAY
MOV DPTR,#OUTBIT
MOV A,#0
MOVX @DPTR,A
RET

TESTKEY: MOV DPTR,#OUTBIT ;检测键盘
MOV A,#00H
MOVX @DPTR,A ;输出列置0
MOV DPTR,#HIN
MOVX A,@DPTR ;读入键盘状态
CPL A
ANL A,#0FH
RET
KEYTABLE: DB 16H,15H,14H,0FFH ;键码定义
DB 13H,12H,11H,10H
DB 0DH,0CH,0BH,0AH
DB 0EH,03H,06H,09H
DB 0FH,02H,05H,08H
DB 00H,01H,04H,07H
GETKEY: MOV DPTR,#OUTBIT ;计算键编号
MOV P2,DPH
MOV R1,#HIN ;R1行地址
MOV R3,#20H ; R2列码
MOV R7,#6
KLOOP: MOV A,R3
CPL A
MOVX @DPTR,A ;第一列置0
CPL A
RR A
MOV R3,A ;下一列
MOVX A,@R1 ; 读该列状态
CPL A
ANL A,#0FH ;屏蔽高四位
JNZ GOON1
DJNZ R7,KLOOP
MOV R7,#0FFH ;无键按下返回0FFH
SJMP EXIT
GOON1: MOV R3,A ;编号=列*4+行
MOV A,R7
DEC A
RL A
RL A
MOV R7,A ;R0=(R7-1)*4
MOV A,R3 ;R2为读入列值
MOV R2,#4
LOOPC: RRC A ;右移计算行值
JC EXIT ;R0=R0+行值
INC R7
DJNZ R3,LOOPC
EXIT: MOV A,R7 ;取键编号
MOV DPTR,#KEYTABLE
MOVC A,@A+DPTR
MOV @R0,A ;存键值R0中
WAITRELEASE: ;等待键释放
MOV DPTR,#OUTBIT
CLR A
MOVX @DPTR,A
ACALL DELAY
ACALL TESTKEY
JNZ WAITRELEASE
MOV A,@R0 ;键值存入A
RET

ADDY: MOV 12H,R0
CLR C ;加法
MOV R7,#4
ADDY1: MOV A,@R0
ADDC A,@R1
MOV @R0,A ;结果存入R0
INC R0
INC R1
DJNZ R7,ADDY1
MOV R7,#5
ACALL CHANG
RET

SUBBY: MOV 12H,R0
CLR C ;减法
MOV R7,#2
SUB1: MOV A,@R1
SUBB A,@R0
JNC N1
ADD A,#10
SETB C
N1: MOV @R0,A
INC R0
INC R1
DJNZ R7,SUB1
MOV R0,12H
RET

MULY: MOV 12H,R0
MOV R3,#0 ;乘法
MOV 15H,@R0 ;另存乘数
INC R0
MOV 16H,@R0
DEC R0
MOV R2,#2
MUL1: MOV A,@R1
MOV B,@R0
MUL AB
MOV @R0,A
INC R0
DJNZ R2,MUL1
DEC R0
INC R1
MOV B,15H
MOV R2,#2
MUL2: MOV A,@R1
MUL AB
ADD A,@R0
MOV @R0,A
INC R0
MOV A,#0
ADDC A,#0
MOV @R0,A
MOV B,16H
DJNZ R2,MUL2
MOV R7,#4
ACALL CHANG
RET

CHANG: MOV R0,12H ;转化为十进制
MOV R3,#0
C1: MOV A,@R0
ADD A,R3
MOV B,#10
DIV AB
XCH A,B
MOV @R0,A
INC R0
MOV R3,B
DJNZ R7,C1
MOV R0,12H
RET

LEDBUFY: JC NEXT1 ;数据缓冲子程序
SJMP NEXT2
NEXT1: MOV R5,#40H ;负数
MOV R2,#20H
ACALL DISPLAY
MOV R2,17H
NEXT2: MOV A,@R0
MOV DPTR,#LEDMAP
MOVC A,@A+DPTR
MOV R5,A
ACALL DISPLAY
MOV A,R2
RR A
MOV R2,A
DEC R0
DJNZ R6,NEXT2
RET

START: CLR C ;开始
MOV R0,#LEDBUF ;R0--数据缓冲地址
MOV R6,#0
MOV R3,#30 ;初始化参数
K1: MOV @R0,#00H
INC R0
DJNZ R3,K1
MOV R0,#LEDBUF+20 ;缓冲区清零
DISPL: MOV 10H,R0 ;保护R0,R6
MOV 11H,R6
MOV R2,#1
CJNE R6,#0,Y1
SJMP Y3 ;无任何键按下
Y1: MOV A,R0
ADD A,R6
MOV R0,A ;数据高位地址送R0
MOV A,R2
RRC A
Y2: RLC A
DJNZ R6,Y2
MOV R2,A ;位码移到高位
MOV R6,11H
SJMP Y4
Y3: MOV R6,#01H
Y4: MOV 17H,R2
ACALL LEDBUFY ;数据送缓冲区显示
MOV R6,11H
MOV R0,10H
TESTY: ACALL TESTKEY
ACALL DELAY ;测试键盘
JZ DISPL ;无键按下,动态显示缓冲区内容
ACALL GETKEY ;有键输入
DEC R0
K2: CJNE A,#0AH,K3 ;确认键值
SJMP NEXT ;功能键“+”
K3: JNC K4
INC R6
SJMP DISPL
K4: CJNE A,#0FH,K5
SJMP START ;清零键
K5: CJNE A,#0BH,K6 ;功能键“-”
SJMP NEXT
K6: CJNE A,#0CH,K7 ;功能键“*”
NEXT: MOV R4,A ;功能键“+,-,*”,并保存入R4
MOV A,R0
INC A
INC A
MOV 1FH,A
MOV R0,#LEDBUF+10 ;赋下一个操作数缓冲地址
MOV R6,#0 ; 计数清零
SJMP TESTY ;等待数据输入
K7: CJNE A,#0EH,K8 ;功能键“=”
EQUY: INC R0
INC R0
MOV R1,1FH
CJNE R4,#0AH,LOOP1 ;测试上一次功能键
ACALL ADDY
DEC R0 ;加法
MOV R6,#5 ;五个缓冲单元
SJMP DISPL
LOOP1: CJNE R4,#0BH,LOOP2
ACALL SUBBY
DEC R0 ;减法
MOV R6,#2 ;两个缓冲单元
SJMP DISPL
LOOP2: ACALL MULY ;乘法
DEC R0
MOV R6,#4 ;四个缓冲单元
SJMP DISPL ;送数入显示缓冲区
K8: INC R0
MOV @R0,#0
SJMP TESTY ;继续测试键盘
END本回答被提问者和网友采纳
第2个回答  2011-01-20
这个是我原来点的1602驱动。你对照看看,判忙,发数据,发命令函数是不是一样的。 你的程序我没具体看。你尝试在某些命令后加上延时试看。 还有第二行的地址是40H开头的。
/********************************************************************************
*Design: qinhao
*********************************************************************************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
volatile char bf;

sbit rs=P3^0;
sbit rw=P3^1;
sbit e=P3^2;
#define bf P1^7

uchar code qin[]={
0x1F,0x11,0x11,0x11,0x11,0x11,0x11,0x1F, //方框
0x0E,0x0A,0x04,0x1F,0x04,0x0E,0x0A,0x1B, //小人
0x0A,0x15,0x0A,0x15,0x0A,0x15,0x0A,0x15, //黑白格子
0x1F,0x15,0x1F,0x1B,0x1B,0x1F,0x11,0x1F, //脸
0x0E,0x11,0x11,0x15,0x15,0x0E,0x04,0x04, //树
0x0f,0x09,0x0f,0x09,0x0f,0x09,0x0b,0x11, // 月
0x1F,0x00,0x1F,0x00,0x1F,0x00,0x1F,0x00, //黑白横条
0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, //黑白竖条

};

void delay(unsigned int n)
{
unsigned int i,j;
for(j=n;j>0;j--)
for(i=112;i>0;i--);
} /////// 精确MS,

void check() // 判忙
{

rs=0;
rw=1;
e=0;
P1=0xff;
e=1;
_nop_();
_nop_();
while(P1&0x80){};
delay(10);
}

void sendc(uchar com) // 发命令字
{
check();
rs=0;
rw=0;
e=1;
P1=com;
_nop_();
e=0;
_nop_();
}

void sendd(uchar word) // 发显示字
{
check();
rs=1;
rw=0;
e=1;
P1=word;
_nop_();
e=0;
_nop_();
}

void inti() // 初始化
{
sendc(0x01);
sendc(0x38);
sendc(0x0f);
sendc(0x06);
delay(10);
}

void setcgram() ////// 写cgram
{
uchar x;
sendc(0x40);
for(x=0;x<64;x++)
{
sendd(*(qin+x));
};
}

void main()
{
unsigned char i;
setcgram();
inti();
sendc(0x80); /// 第一行
for(i=0;i<8;i++)
{
sendd(i+0x00);
};
sendc(0xc0); /// 第二行
for(i=0;i<8;i++)
{
sendd(0x07-i);
};

while(1){};

}