找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1341|回复: 4
收起左侧

基于51单片机实现的汇编语言的带优先级计算的简易计算器 带优先级,蜂鸣器存在些许问题

[复制链接]
ID:1085458 发表于 2023-6-30 22:35 | 显示全部楼层 |阅读模式
51hei.gif

        ORG 0000H
        LED EQU P2.0;P2.0控制的LED(RP9,8,D1)
        RW EQU P2.5;RW等值P2.5(读写控制位)
        RS EQU P2.6;RS等值P2.6(数据/指令控制位)
        E  EQU P2.7; E等值P2.7(使能控制位)
        BR EQU P2.5;BR等值P2.5(蜂鸣器)
        ON EQU P3.3;开机键等值P3.3
        OFF EQU P3.2;关机键等值P3.2
        POSITION EQU 30H;LM016L第一行的行地址
        TEMPORARY0 EQU 40H;数据临时存放0
        TEMPORARY1 EQU 41H;数据临时存放1
        TEMPORARY2 EQU 42H;数据临时存放2
        TEMPORARY3 EQU 43H;数据临时存放3
        TEMPORARY4 EQU 44H;数据临时存放4
        TEMPORARY5 EQU 45H;数据临时存放5
        TEMPORARY6 EQU 46H;数据临时存放6
        TEMPORARY7 EQU 47H;数据临时存放7
        POINTER EQU 48H;转换后的数据储存的范围
        DATA0 EQU 50H;运算位0,储存符号前一位的数据
        DATA1 EQU 51H;运算位1,储存符号后一位的数据
        DATA2 EQU 52H;运算位2,在RESULT子程序中使用
        DATA3 EQU 53H;运算位3,在乘除法的命令中使用
        ANDS EQU 54H;结果存储
        LJMP MAIN
        ORG 0300H
/*初始化LM016L的屏幕设置,该部分的功能包括:
        LM016L两行显示,每行8个字模,开启光标,但光标不闪烁,在输入字模时,屏幕不会随着输入移位,在输入前清除屏幕显示,同时关闭蜂鸣器*/
MAIN:
        SETB LED;关闭LED
        CLR BR;初始化蜂鸣器的状态,关闭蜂鸣器
        MOV A,#38H;8位,2行,5*10点阵/字符
        LCALL COMMAND_WRITTING
        MOV A,#0EH;整体显示,开光标,光标不闪烁
        LCALL COMMAND_WRITTING                                                                                 
        MOV A,#06H;设定输入方式,增量不移位
        LCALL COMMAND_WRITTING
        MOV A,#01H;清除屏幕显示
        LCALL COMMAND_WRITTING
        MOV POSITION,#0FFH;设定POSITION的初始地址
        MOV R0,#70H;存储输入的数据,储存空间为70H~7FH
        MOV R1,#80H;修改输入的数据,储存空间为80H~100H
        MOV ANDS,#00H;初始化结果存储
        AJMP DISPLAY;隔离指令
/*LM016L显示功能部分,该部分的功能包括:
        判断是否超过屏幕最大显示范围,执行清屏指令,执行等于指令,输出按键对应的字模*/
DISPLAY:        
                LCALL RANGE;判断是否超出第一行最大显示范围
                LCALL KEYS
                MOV DPTR,#TABLE;将字码表传送给DPTR
                MOVC A,@A+DPTR ;查表指令,A中储存相应字码
                JNZ WRITE;检查A是否为00H,如果是则说明需执行AC或=操作
                LCALL DELAY;等待按键重新按下
                LJMP DISPLAY
                WRITE:
                        LCALL DATA_WRITTING;向P0口写数
                        LCALL DELAY
                        INC POSITION;记录当前的地址,并同时记录指令执行的次数
                        MOV @R0,A;将输入的字模放入R0中储存起来了
                        INC R0;R0的地址加1
                        AJMP DISPLAY
KEYS:
        JNB ON,STEP0;如果ON键按下,P3.0为低电平
        JNB OFF,STEP1;如果OFF键按下,P3.1为低电平
        AJMP STEP2;隔离指令
STEP0:
        LCALL ON_SET
        AJMP STEP2;隔离指令
