【说明】
这是嵌入式课程的一个小作业,用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