单片机简易计算器设计的程序
展开全部
首先会按键扫描,再会数码管或液晶屏显示,基本上可以了
程序
流程:
扫描按键(最多5次,最大65536,简易计算器吗)获得一个数,再扫描按键获得加减乘除符号
扫描按键获得另一个数
扫描按键获得“=”,显示计算结果
由于程序比较长,且与硬件有关,因此只贴出主程序:
void
main()
{
while(1)
{
c=1
while(c<6)//输入第1个5
位数
{
keyval=keyscan()
if(keyval<10)
{
switch(c)
{
case
1:b1=keyval
break
case
2:b2=keyval
break
case
3:b3=keyval
break
case
4:b4=keyval
break
case
5:b5=keyval
break
}
c++
}
display1(b1,b2,b3,b4,b5)
}
while(c==6)
//输入计算符号
{
keyval=keyscan()
if((keyval>=10)&&(keyval<14))
//10-13代表加减乘除
4种符号
{
d=keyval
}
c=1
display3(d)
}
while(c<6)
//输入第2个5
位数
{
keyval=keyscan()
if(keyval<10)
{
switch(c)
{
case
1:d1=keyval
break
case
2:d2=keyval
break
case
3:d3=keyval
break
case
4:d4=keyval
break//
除
case
5:d5=keyval
break
}
c++
}
display2(d1,d2,d3,d4,d5)
}
bb=
b1*10000+b2*1000+b3*100+b4*10+b5//5个按键数值合成一个数
dd=d1*10000+d1*1000+d3*100+d4*10+d5
//另外5个按键数值也合成一个数
while(keyval!=14)
//等待按下"="
{
keyval=keyscan()
}
Delay1ms(10)
switch(d)
{
case
10:ee=bb+dd
break//+
case
11:
flag1=1//结果是负数的标志,先假定是负数
if(bb>=dd)
{
ee=bb-dd
//结果不是负数
flag1=0
}
else
ee=dd-bb
//减数和被减数交换
break
case
12:ee=bb*dd
break//*可能会溢出
case
13:ee=bb/dd
//除法小数部分会丢失,保留2位
ff=bb%dd
fd1=ff*10/dd
fd2=ff*100/dd%10
break
}
f10=ee/1000000000%10
f9=ee/100000000%10
f8=ee/10000000%10
f7=ee/1000000%10
f6=ee/100000%10
f5=ee/10000%10
f4=ee/1000%10
f3=ee/100%10
f2=ee/10%10
f1=ee%10
display4(f10,f9,f8,f7,f6,f4,f4,f3,f2,f1,fd1,fd2)
while(keyval!=15)
{
keyval=keyscan()
}
b1=0b2=0b3=0b4=0b5=0
d1=0d2=0d3=0d4=0d5=0
bb=0dd=0ee=0
init2()
}
}
下面是我以前写的一个简单的计算器的程序,你可以参考参考
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit E=P2^7 //1602使能引脚
sbit RW=P2^6 //1602读写引脚
sbit RS=P2^5 //1602数据/命令选择引脚
uchar temp,num,k,m,flag,flag1,tt,a
uint table[10]
uint val[8]
uint shu,shu1,shu2
void init()
void delay(uint z)
void write_com(uchar com)
void write_date(uchar date)
uchar keyscan()
void input()
void output()
void main()
{
init()
while(1)
{
input()
output()
}
}
void delay(uint z)
{
int i,j
for(i=zi>0i--)
for(j=110j>0j--)
}
void init()
{
write_com(0x38)
write_com(0x0c)
write_com(0x06)
write_com(0x80)
write_com(0x01)
}
void write_com(uchar com)
{
P0=com
RS=0
RW=0
E=0
delay(5)
E=1
delay(5)
}
void write_date(uchar date)
{
P0=date
RS=1
RW=0
E=0
delay(5)
E=1
delay(5)
}
uchar keyscan()
{
P1=0xfe//对矩阵键盘的第一行全赋0,扫描第一行
temp=P1
temp=temp&0xf0
while(temp!=0xf0)//消抖
{
delay(10)
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
temp=P1//将P1的值读入temp中,否则temp的值始终为0xf0
//因为当程序运行到松手检测循环时,要退出松手
//检测循环就必须是temp值为0xf0
switch(temp)
{
case 0xee:num=7break//break是跳出switch语句,
case 0xde:num=8break//而不是跳出while语句
case 0xbe:num=9break
case 0x7e:num=13break//num=13表示除号
}
while(temp!=0xf0) //松手检测
{ //即当手松开时,也即无按键被按下
temp=P1 //则temp值就等于0xf0,
temp=temp&0xf0 //退出此循环
}
}
}
P1=0xfd//对矩阵键盘的第二行全赋0,扫描第二行
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
delay(5)
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
temp=P1
switch(temp)
{
case 0xed:num=4break
case 0xdd:num=5break
case 0xbd:num=6break
case 0x7d:num=12break//num=12表示乘号
}
while(temp!=0xf0)
{
temp=P1
temp=temp&0xf0
}
}
}
P1=0xfb//对矩阵键盘的第三行全赋0,扫描第三行
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
delay(5)
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
temp=P1
switch(temp)
{
case 0xeb:num=1break
case 0xdb:num=2break
case 0xbb:num=3break
case 0x7b:num=11break//num=11表示减号
}
while(temp!=0xf0)
{
temp=P1
temp=temp&0xf0
}
}
}
P1=0xf7//对矩阵键盘的第四行全赋0,扫描第四行
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
delay(5)
temp=P1
temp=temp&0xf0
while(temp!=0xf0)
{
temp=P1
switch(temp)
{
case 0xe7:num=15break//num=15表示清零
case 0xd7:num=16break//num=16表示0
case 0xb7:num=14break//num=14表示等号
case 0x77:num=10break//num=10表示加号
}
while(temp!=0xf0)
{
temp=P1
temp=temp&0xf0
}
}
}
return num
}
void digit(uchar number)
{
write_com(0x80+a)
write_date(number+'0')
table[a]=tt
delay(5)
tt=0
num=0
a++
}
void input()
{
uint i,j
tt=keyscan()
if(tt==15) //清零
{
write_com(0x01)
tt=0
num=0
a=0
m=0
flag1=0
flag=0
}
if(tt==1) digit(1)
if(tt==2) digit(2)
if(tt==3) digit(3)
if(tt==4) digit(4)
if(tt==5) digit(5)
if(tt==6) digit(6)
if(tt==7) digit(7)
if(tt==8) digit(8)
if(tt==9) digit(9)
if(tt==16)
{
write_com(0x80+a)
write_date(0+'0')
table[a]=0
delay(5)
tt=0
num=0
a++
}
if(tt==10)//检测到加号
{
m=1//表示加法
shu1=0
j=1
write_com(0x80+a)
write_date('+')
delay(5)
flag=a
for(i=flagi>0i--)
{
shu1+=(table[i-1]*j)
j*=10
}
tt=0
num=0
a++
}
if(tt==11)//检测到减号
{
m=2//表示减法
shu1=0
j=1
write_com(0x80+a)
write_date('-')
delay(5)
flag=a
for(i=flagi>0i--)
{
shu1+=(table[i-1]*j)
j*=10
}
tt=0
num=0
a++
}
if(tt==12)//检测到乘号
{
m=3//表示乘法
shu1=0
j=1
write_com(0x80+a)
write_date('*')
delay(5)
flag=a
for(i=flagi>0i--)
{
shu1+=(table[i-1]*j)
j*=10
}
tt=0
num=0
a++
}
if(tt==13)//检测到除号
{
m=4//表示除法
shu1=0
j=1
write_com(0x80+a)
write_date('/')
delay(5)
flag=a
for(i=flagi>0i--)
{
shu1+=(table[i-1]*j)
j*=10
}
tt=0
num=0
a++
}
if(tt==14) //检测到等号
{
flag1=1
write_com(0x80+a)
write_date('=')
shu2=0
j=1
for(i=a-1i>flagi--)
{
shu2+=(table[i]*j)
j*=10
}
num=0
tt=0
}
}
void output()
{
uint value
uchar n
if((m==1)&&(flag1==1))//加的时候
{
value=shu1+shu2
if(value>=0&&value<10)
{
val[0]=value
write_com(0xc0)
for(n=0n<1n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10&&value<100)
{
val[0]=value/10
val[1]=value%10
write_com(0xc0)
for(n=0n<2n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=100&&value<1000)
{
val[0]=value/100
val[1]=value%100/10
val[2]=value%10
write_com(0xc0)
for(n=0n<3n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=1000&&value<10000)
{
val[0]=value/1000
val[1]=value%1000/100
val[2]=value%1000%100/10
val[3]=value%10
write_com(0xc0)
for(n=0n<4n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10000&&value<100000)
{
val[0]=value/10000
val[1]=value%10000/1000
val[2]=value%10000%1000/100
val[3]=value%10000%1000%100/10
val[4]=value%10
write_com(0xc0)
for(n=0n<5n++)
{
write_date(val[n]+'0')
delay(2)
}
}
}
if((m==2)&&(flag1==1))//减的时候
{
value=shu1-shu2
if(value>=0&&value<10)
{
val[0]=value
write_com(0xc0)
for(n=0n<1n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10&&value<100)
{
val[0]=value/10
val[1]=value%10
write_com(0xc0)
for(n=0n<2n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=100&&value<1000)
{
val[0]=value/100
val[1]=value%100/10
val[2]=value%10
write_com(0xc0)
for(n=0n<3n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=1000&&value<10000)
{
val[0]=value/1000
val[1]=value%1000/100
val[2]=value%1000%100/10
val[3]=value%10
write_com(0xc0)
for(n=0n<4n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10000&&value<100000)
{
val[0]=value/10000
val[1]=value%10000/1000
val[2]=value%10000%1000/100
val[3]=value%10000%1000%100/10
val[4]=value%10
write_com(0xc0)
for(n=0n<5n++)
{
write_date(val[n]+'0')
delay(2)
}
}
}
if((m==3)&&(flag1==1))//乘的时候
{
value=shu1*shu2
if(value>=0&&value<10)
{
val[0]=value
write_com(0xc0)
for(n=0n<1n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10&&value<100)
{
val[0]=value/10
val[1]=value%10
write_com(0xc0)
for(n=0n<2n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=100&&value<1000)
{
val[0]=value/100
val[1]=value%100/10
val[2]=value%10
write_com(0xc0)
for(n=0n<3n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=1000&&value<10000)
{
val[0]=value/1000
val[1]=value%1000/100
val[2]=value%1000%100/10
val[3]=value%10
write_com(0xc0)
for(n=0n<4n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10000&&value<100000)
{
val[0]=value/10000
val[1]=value%10000/1000
val[2]=value%10000%1000/100
val[3]=value%10000%1000%100/10
val[4]=value%10
write_com(0xc0)
for(n=0n<5n++)
{
write_date(val[n]+'0')
delay(2)
}
}
}
if((m==4)&&(flag1==1))//除的时候
{
value=shu1/shu2
if(value>=0&&value<10)
{
val[0]=value
write_com(0xc0)
for(n=0n<1n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10&&value<100)
{
val[0]=value/10
val[1]=value%10
write_com(0xc0)
for(n=0n<2n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=100&&value<1000)
{
val[0]=value/100
val[1]=value%100/10
val[2]=value%10
write_com(0xc0)
for(n=0n<3n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=1000&&value<10000)
{
val[0]=value/1000
val[1]=value%1000/100
val[2]=value%1000%100/10
val[3]=value%10
write_com(0xc0)
for(n=0n<4n++)
{
write_date(val[n]+'0')
delay(2)
}
}
if(value>=10000&&value<100000)
{
val[0]=value/10000
val[1]=value%10000/1000
val[2]=value%10000%1000/100
val[3]=value%10000%1000%100/10
val[4]=value%10
write_com(0xc0)
for(n=0n<5n++)
{
write_date(val[n]+'0')
delay(2)
}
}
}
}
@@@@@@@@@双字节整数运算@@@@@@@@@@@@@@@@@@
***********双字节无符号加法**************
入口:R6(H),R7,R4(H),R5,出口:和R6(H),R7(L)
UADD: MOV A,R7
ADD A,R5
MOV R7,A
MOV A,R6
ADDC A,R4
MOV R6,A
RET
***********双字节无符号减法**************
入口:被减数R6(H),R7(L),减数R4(H),R5(L),出口:差R6(H),R7(L)
CLR C
MOV A,R7
SUBB A,R5
MOV R7,A
MOV A,R6
SUBB A,R4
MOV R6,A
RET
***********双字节无符号乘法**************
入口:R6(H),R7(L),R4(H),R5(L),出口:积R6(H),R7(L)
UMUL: MOV A,R7
MOV B,R5
MUL AB
MOV R0,B
XCH A,R7
MOV B,R4
MUL AB
ADD A,R0
XCH A,R6
MOV B,R5
MUL AB
ADD A,R6
MOV R6,A
RET
***********双字节无符号除法*****************
入口:R6(H),R7(L),R4(H),R5(L),出口:商R6(H),R7(L),余R4(H),R5(L)
影响:R2,R3,
堆栈需求:1
UDIV: CLR C
CLR A
MOV R2,A
MOV R3,A
MOV B,#10H
MOVBIT: MOV A,R7R6、R7中数据左移一位到R2、R3中,C到R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R3
RLC A
MOV R3,A
MOV A,R2
RLC A
MOV R2,A
CLR C R2R3-R4R5
MOV A,R3
SUBB A,R5
PUSH Acc
MOV A,R2
SUBB A,R4
JBC Cy,MOVBIT0不够减,清C继续左移
MOV R2,A够减,存回余数并置位C
POP Acc
MOV R3,A
SETB C
SJMP MOVBIT1
MOVBIT0: POP Acc
MOVBIT1: DJNZ B,MOVBIT
MOV A,R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R2
MOV R4,A
MOV A,R3
MOV R5,A
RET
(7) 标号: DIVD 功能:双字节二进制无符号数除法
入口条件:被除数在R2、R3、R4、R5中,除数在R6、R7中。
出口信息:OV=0 时,双字节商在R2、R3中,OV=1 时溢出。
影响资源:PSW、A、B、R1~R7 堆栈需求: 2字节
DIVD: CLR C ;比较被除数和除数
MOV A,R3
SUBB A,R7
MOV A,R2
SUBB A,R6
JC DVD1
SETB OV ;溢出
RET
DVD1: MOV B,#10H ;计算双字节商
DVD2: CLR C ;部分商和余数同时左移一位
MOV A,R5
RLC A
MOV R5,A
MOV A,R4
RLC A
MOV R4,A
MOV A,R3
RLC A
MOV R3,A
XCH A,R2
RLC A
XCH A,R2
MOV F0,C ;保存溢出位
CLR C
SUBB A,R7 ;计算(R2R3-R6R7)
MOV R1,A
MOV A,R2
SUBB A,R6
ANL C,/F0 ;结果判断
JC DVD3
MOV R2,A ;够减,存放新的余数
MOV A,R1
MOV R3,A
INC R5 ;商的低位置一
DVD3: DJNZ B,DVD2 ;计算完十六位商(R4R5)
MOV A,R4 ;将商移到R2R3中
MOV R2,A
MOV A,R5
MOV R3,A
CLR OV ;设立成功标志
RET
//功能 0 1 2 3 4 5 6 7 8 9 + - × ÷ = 清零 表3-1 3.2 计算器的软件设计
#include<reg51.h> //头文件
#define uint unsigned int //
#define uchar unsigned char
sbit lcden=P2^3//定义引脚
sbit rs=P2^4
sbit rw=P2^0
sbit busy=P0^7
char i,j,temp,num,num_1
long a,b,c //a,第一个数 b,第二个数 c,得数
float a_c,b_c
uchar flag,fuhao//flag表示是否有符号键按下,fuhao表征按下的是哪个符号
uchar code table[]={ 7,8,9,0, 4,5,6,0, 1,2,3,0, 0,0,0,0}
uchar code table1[]={
7,8,9,0x2f-0x30,
4,5,6,0x2a-0x30,
1,2,3,0x2d-0x30,
0x01-0x30,0,0x3d-0x30,0x2b-0x30}
void delay(uchar z) // 延迟函数
{
uchar y
for(zz>0z--)
for(y=0y<110y++)
} void check() // 判断忙或空闲
{
do{
P0=0xFF
rs=0 //指令
rw=1 //读
lcden=0 //禁止读写
delay(1)//等待,液晶显示器处理数据
lcden=1 //允许读写
}while(busy==1)//判断是否为空闲,1为忙,0为空闲
}
void write_com(uchar com) // 写指令函数
{
P0=com //com指令付给P0口
rs=0
rw=0
lcden=0
check()
lcden=1
}
void write_date(uchar date) // 写数据函数
{
P0=date
rs=1
rw=0
lcden=0
check()
lcden=1
}
void init() //初始化
{
num=-1
lcden=1//使能信号为高电平
write_com(0x38)//8位,2行
write_com(0x0c)//显示开,光标关,不闪烁*/
write_com(0x06)//增量方式不移位 显竟獗暌贫 柚?
write_com(0x80)//检测忙信号
write_com(0x01)//显示开,光标关,不闪烁
num_1=0
i=0
j=0
a=0 //第一个参与运算的数
b=0 //第二个参与运算的数
c=0
flag=0//flag表示是否有符号键按下,
fuhao=0// fuhao表征按下的是哪个符号
}
void keyscan() // 键盘扫描程序
{
P3=0xfe
if(P3!=0xfe)
{
delay(20)//延迟20ms
if(P3!=0xfe)
{
temp=P3&0xf0
switch(temp)
{
case 0xe0:num=0
break
case 0xd0:num=1
break
case 0xb0:num=2
break
case 0x70:num=3
break
}
}
while(P3!=0xfe)
if(num==0||num==1||num==2)//如果按下的是'7','8'或'9
{
if(j!=0)
{
write_com(0x01)
j=0
}
if(flag==0)//没有按过符号键
{
a=a*10+table[num]
}
else//如果按过符号键
{
b=b*10+table[num]
}
}
else//如果按下的是'/'
{
flag=1
fuhao=4//4表示除号已按
}
i=table1[num]
write_date(0x30+i)
}
P3=0xfd
if(P3!=0xfd)
{
delay(5)
if(P3!=0xfd)
{
temp=P3&0xf0
switch(temp)
{
case 0xe0:num=4
break
case 0xd0:num=5
break
case 0xb0:num=6
break
case 0x70:num=7
break
}
}
while(P3!=0xfd)
if(num==4||num==5||num==6&&num!=7)//如果按下的是'4','5'或'6'
{
if(j!=0)
{
write_com(0x01)
j=0
}
if(flag==0)//没有按过符号键
{
a=a*10+table[num]
}
else//如果按过符号键
{
b=b*10+table[num]
}
}
else//如果按下的是'/'
{
flag=1
fuhao=3//3表示乘号已按
}
i=table1[num]
write_date(0x30+i)
}
P3=0xfbif(P3!=0xfb)
{
delay(5)
if(P3!=0xfb)
{
temp=P3&0xf0
switch(temp)
{
case 0xe0:num=8
break
case 0xd0:num=9
break
case 0xb0:num=10
break
case 0x70:num=11
break
}
}
while(P3!=0xfb)
if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
{
if(j!=0)
{
write_com(0x01)
j=0
}
if(flag==0)//没有按过符号键
{
a=a*10+table[num]
}
else//如果按过符号键
{
b=b*10+table[num]
}
}
else if(num==11)//如果按下的是'-'
{
flag=1
fuhao=2//2表示减号已按
}
i=table1[num]
write_date(0x30+i)
}
P3=0xf7
if(P3!=0xf7)
{
delay(5)
if(P3!=0xf7)
{
temp=P3&0xf0
switch(temp)
{
case 0xe0:num=12
break
case 0xd0:num=13
break
case 0xb0:num=14
break
case 0x70:num=15
break
}
}
while(P3!=0xf7)
switch(num)
{
case 12:{write_com(0x01)a=0b=0flag=0fuhao=0}//按下的是"清零"
break
case 13:{ //按下的是"0"
if(flag==0) //没有按过符号键
{
a=a*10
write_date(0x30)
P1=0
}
else if(flag==1)//如果按过符号键
{
b=b*10
write_date(0x30)
}
}
break
case 14:{j=1
if(fuhao==1){write_com(0x80+0x4f)//按下等于键,光标前进至第二行最后一个显示处
write_com(0x04) //设置从后住前写数据,每写完一个数据,光标后退一格
c=a+b
while(c!=0)
{
write_date(0x30+c%10)
c=c/10
}
write_date(0x3d) //再写"="
a=0b=0flag=0fuhao=0
}
else if(fuhao==2){write_com(0x80+0x4f) //光标前进至第二行最后一个显示处
write_com(0x04) //设置从后住前写数据,每写完一个数据,光标后退一格
//(这个照理说顺序不对,可显示和上段一样)
if(a-b>0)
c=a-b
else
c=b-a
while(c!=0)
{
write_date(0x30+c%10)
c=c/10
}
if(a-b<0)
write_date(0x2d)
write_date(0x3d) //再写"="
a=0b=0flag=0fuhao=0
}
else if(fuhao==3){write_com(0x80+0x4f)
write_com(0x04)
c=a*b
while(c!=0)
{
write_date(0x30+c%10)
c=c/10
}
write_date(0x3d)
a=0b=0flag=0fuhao=0
}
else if(fuhao==4){write_com(0x80+0x4f)
write_com(0x04)
i=0
c=(long)(((float)a/b)*1000)
while(c!=0)
{
write_date(0x30+c%10)
c=c/10
i++
if(i==3)
write_date(0x2e)
}
if(a/b<=0)
write_date(0x30)
write_date(0x3d)
a=0b=0flag=0fuhao=0
}
}
break
case 15:{write_date(0x30+table1[num])flag=1fuhao=1}
break
}
}
}
main()
{
init()
while(1)
{
keyscan()
}
}
纵观单片机的发展过程,可以预示单片机的发展趋势,;1)低功耗CMOS化;MCS-51系列的8051推出时的功耗达630m;2)微型单片化;现在常规的单片机普遍都是将中央处理器(CPU)、;此外,现在的产品普遍要求体积
照程序设计的各部分实现的功能不同,将整个软件系统分成了三个块,并对每一个功能块所采用的元器件进行了详细介绍。此外还编写了主要功能模块的基本程序,详尽阐述了各模块的工作过程。还有总流程图,源代码,硬器件铺线图。
1、硬件仿真图
硬件部分比较简单,当键盘按键按下时它的那一行、那一列的端口为低电平。因此,只要扫描行、列端口是否都为低电平就可以确定是哪个键被按下。
2、主程序流程图
程序的主要思想是:将按键抽象为字符,然后就是对字符的处理。将操作数分别转化为字符串存储,操作符存储为字符形式。然后调用compute()函数进行计算并返回结果。具体程序及看注释还有流程图。
3、Altium Designer画的PCB图
4、程序源代码
#include <reg51.h>#include <intrins.h>
#include <ctype.h>
#include <stdlib.h>
#define uchar unsigned char
#define uint unsigned int
uchar operand1[9], operand2[9]
uchar operator
void delay(uint)
uchar keyscan()
void disp(void)
void buf(uint value)
uint compute(uint va1,uint va2,uchar optor)
uchar code table[] = {0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,0xff}
uchar dbuf[8] = {10,10,10,10,10,10,10,10}
void delay(uint z)
{
uint x,y
for(x=zx>0x--)
for(y=110y>0y--)
}
uchar keyscan()
{
uchar skey
P1 = 0xfe
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xee: skey = '7'break
case 0xde: skey = '8'break
case 0xbe: skey = '9'break
case 0x7e: skey = '/'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xfd
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xed: skey = '4'break
case 0xdd: skey = '5'break
case 0xbd: skey = '6'break
case 0x7d: skey = '*'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xfb
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xeb: skey = '1'break
case 0xdb: skey = '2'break
case 0xbb: skey = '3'break
case 0x7b: skey = '-'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xf7
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xe7: skey = '$'break
case 0xd7: skey = '0'break
case 0xb7: skey = '='break
case 0x77: skey = '+'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
return skey
}
void main()
{
uint value1, value2, value
uchar ckey, cut1 = 0, cut2 = 0
uchar operator
uchar i, bool = 0
init:
buf(0)
disp()
value = 0
cut1 = cut2 = 0
bool = 0
for(i = 0i <9i++)
{
operand1[i] = '\0'
operand2[i] = '\0'
}
while(1)
{
ckey = keyscan()
if(ckey != '#')
{
if(isdigit(ckey))
{
switch(bool)
{
case 0:
operand1[cut1] = ckey
operand1[cut1+1] = '\0'
value1 = atoi(operand1)
cut1++
buf(value1)
disp()
break
case 1:
operand2[cut2] = ckey
operand2[cut2+1] = '\0'
value2 = atoi(operand2)
cut2++
buf(value2)
disp()
break
default: break
}
}
else if(ckey=='+'||ckey=='-'||ckey=='*'||ckey=='/')
{
bool = 1
operator = ckey
buf(0)
dbuf[7] = 10
disp()
}
else if(ckey == '=')
{
value = compute(value1,value2,operator)
buf(value)
disp()
while(1)
{
ckey = keyscan()
if(ckey == '$')
goto init
else
{
buf(value)
disp()
}
}
}
else if(ckey == '$')
{ goto init}
}
disp()
}
}
uint compute(uint va1,uint va2,uchar optor)
{
uint value
switch(optor)
{
case '+' : value = va1+va2 break
case '-' : value = va1-va2 break
case '*' : value = va1*va2 break
case '/' : value = va1/va2 break
default : break
}
return value
}
void buf(uint val)
{
uchar i
if(val == 0)
{
dbuf[7] = 0
i = 6
}
else
for(i = 7val >0i--)
{
dbuf[i] = val % 10
val /= 10
}
for( i >0i--)
dbuf[i] = 10
}
void disp(void)
{
uchar bsel, n
bsel=0x01
for(n=0n<8n++)
{
P2=bsel
P0=table[dbuf[n]]
bsel=_crol_(bsel,1)
delay(3)
P0=0xff
}
}
扩展资料:
PROTEUS 是单片机课堂教学的先进助手
PROTEUS不仅可将许多单片机实例功能形象化,也可将许多单片机实例运行过程形象化。前者可在相当程度上得到实物演示实验的效果,后者则是实物演示实验难以达到的效果。
它的元器件、连接线路等却和传统的单片机实验硬件高度对应。这在相当程度上替代了传统的单片机实验教学的功能,例:元器件选择、电路连接、电路检测、电路修改、软件调试、运行结果等。
课程设计、毕业设计是学生走向就业的重要实践环节。由于PROTEUS提供了实验室无法相比的大量的元器件库,提供了修改电路设计的灵活性、提供了实验室在数量、质量上难以相比的虚拟仪器、仪表,因而也提供了培养学生实践精神、创造精神的平台
随着科技的发展,“计算机仿真技术”已成为许多设计部门重要的前期设计手段。它具有设计灵活,结果、过程的统一的特点。可使设计时间大为缩短、耗资大为减少,也可降低工程制造的风险。相信在单片机开发应用中PROTEUS也能茯得愈来愈广泛的应用。
使用Proteus 软件进行单片机系统仿真设计,是虚拟仿真技术和计算机多媒体技术相结合的综合运用,有利于培养学生的电路设计能力及仿真软件的操作能力;
在单片机课程设计和全国大学生电子设计竞赛中,我们使用 Proteus 开发环境对学生进行培训,在不需要硬件投入的条件下,学生普遍反映,对单片机的学习比单纯学习书本知识更容易接受,更容易提高。
实践证明,在使用 Proteus 进行系统仿真开发成功之后再进行实际制作,能极大提高单片机系统设计效率。因此,Proteus 有较高的推广利用价值。
参考资料来源:百度百科-protues
START:MOV 78H,#0 初始化:78H放0的段码,其余放熄灭码
MOV 79H,#10
MOV 7AH,#10
MOV 7BH,#10
MOV 7CH,#10
MOV 7DH,#10
MOV R5, #0 R5是按键次数,初始置0
MOV 30H,#0 30H是功能键存放单元,置为0
MOV 40H,#0 40H单元初始置为0
MOV 41H,#0 41H单元初始置为0
LOOP:LCALL DIR
LCALL KEY
INC R5
散转程序,判断按下的是哪个键
S1:CJNE A,#10,S2 不是"+"键,跳到S2
LJMP FUN 是"+"键,跳到FUN
S2:CJNE A,#11,S3 不是"-"键,跳到S3
LJMP FUN 是"-"键,跳到FUN
S3:CJNE A,#12,S4 不是"*"键,跳到S4
LJMP FUN 是"*"键,跳到FUN
S4:CJNE A,#13,S5 不是"/"键,跳到S5
LJMP FUN 是"/"键,跳到FUN
S5:CJNE A,#14,S6 不是"="键,跳到S6
LJMP FUN 是"="键,跳到FUN
S6:CJNE A,#15,N1 不是"CL"键,跳到N1
LJMP START 是"CL"键,跳到START
N1:CJNE R5,#1,N2判断第几次按键
LJMP D11
N2:CJNE R5,#2,N3
LJMP T2
N3:CJNE R5,#3,N4
LJMP T3
N4:CJNE R5,#4,N5
LJMP T4
N5:CJNE R5,#5,N6
LJMP T5
N6:CJNE R5,#6,START
LJMP T6
D11:MOV R4,A
MOV 78H,A输入值送显示个位缓存
MOV 79H,#10
MOV 7AH,#10
MOV 7BH,#10
MOV 7CH,#10
MOV 7DH,#10
LJMP LOOP
T2:MOV R7,A
MOV B,#10
MOV A,R4
MUL AB
ADD A,R7
MOV R4,A
MOV 7AH,#10
MOV 7BH,#10
MOV 7CH,#10
MOV 7DH,#10
MOV 79H, 78H 个位到十位
MOV 78H,R7新数为个位
LJMP LOOP
T3:MOV R7,A
MOV B,#10
MOV A,R4
MUL AB
ADD A,R7
MOV R4,A
MOV 7BH,#10
MOV 7CH,#10
MOV 7DH,#10
MOV 7AH,79H 十位到百位
MOV 79H,78H 个位到十位
MOV 78H,R7新数为个位
LJMP LOOP
T4:MOV R7,A
MOV B,#10
MOV A,R4
MUL AB
ADD A,R7
MOV R4,A
MOV 7CH,#10
MOV 7DH,#10
MOV 7BH,7AH
MOV 7AH,79H
MOV 79H,78H
MOV 78H,R7
LJMP LOOP
T5:MOV R7,A
MOV B,#10
MOV A,R4
MUL AB
ADD A,R7
MOV R4,A
MOV 7DH,#10
MOV 7CH,7BH
MOV 7BH,7AH
MOV 7AH,79H
MOV 79H,78H
MOV 78H,R7
LJMP LOOP
T6:MOV R7,A
MOV B,#10
MOV A,R4
MUL AB
ADD A,R7
MOV R4,A
MOV 7DH,7CH
MOV 7CH,7BH
MOV 7BH,7AH
MOV 7AH,79H
MOV 79H,78H
MOV 78H,R7
LJMP LOOP
MOV 7CH,7BH
MOV 7BH,7AH
MOV 7AH,79H
MOV 79H,78H
MOV 78H,R7
LJMP LOOP
FUN:MOV 78H,#10
MOV 79H,#10
MOV 7AH,#10
MOV R0,30H 与上次功能键交换
MOV 30H,A
MOV A,R0
CJNE A,#10,FUN1判断功能键
LJMP ADDY "+"
FUN1:CJNE A,#11,FUN2
LJMP SUBT "-"
FUN2:CJNE A,#12,FUN3
LJMP MULT "*"
FUN3:CJNE A,#13,FUN4
LJMP DIVI "/"
FUN4:CJNE A,#14,FUN5 首次按功能键,即A=#0
LJMP EQUA "="
FUN5:MOV 40H,R4 保存第一个数
MOV R5,#0按键次数清零
LJMP BCD 将其拆为bcd码,以便后来将其显示
OF:LJMP START 溢出处理
ADDY:MOV A,40H 第一个数送累加器
ADD A,R4 第一个数加第二个数
JB CY,OF 溢出
MOV 40H,A 存本次结果
MOV R5,#0 按键次数清零
LJMP BCD
SUBT:MOV A,40H
SUBB A,R4
JB CY,OF
MOV 40H,A
MOV R5,#0
LJMP BCD
MULT:MOV A,40H
MOV B,A
MOV A,R4
MUL AB
JB OV,OF
MOV 40H,A
MOV R5,#0
LJMP BCD
DIVI:MOV A,R4
MOV B,A
MOV A,40H
DIV AB
JB OV,OF
MOV 40H,A
MOV R5,#0
LJMP BCD
EQUA:MOV R5,#0
LJMP BCD
BCD:MOV B,#10
MOV A,40H 结果送累加器
DIV AB 结果除10
MOV 41H,A 暂存"商"
MOV A,B 取个位数
MOV 78H,A 个位数送显示缓存
MOV A,41H
JZ RETURN 结果是一位数,返回LOOP
MOV B,#10
MOV A,41H
DIV AB
MOV 41H,A
MOV A,B
MOV 79H,A 十位送显示缓存
MOV A,41H
JZ RETURN结果是二位数,返回LOOP
MOV 7AH,A 百位数送显示缓存
RETURN:LJMP LOOP
动态显示子程序
DIR:MOV DPTR,#TAB 数码管译码表首址
MOV R0,#78H 待显缓冲区个位地址
MOV A,#0FEH个位位选信号
MOV R1,A
LD1:MOV A,@R0
MOVC A,@A+DPTR 查表
MOV P2,R1 共阳极管字位选择送到P2口
MOV P0,A 字段码送P0口
LCALL DELAY1ms 调延时1ms 子程序
INC R0 R0指向下一模块
MOV A,R1
JNB ACC.5,LD2 判断是否发完6个数
RL A 指向下一个位
MOV R1,A 位选信号存回R3
SJMP LD1 跳去再显示下一个数
LD2:RET发完6个数就返回
TAB:DB 0C0H,0F9H,0A4H,0B0H,099H,092H,082H,0F8H,80H,90H,0FFH 共阳极译码表
DELAY1ms:MOV R6,#2
LOOP1:MOV R7,#248
NOP
LOOP2:DJNZ R7,LOOP2
DJNZ R6,LOOP1
RET
KEY:LCALL KS调用检测按键子程序
JNZ K1 有键按下继续
LCALL DELAY2无键按调用延时去抖
ACALL DIR 调用动态显示
AJMP KEY返回继续检测按键
K1:LCALL DELAY2 有键按下延时去抖动
LCALL KS 再调用检测按腱子程序
JNZ K2 确认有按键进行下一步
ACALL DIR调用动态显示
AJMP KEY 无键按下返回继续检测
K2:MOV R2,#0EFH 将扫描值送入R2暂存
MOV R3,#00H 将第一列值送入R3暂存
K3:MOV P1,R2将R2值送入P1口
L0:JB P1.0,L1 P1.0等于1跳转到L1
MOV A,#00H 将第一行值送入ACC
AJMP LK 跳转到键值处理程序
L1:JB P1.1,L2 P1.1等于1跳转到L2
MOV A,#04H 将第二行的行值送入ACC
AJMP LK 跳转到键值处理程序
L2:JB P1.2,L3 P1.2等于1跳转到L3
MOV A,#08H 将第三行行值送入ACC
AJMP LK 跳转到键值处理程序
L3:JB P1.3,NEXT P1.3等于1跳转到NEXT处
MOV A,#0CH 将第四行行值送入ACC
LK:ADD A,R3 行值与列值相加后的键值送入A
PUSH ACC 将A中的值送入堆栈暂存
K4:LCALL DELAY2 调用延时去抖程序
LCALL KS 调用按键检测程序
JNZ K4 按键没有松开继续返回检测
POP ACC 将堆栈值送入ACC
MOV DPTR,#KEYTAB
MOVC A,@A+DPTR
RET
NEXT:INC R3 列值加一
MOV A,R2 R2值送入A
JNB ACC.7,KEY 扫描完至KEY处进行下一扫描
RL A 扫描未完将值左移一位进行下一列扫描
MOV R2,A 将ACC值送入R2暂存
AJMP K3跳转到K3继续
KS:MOV P1,#0FH 将P1口高四位置0低四位置1
MOV A,P1 读P1口
XRL A,#0FH 将A中的值与A中的值相异或
RET 子程序返回
KEYTAB:DB 1,2,3,10,4,5,6,11,7,8,9,12,15,0,14,13 键值表
DELAY2:MOV R6,#2H 延时去抖动子程序
LP1:MOV R7,#0FAH
LP2:DJNZ R7,LP2
DJNZ R6,LP1
RET
END