STEP1:
        LCALL OFF_SET
        AJMP STEP2;隔离指令
STEP2:
        MOV P1,#0FH;将P1口拉高电平
        MOV A,P1;读P1口的状态
        ANL A,#0FH;屏蔽高四位
        MOV B,A;将A中的内容放入B中保护
        MOV P1,#0F0H;将行线输出为1,列线输出为0
        MOV A,P1;读P1口的状态
        ANL A,#0F0H;屏蔽第四位
        ORL A,B;将两次高4位,低4位合并,即为键码        
        CJNE A,#0FFH,KEYPR0;不相等则有键按下,跳转至KEYPR0
        LCALL DELAY
        SJMP KEYS;防止输出方块字符
        KEYPR0:
                MOV B,A;暂存键码
                LJMP CLEAR
        TEMP:
                LJMP EQUAL
        KEY0:
                MOV DPTR,#KEYVALUE;将KEYVALUE的表头给DPTR
                MOV R3,#0FFH;R3置初值
        KEY1:
                INC R3;键号加1
                MOV A,R3;将键号传送给A
                MOVC A,@A+DPTR;查表指令
                CJNE A,B,KEY2;查得的键码与B中暂存的键码不相等,转到KEY2
                LCALL BUZZER;响铃一声
                MOV A,R3;查得的键码与B中暂存的键码相等,转存到A
                RET
        KEY2:
                CJNE A,#00H,KEY1;A≠0,转到KEY1,进行查键码
                RET;A=0,键盘异常,返回主程序
//执行运算子程序
EQUAL:
        CJNE A,#0EDH,KEY0;查询是否为等于指令
        MOV A,#0C8H;给定下一个将要写入的DDRAM地址
        LCALL COMMAND_WRITTING
        MOV A,#3DH;输入等号
        LCALL DATA_WRITTING
        LCALL BUZZER;响铃一声
        INC POSITION;计数次数加1
        MOV R0,#70H;将储存空间指向70H
        LCALL COUNT;记录并修改数据
        LCALL SIGN_SCAN;跳转至SIGN_SCAN子程序
        MOV POSITION,#00H;初始化POSITION的地址
        MOV A,#80H;从第一行首地址重新点亮字码
        LCALL COMMAND_WRITTING
EQUAL0:
        MOV R0,#70H;将储存空间指向70H
        MOV R4,#30H;计数次数,此处的计数次数为最大计数空间,从70H一直到9FH
        RET_SET0:
                MOV @R0,#00H
                INC R0
                DJNZ R4,RET_SET0        
        MOV R0,#70H;将储存空间指向70H
        MOV R1,#80H;将修改空间指向80H
        LJMP DISPLAY;返回至调用口
//执行清屏子程序
CLEAR:
        CJNE A,#0E7H,TEMP;查询是否为清屏指令
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV ANDS,#00H;初始化结果存储
        MOV A,#80H;从第一行首地址重新点亮字码
        LCALL COMMAND_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        MOV A,#45H;输入E
        LCALL DATA_WRITTING
        MOV A,#53H;输入S
        LCALL DATA_WRITTING
        MOV A,#54H;输入T
        LCALL DATA_WRITTING
        MOV A,#41H;输入A
        LCALL DATA_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        MOV A,#54H;输入T
        LCALL DATA_WRITTING
        LCALL DELAY
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV POSITION,#00H;初始化POSITION的地址
        MOV A,#80H;从第一行首地址重新点亮字码
        LCALL COMMAND_WRITTING
        LCALL BUZZER;响铃一声
        LCALL BUZZER;响铃两声
        MOV ANDS,#00H;初始结果储存
        MOV R0,#70H
        MOV R4,#30H;计数次数
        RET_SET1:
                MOV @R0,#00H
                INC R0
                DJNZ R4,RET_SET1        
        MOV R0,#70H;将储存空间指向70H
        MOV R1,#80H;将修改空间指向80H
        LJMP DISPLAY;返回至调用口
