【说明】
这是嵌入式课程的一个小作业,用C51单片机,实现了0-255内的简易四则运算,暂不支持负数、溢出等特殊情况的处理。
【关键点】
1、计算器用R5、R6、R7三位显示,段码为0,全暗,段码为0xff,全亮。
2、R3用于保存运算符
3、两数都用B压入栈中,最后取结果时可以分别弹出,并根据操作符计算。
4、程序在两数的第一位默认都输入数字,其他位置皆可复位。
5、一次计算完成后、按任意键复位。
【键盘位置】
代码:
;3位0-255计算器,支持四则运算
;按键有0-9、+、-、*、/、复位、=
;R5,R6,R7分别用于显示三位
;暂不支持负数、溢出处理
ORG 0000H
LJMP START
WC EQU P0 ;数码管位控
DC EQU P1 ;数码管段控
KC EQU P2 ;键盘检测
ORG 0030H
START:
MOV R5, #0
MOV R6, #0
MOV R7, #0
N1_B1:
ACALL KEYDOWN
CJNE R4, #0x10, PRO1 ;检测到按键做相应处理
ACALL DISPLAY
JMP N1_B1 ;否则继续检测
PRO1:
MOV A, R4
MOV R0, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R5, A
N1_B2:
ACALL DISPLAY
ACALL KEYDOWN
CJNE R4, #0x10, PRO2 ;检测按键,有键按下做相应处理
JMP N1_B2
PRO2:
MOV A, R4
ACALL JUDGE_OPER ;检查是否为操作符
CJNE R3, #0x04, CON1 ;是清除键,直接复位
JMP START
CON1:
CJNE R3, #0x06, PRO3 ;是操作符,跳转到PRO3
MOV A, R4 ;是数字
MOV R1, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R6, A
MOV R4, #0x10
JMP N1_B3
PRO3:
MOV B, R0 ;将num1的结果保存在B中
PUSH B
JMP N2_B1 ;转去判断第2个数的第1位
N1_B3:
ACALL DISPLAY ;第1个数字第3位
ACALL KEYDOWN
CJNE R4, #0x10, PRO4 ;检测按键,有键按下做相应处理
JMP N1_B3
PRO4:
MOV A, R4
ACALL JUDGE_OPER ;检查是否为操作符
MOV A, R3
CJNE A, #0x04, CON2 ;是清除键,直接复位
JMP START
CON2:
CJNE A, #0x06, PRO5 ;等于则是数字,不等于则是操作符
MOV A, R4 ;是数字
MOV R2, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R7, A
MOV A, R0 ;保留第1位数
MOV B, #100D
MUL AB
MOV R0, A ;将百位保留在R0
MOV A, R1 ;保留第2位数
MOV B, #10D
MUL AB
MOV R1, A ;将十位保留在R1
MOV A, R2 ;相加
ADD A, R1
ADD A, R0
MOV B, A ;将第1位数先存在B中
PUSH B
JMP OPER
PRO5:
MOV A, R0
MOV B, #10D
MUL AB
MOV R0, A
MOV A, R1
ADD A, R0
MOV B, A
PUSH B
JMP N2_B1
OPER:
ACALL DISPLAY
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, PRO6 ;有键按下
JMP OPER
PRO6:
MOV A, R4
ACALL JUDGE_OPER
MOV A, R3
CJNE A, #0x04, N2_B1 ;不等于是操作符,等于是复位键
JMP START
N2_B1:
ACALL DISPLAY ;第2个数第1位
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, PRO7 ;有键按下
JMP N2_B1
PRO7:
MOV A, R4 ;保留原有操作符
PUSH 0x03 ;保存R3中的操作符标记
ACALL JUDGE_OPER
MOV A, R3
POP 0x03
CJNE A, #0x04, CON3 ;判断是否是复位键
JMP START
CON3:
MOV A, R4
MOV R0, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R5, A
MOV R6, #0x00 ;清除后两位显示
MOV R7, #0X00
N2_B2:
ACALL DISPLAY
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, PRO8 ;有键按下
JMP N2_B2
PRO8:
MOV A, R4 ;保留原有操作符
PUSH 0x03 ;保存R3中的操作符标记
ACALL JUDGE_OPER
MOV A, R3
POP 0x03
CJNE A, #0x04, CON4 ;不是清除键继续判断
JMP START
CON4:
CJNE A, #0x06, PRO9 ;不相等说明是操作符,相等说明是数字
MOV A, R4
MOV R1, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R6, A
JMP N2_B3
PRO9:
CJNE A, #0x05, MIDNODE ;不是等于号,出错返回
MOV A, R0
MOV B, A
PUSH B
JMP EDIS
N2_B3:
ACALL DISPLAY
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, PRO10
JMP N2_B3
PRO10:
MOV A, R4 ;保留原有操作符
PUSH 0x03 ;保存R3中的操作符标记
ACALL JUDGE_OPER
MOV A, R3
POP 0x03
CJNE A, #0x04, CON5 ;不是清除键继续判断
JMP START
CON5:
CJNE A, #0x06, PRO11 ;不相等说明是操作符
MOV A, R4
MOV R2, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R7, A
MOV A, R0
MOV B, #100D
MUL AB
MOV R0, A
MOV A, R1
MOV B, #10D
MUL AB
MOV R1, A
MOV A, R2
ADD A, R1
ADD A, R0
MOV B, A
PUSH B
JMP AK
MIDNODE:
JMP START
PRO11:
CJNE A, #0x05, MIDNODE ;通过中继节点返回
MOV B, #10D
MOV A, R0
MUL AB
ADD A, R1
MOV B, A
PUSH B
JMP EDIS
AK:
ACALL DISPLAY
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, EDIS
JMP AK
EDIS:
POP B
MOV A, B
POP B
MOV R0, A ;交换AB
MOV A, B
MOV B, R0
MOV R1, A
MOV A, R3
CJNE A, #0x00, NXT1 ;通过R3的值,判断运算符
MOV A, R1 ;并进行相应运算
ADD A, B
JMP TS
NXT1:
CJNE A, #0x01, NXT2
MOV A, R1
SUBB A, B
JMP TS
NXT2:
CJNE A, #0x02, NXT3
MOV A, R1
MUL AB
JMP TS
NXT3:
CJNE A, #0x03, MIDNODE
MOV A, R1
DIV AB
TS: ;转换显示
MOV R0, A
MOV B, #100D
DIV AB
MOV R1, A
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R5, A
MOV A, B
MOV B, #10D
DIV AB
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R6, A
MOV A, B
MOV DPTR, #DCODE
MOVC A, @A+DPTR
MOV R7, A
RESTART:
ACALL DISPLAY
ACALL KEYDOWN
MOV A, R4
CJNE A, #0x10, MIDNODE
JMP RESTART
;按键检测程序,若有键按下,返回0-15,无键按下返回16
KEYDOWN:
MOV R4, #0x10
MOV KC, #0x0F
MOV A, KC
CJNE A, #0X0F, PRO ;检测列
RET
PRO:
ACALL DELAY ;延时消抖
MOV A, KC
CJNE A, #0X0F, COL ;确认有键按下
RET
COL:
COL1:
MOV A, KC
CJNE A, #0X07, COL2 ;判断哪一列
MOV R4, #0H
JMP ROW
COL2:
CJNE A, #0X0B, COL3
MOV R4, #4H
JMP ROW
COL3:
CJNE A, #0X0D, COL4
MOV R4, #8H
JMP ROW
COL4:
CJNE A, #0X0E, BACK ;没有列被按下,直接返回
MOV R4, #0CH
ROW:
MOV KC, #0XF0 ;行检测
MOV A, KC
ROW1:
CJNE A, #0X70, ROW2
MOV A, R4
ADD A, #3H
MOV R4, A
JMP BACK
ROW2:
CJNE A, #0XB0, ROW3
MOV A, R4
ADD A, #2H
MOV R4, A
JMP BACK
ROW3:
CJNE A, #0XD0, ROW4
MOV A, R4
ADD A, #1H
MOV R4, A
JMP BACK
ROW4:
BACK:
MOV A, R4
CJNE A, #0x10, DY
RET
DY:
ACALL DELAY
ACALL DELAY
ACALL DELAY
ACALL DELAY
RET
;数码管显示3位数字,分别存在R5,R6,R7
DISPLAY:
PUSH 0x00
PUSH 0x01
MOV R0, #0
;输出位码
MOV DPTR, #WCODE
MOV A, R0
MOVC A, @A+DPTR
MOV WC, A
;输出段码
MOV A, R5
MOV DC, A
MOV R1, #0x0f
LP1:
;延长单位显示时间
DJNZ R1, LP1
MOV DC, #0
INC R0
;输出位码
MOV DPTR, #WCODE
MOV A, R0
MOVC A, @A+DPTR
MOV WC, A
;输出段码
MOV A, R6
MOV DC, A
MOV R1, #0x0f
LP2:
;延长单位显示时间
DJNZ R1, LP2
MOV DC, #0
INC R0
;输出位码
MOV DPTR, #WCODE
MOV A, R0
MOVC A, @A+DPTR
MOV WC, A
;输出段码
MOV A, R7
MOV DC, A
MOV R1, #0x0f
LP3:
;延长单位显示时间
DJNZ R1, LP3
MOV DC, #0
POP 0x01
POP 0x00
RET
;判断A中是什么操作符,+ — * / reset =分别对应R3中的值为0-5,
;若不是操作符,则R3中的值被设置为6
JUDGE_OPER:
MOV R3, #6
AD:
CJNE A, #0x0a, SB ;不是加号,跳到减号
MOV R3, #0 ;0代表加法
RET
SB:
CJNE A, #0x0b, ML ;不是减号,跳到乘号
MOV R3, #1 ;1代表减法
RET
ML:
CJNE A, #0x0c, DV ;不是乘号,跳到除号
MOV R3, #2 ;2代表乘法
RET
DV:
CJNE A, #0x0d, CL ;不是除号,跳到清除键
MOV R3, #3 ;3代表除法
RET
CL:
CJNE A, #0x0e, EU ;不是清除键,跳到等号
MOV R3, #4 ;4代表清除键
RET
EU:
CJNE A, #0x0f, FN ;不是等号,返回
MOV R3, #5 ;5代表等号
FN:
RET
;延时程序
DELAY:
PUSH 0x00 ;保护现场,R0,R1
PUSH 0x01
MOV R0, #96H
LP4:
MOV R1, #82H
LP5:
DJNZ R1, LP5
DJNZ R0, LP4
POP 0x01 ;还原现场
POP 0x00
RET
WCODE: DB 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f ;位码
DCODE: DB 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f ;段码
NUM1: DB 0xff,0xff,0xff ;操作数1
NUM2: DB 0xff,0xff,0xff ;操作数2
END