建材秒知道
登录
建材号 > 设计 > 正文

单片机简易计算器设计的程序

哭泣的外套
大力的水杯
2023-01-25 09:59:11

单片机简易计算器设计的程序

最佳答案
可爱的黑裤
刻苦的歌曲
2026-05-10 19:50:56

展开全部

首先会按键扫描,再会数码管或液晶屏显示,基本上可以了

程序

流程:

扫描按键(最多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()

}

}

最新回答
傻傻的吐司
鳗鱼金鱼
2026-05-10 19:50:56

下面是我以前写的一个简单的计算器的程序,你可以参考参考

#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)

}

}

}

}

靓丽的发箍
痴情的樱桃
2026-05-10 19:50:56
给你些子程序,自己看着凑吧。呵呵。有了这些,写出来应该不难了。

@@@@@@@@@双字节整数运算@@@@@@@@@@@@@@@@@@

***********双字节无符号加法**************

入口: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

从容的羽毛
秀丽的钢笔
2026-05-10 19:50:56

//功能 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()

}

}

疯狂的帆布鞋
正直的芒果
2026-05-10 19:50:56
您好,这样的:

纵观单片机的发展过程,可以预示单片机的发展趋势,;1)低功耗CMOS化;MCS-51系列的8051推出时的功耗达630m;2)微型单片化;现在常规的单片机普遍都是将中央处理器(CPU)、;此外,现在的产品普遍要求体积

照程序设计的各部分实现的功能不同,将整个软件系统分成了三个块,并对每一个功能块所采用的元器件进行了详细介绍。此外还编写了主要功能模块的基本程序,详尽阐述了各模块的工作过程。还有总流程图,源代码,硬器件铺线图。

激动的中心
烂漫的板栗
2026-05-10 19:50:56

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

闪闪的仙人掌
小巧的冬日
2026-05-10 19:50:56
ORG 0000H

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