//打开单片机
ON_SET:
        MOV A,#0EH;打开显示功能,有光标且光标不闪烁
        LCALL COMMAND_WRITTING
        MOV A,#57H;输入W
        LCALL DATA_WRITTING
        MOV A,#45H;输入E
        LCALL DATA_WRITTING
        MOV A,#4CH;输入L
        LCALL DATA_WRITTING
        MOV A,#43H;输入C
        LCALL DATA_WRITTING
        MOV A,#4FH;输入O
        LCALL DATA_WRITTING
        MOV A,#4DH;输入M
        LCALL DATA_WRITTING
        LCALL DELAY
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        RET
//关闭单片机
OFF_SET:
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV A,#09H;关闭显示功能,无光标且光标不闪烁
        LCALL COMMAND_WRITTING
        RET
//超过第一行最大显示范围报错
RANGE:
        MOV A,POSITION;将当前显示地址装入A中
        CJNE A,#10H,NON_RANGE;判断当前POSITION是否为10H,如果是则说明超过范围,输出RANGE并光标归位
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV A,#4FH;输入O
        LCALL DATA_WRITTING
        MOV A,#46H;输入F
        LCALL DATA_WRITTING
        MOV A,#46H;输入F
        LCALL DATA_WRITTING
        MOV A,#20H;输入空
        LCALL DATA_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        MOV A,#41H;输入A
        LCALL DATA_WRITTING
        MOV A,#4EH;输入N
        LCALL DATA_WRITTING
         MOV A,#47H;输入G
        LCALL DATA_WRITTING
        MOV A,#45H;输入E
        LCALL DATA_WRITTING
        LCALL DELAY
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV POSITION,#0FFH;初始化POSITION的地址
        MOV A,#80H;从第一行首地址重新点亮字码
        LCALL COMMAND_WRITTING
        RET;返回调用程序处
//未超出范围,跳转至NON_RANGE
NON_RANGE:
        RET
//报错程序
ERROR:
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV A,#45H;输入E
        LCALL DATA_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        MOV A,#4FH;输入O
        LCALL DATA_WRITTING
        MOV A,#52H;输入R
        LCALL DATA_WRITTING
        LCALL BUZZER;响铃一声
        LCALL BUZZER;响铃一声
        LCALL BUZZER;响铃一声
        LCALL LIGHT;闪烁
        LCALL DELAY
        MOV A,#01H;清屏指令
        LCALL COMMAND_WRITTING
        MOV POSITION,#0FFH;初始化POSITION的地址
        MOV A,#80H;从第一行首地址重新点亮字码
        LCALL COMMAND_WRITTING
        LJMP EQUAL0;打断执行        
/*LM016L的计算功能部分,该部分的功能包括:
        判断并转换数据格式,单次运算实现小数点后两位,连续运算实现取整数,带优先级*/
//记录并修改数据,将输入的数据字模转换为包含十位与个位的数据形式,字符字模不变,由R0导入到R1中,eg:7+89→07+89
COUNT:
        MOV A,@R0;取出存储的字模
        INC R0;R0的地址加1,进入下一个字模的地址
        AJMP DIGIT0
        DIGIT0:
                MOV TEMPORARY0,A;将LM016L显示的字模送入TEMPORARY0中保护起来
                ANL A,#0F0H;屏蔽低四位,如果为30H说明是数据,如果为20H,说明是字符
                CJNE A,#20H,INTEGER0;判断为数据转移到INTEGER0
                MOV @R1,TEMPORARY0;存放字符
                INC R1;R1的地址加1
                DJNZ POSITION,COUNT;计数指针不为0,继续执行
                AJMP INTEGER1
        INTEGER0:
                MOV A,@R0;取出下一个存储的字模
                CJNE A,#00H,DIGIT1;下一个字符如果为空,说明为一位数
                AJMP ONE_DIGIT
        DIGIT1:
                MOV TEMPORARY1,A;将LM016L显示的下一位字模送入TEMPORARY1中保护起来
                ANL A,#0F0H;屏蔽低四位,如果为30H说明是数据,如果为20H,说明是字符
                CJNE A,#20H,DIGIT2;判断为数据转移到DIGIT2
                AJMP ONE_DIGIT
        ONE_DIGIT:
                MOV @R1,#00H;百位为0
                INC R1;R1的地址加1
                MOV @R1,#00H;十位为0
                INC R1;R1的地址加1
                MOV A,TEMPORARY0;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;个位为数
                INC R1;R1的地址加1
                DJNZ POSITION,COUNT;计数指针不为0,继续执行
                AJMP INTEGER1
        DIGIT2:
                INC R0;R0的地址再次加1,跳过下一个数
                MOV A,@R0;将进位两次后的地址赋给A
                MOV TEMPORARY2,A;将LM016L显示的下下个字模送入TEMPORARY2中保护起来
                CJNE A,#00H,DIGIT3;下一个字符如果为空,说明为两位数
                AJMP TWO_DIGIT                 
        DIGIT3:
                ANL A,#0F0H;屏蔽低四位,如果为30H说明是数据,如果为20H,说明是字符
                CJNE A,#20H,THREE_DIGIT;判断为数据转移到THREE_DIGIT
                AJMP TWO_DIGIT
        TWO_DIGIT:
                MOV @R1,#00H;百位为0
                INC R1;R1的地址加1
                MOV A,TEMPORARY0;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;十位为数
                INC R1;R1的地址加1
                MOV A,TEMPORARY1;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;个位为数
                INC R1;R1的地址加1
                DJNZ POSITION,COUNT;计数指针不为0,继续执行
                AJMP INTEGER1
        THREE_DIGIT:
                MOV A,TEMPORARY0;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;百位为数
                INC R1;R1的地址加1
                MOV A,TEMPORARY1;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;十位为数
                INC R1;R1的地址加1
                MOV A,TEMPORARY2;将数据取出
                ANL A,#0FH;屏蔽高四位,得出对应的显示数字
                MOV @R1,A;个位为数
                INC R1;R1的地址加1
                INC R0;R0的地址加1,跳过下一个数
                DJNZ POSITION,COUNT;计数指针不为0,继续执行
                AJMP INTEGER1
        INTEGER1:
        RET
//从左往右,按优先级依次判断执行运算操作类型
SIGN_SCAN:
//乘除计算
                MOV POINTER,#30H;记录计数次数
                MOV R1,#80H;初始化地址
                MOV ANDS,#00H;初始化结果存储
                AJMP SCAN0;隔离指令
        SCAN0:
                MOV A,@R1;传送数据给A               
                INC R1;R1的地址加1
                MOV TEMPORARY5,A;保护数据
                ANL A,#0F0H;屏蔽低四位
                CJNE A,#20H,SIGN2;如果是20H,说明为符号,反之则返回
                AJMP RITE0
        RITE0:
                DEC R1;R1回退并指向符号         
                MOV A,TEMPORARY5;取出数据
                MOV B,#05;给B赋5
                ANL A,#0FH;屏蔽高四位
                DIV AB;商放在A,余数放在B
                MOV A,B;传递余数
                CJNE A,#00H,INSTRUCTION;如果余数为0,说明是乘除指令,如果余数不为0,说明是加减指令,返回
                AJMP INSTRUCTION0;隔离指令
        INSTRUCTION0:
                MOV A,TEMPORARY5;取出数据
                CJNE A,#2AH,SIGN0;乘法判别
                LCALL CALCULATE_MULTIPLICATION;跳转乘法处理运算
                INC R1;地址指针加1
                AJMP SIGN2
        SIGN0:
                CJNE A,#2FH,SIGN2;除法判别
                LCALL CALCULATE_DIVISION;跳转除法处理运算
                INC R1;地址指针加1
                AJMP SIGN2
        INSTRUCTION:
                INC R1;地址指针加1
                AJMP SIGN2
           SIGN2:
                DJNZ POINTER,SCAN0;指针减1不为0继续计算

//加减计算
                MOV POINTER,#30H;记录计数次数
                MOV R1,#80H;初始化地址
        SCAN3:
                MOV A,@R1;传送数据给A               
                INC R1;R1的地址加1
                MOV TEMPORARY5,A;保护数据
                ANL A,#0F0H;屏蔽低四位
                CJNE A,#20H,SIGN4;如果是20H,说明为符号,反之则返回
                DEC R1;R1回退并指向符号         
                MOV A,TEMPORARY5;取出数据
                CJNE A,#2BH,SIGN3;加法判别
                LCALL CALCULATE_ADDITION;跳转加法处理运算
                INC R1;地址指针加1
                AJMP SIGN4
        SIGN3:
                CJNE A,#2DH,SIGN4;减法判别
                LCALL CALCULATE_SUBTRACTION;跳转减法处理运算
                INC R1;地址指针加1
                AJMP SIGN4
           SIGN4:
                DJNZ POINTER,SCAN3;指针减1不为0继续计算
                LCALL RESULT
        RET
//加法子程序
CALCULATE_ADDITION:
        LCALL ANTI;转换数据并放在DATA0与DATA1中
        MOV A,DATA0;将DATA0的数据存放在A中
        ADD A,DATA1;进行加法运算
        MOV ANDS,A;将加法计算的结果存储在ANDS中
        LCALL SORT;重新排序        
        RET
//减法子程序
CALCULATE_SUBTRACTION:
        LCALL ANTI;转换数据并放在DATA0与DATA1中
        MOV A,DATA0
        CLR C
        SUBB A,DATA1;DATA0减去DATA1
        JC NEGATIVE;判断DATA0和DATA1的大小
        MOV ANDS,A;将减法计算的结果存储在ANDS中
        LCALL SORT;重新排序        
        RET
//负数,用DATA1减去DATA0
NEGATIVE:
        LJMP ERROR;报错
        RET
/*
NEGATIVE:
        MOV A,#2DH;输入负号
        LCALL DATA_WRITTING
        MOV A,DATA1
        CLR C
        SUBB A,DATA0;用DATA1减去DATA0
        LCALL RESULT;调用RESULT来实现屏幕显示
        MOV ANDS,A;将减法计算的结果存储在ANDS中        
        LCALL SORT;重新排序        
        RET
*/
//乘法子程序
CALCULATE_MULTIPLICATION:
        LCALL ANTI;转换数据
        MOV A,DATA0
        MOV B,DATA1
        CLR C
        MUL AB;乘法的结果,低八位储存在A,高八位储存在B
        MOV ANDS,A;将乘法计算的结果存储在ANDS中
        LCALL SORT;重新排序               
        RET
//除法子程序
CALCULATE_DIVISION:
        LCALL ANTI;转换数据
        MOV A,DATA1
        JZ RE0;判断被除数是否为0
        AJMP RE1;
RE0:
        LCALL ERROR;报错
RE1:
        MOV A,DATA0
        MOV B,DATA1
        DIV AB;商放在A,余数放在B
        MOV DATA3,B;保护数据
        MOV ANDS,A;将除法计算的结果保存在ANDS中,只储存了整数位
        MOV B,DATA3;取出数据
        MOV A,B;将余数赋给A
//        CJNE A,#00H,REMAINDER0;判断余数是否为零
        LCALL SORT;重新排序        
        RET
//余数不为0计算小数点后一位
/*        REMAINDER0:
                MOV DATA3,A;放置数据
                MOV A,#2EH;赋字模.
                LCALL DATA_WRITTING
                MOV A,DATA3;取出数据
                MOV B,#10
                MUL AB;余数乘以10
                MOV B,DATA1;将除数给B
                DIV AB;商放在A,余数放在B
                MOV DATA3,B;保护数据
                LCALL RESULT;调用RESULT来实现屏幕显示
                MOV B,DATA3;取出数据
                MOV A,B;将余数赋给A        
                CJNE A,#00H,REMAINDER1
                RET
//余数不为0计算小数点后第二位
        REMAINDER1:
                MOV B,#10
                MUL AB;余数乘以10
                MOV B,DATA1;将除数给B
                DIV AB;商放在A,余数放在B
                LCALL RESULT;调用RESULT来实现屏幕显示
                RET
*/

//移位程序,新数据左移覆盖原有数据
SORT:
        MOV        TEMPORARY4,R0;保护R0的地址
        MOV R4,#20H;计数次数
        MOV A,ANDS;将计算结果的数据传给A
        MOV B,#100;取百位
        DIV AB;A取商,B取余数
        MOV TEMPORARY5,A;保存百位
        MOV A,B;将余数传给A
        MOV B,#10;取十位
        DIV AB;A取十位,B取个位
        MOV TEMPORARY6,A;保存十位
        MOV TEMPORARY7,B;保存个位
        DEC R1;R1的地址减1
        MOV @R1,TEMPORARY7
        DEC R1;R1的地址减1
        MOV @R1,TEMPORARY6
        DEC R1;R1的地址减1
        MOV @R1,TEMPORARY5
        MOV A,R1
        ADD A,#03H
        MOV R1,A;
        MOV TEMPORARY6,R1;新数据起始地址
        MOV A,R1
        ADD A,#04H
        MOV R0,A;
        MOV R1,TEMPORARY6;新数据起始地址
        AJMP SORT0;隔离指令
SORT0:
        MOV A,@R0;新的数据存储地址中存储的数据
        MOV @R1,A;覆盖数据
        INC R0;新数据地址
        INC R1;原数据地址
        DJNZ R4,SORT0        
        MOV R0,TEMPORARY4;取出地址
        MOV R1,#80H;初始化R1
        RET        
//将计算结果进行显示
RESULT:
        MOV A,ANDS;取出数据
        MOV DATA2,A;保护数据
        MOV B,#100;给B赋值100
        DIV AB;A为百位,B为十位和个位
        CJNE A,#00H,THREE_BIT;百位不为0,则为三位数,反之则为两位数        
        MOV A,DATA2;取出数据
        MOV B,#10;给B赋值10
        DIV AB;A为十位,B为个位
        CJNE A,#00H,TWO_BIT;十位不为0,则为两位数,反之则为一位数
        AJMP ONE_BIT;隔离电路
THREE_BIT:
        ADD A,#30H;百位转换为字码
        LCALL DATA_WRITTING
        MOV A,B;取出数据
        MOV B,#10;给B赋值10
        DIV AB;A为十位,B为个位
        ADD A,#30H;十位转换为字码
        LCALL DATA_WRITTING
        MOV A,B;传递个位
        ADD A,#30H;个位转换为字码
        LCALL DATA_WRITTING
        AJMP BIT0        
TWO_BIT:        
        ADD A,#30H;十位转换为字码
        LCALL DATA_WRITTING
        MOV A,B;传递个位
        ADD A,#30H;个位转换为字码
        LCALL DATA_WRITTING
        AJMP BIT0        
ONE_BIT:
        MOV A,B;传递个位
        ADD A,#30H;个位转换为字码
        LCALL DATA_WRITTING
        AJMP BIT0
BIT0:
        RET
//逆转换数据格式,将十位与个位重新组合
ANTI:
        MOV B,#100
        DEC R1
        DEC R1
        DEC R1
        MOV A,@R1;记录百位
        MUL AB;保留低八位
        MOV TEMPORARY0,A;将百位储存
        INC R1
        MOV B,#10        
        MOV A,@R1;记录十位
        MUL AB;保留低八位
        ADD A,TEMPORARY0;组合百位数和十位数
        CLR C;清除进位标志
        INC R1;进位至个位
        ADD A,@R1;组合数
        MOV DATA0,A;将值存放在DATA0中
        INC R1
        INC R1;进位至百位
        MOV A,@R1;记录百位
        MOV B,#100
        MUL AB;保留低八位
        MOV TEMPORARY0,A;将百位储存
        INC R1
        MOV B,#10        
        MOV A,@R1;记录十位
        MUL AB;保留低八位
        ADD A,TEMPORARY0;组合百位数和十位数
        CLR C;清除进位标志
        INC R1;进位至个位
        ADD A,@R1;组合数
        MOV DATA1,A;将值存放在DATA1中
        DEC R1;
        DEC R1;
        DEC R1;回退至符号位
        RET
//键号对应的键码表
KEYVALUE:
        DB  77H, 7BH, 7DH, 7EH;键码0,1,2,3
        DB 0B7H,0BBH,0BDH,0BEH;键码4,5,6,7
        DB 0D7H,0DBH,0DDH,0DEH;键码8,9,10,11
        DB 0E7H,0EBH,0EDH,0EEH;键码12,13,14,15
//键号对应的LM016L字码表,AC与=赋00H,执行特殊操作
TABLE:;
        DB        37H,38H,39H,2BH;字码7,8,9,+
        DB        34H,35H,36H,2DH;字码4,5,6,-
        DB        31H,32H,33H,2AH;字码1,2,3,*
         DB        00H,30H,00H,2FH;字码AC(空),0,=(空),/
//延迟电路
DELAY:
        MOV R5,#10H;单周期指令
        DLY1:
                MOV R6,#10H;单周期指令
        DLY2:
                MOV R7,#248;单周期指令
                DJNZ R7,$;双周期指令
                DJNZ R6,DLY2;双周期指令
        DJNZ R5,DLY1;双周期指令
        RET;双周期指令
//LM016L设置写的命令输入模式
COMMAND_WRITTING:
        CLR RS;RS=0
        CLR RW;RW=0
        MOV P0,A;单片机传递数据给LM016L
        CLR E;E=0
        LCALL DELAY;等待上升沿数据输入
        SETB E;E=1
        RET
//LM016L设置写的数字输入模式
DATA_WRITTING:
        SETB RS;RS=1
        CLR RW;RW=0
        MOV P0,A;单片机传递数据给LM016L
        CLR E;E=0
        LCALL DELAY;等待上升沿数据输入
        SETB E;E=1
        RET
//蜂鸣器响铃电路
BUZZER:
        LCALL DELAY
        MOV R4,#64H
BUZZER0:
           SETB BR;开启蜂鸣器
           CLR BR;关闭蜂鸣器
        DJNZ R4,BUZZER0;震荡电路
        LCALL DELAY
        RET

//LED闪烁
LIGHT:
        LCALL DELAY
        CLR LED;打开LED
        LCALL DELAY
        SETB LED;关闭LED
        RET
END

01.7z

150.3 KB, 下载次数: 11

基于普中A2的仿真

回复

使用道具 举报

ID:1085458 发表于 2023-7-6 20:38 | 显示全部楼层
BAKELOR 发表于 2023-7-2 20:40
该计算器是8位计算器,输出结果范围为0—255,输入的数据两位正数或一位正数,无法进行负数计算,除法保留 ...

如果把数据转化的格式由原来的“百位,十位,个位”转换为“符号位,百位,十位,个位”的形式,可以进行带符号的运算,更进一步,可以把整数部分和小数部分转换分开计算加减乘除,最后将和相加的方式完成带小数的运算。与此同时,计算相关的程序都需要相关更改
回复

使用道具 举报

ID:1085458 发表于 2023-7-2 20:57 | 显示全部楼层
BAKELOR 发表于 2023-7-2 20:40
该计算器是8位计算器,输出结果范围为0—255,输入的数据两位正数或一位正数,无法进行负数计算,除法保留 ...

如果想让仿真中的蜂鸣器响,可以把无源蜂鸣器speaker替换为有源蜂鸣器,连线不变,并修改蜂鸣器的子程序为延时加高电平加延时加低电平即可,不过延时过短会无法区别多次蜂鸣
回复

使用道具 举报

ID:1085458 发表于 2023-7-2 20:47 | 显示全部楼层
该程序的计算器针对的是输入数据为正数,输入输出的结果不能超过255,否则会溢出,出现错误的输出结果,具有的功能为带优先级的加减乘除运算,输入的字符显示在第一行,超过16个字符会显示“OFF RANGE”字样,结果在按下等号后,输出在下一行,按下“AC”键清零,屏幕出现“RESTART”并清零,当计算结果有负数或除法除以0时,提示“ERROR”并清零,按下“ON”键,开机,显示“WELCOM”,按下“OFF”,关机
回复

使用道具 举报

ID:1085458 发表于 2023-7-2 20:40 | 显示全部楼层
该计算器是8位计算器,输出结果范围为0—255,输入的数据两位正数或一位正数,无法进行负数计算,除法保留整数部分,程序中无输入数据和符号的格式是否正确的判定,在输入错误的情况下会出现错误的结果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表