|

楼主 |
发表于 2007-9-5 00:50:01
|
显示全部楼层
最后,做一个综合实验:目标--正前方;利用这个仿真单片机软件,搭建一个简单的加减计算器,功能是:1,8位10进加法
2,减法
3,0-99递增
4,清除错误输入
5,全清
用数字键输入数字,用a-f共6个键实现功能太晚,明天再说...接着说:
这些功能,看似简单,然而要考虑问题的方方面面,或许就不那么简单,比如加法计算,按照习惯,得先输入被加数,然后按下+键,然后输入加数,再按等号键显示和,这样,就要考虑加数,被加数放在哪里?+号键的功能,=号键的功能,而且=号键还要用于减法计算,如何区别?等等都要考虑好。下面先交待一下有关技术热身:
1。汇编语言为了便于理解阅读,加入了一些“伪指令”它们只是用来控制汇编过程,或者表示某些标号,例如经常用到的ORG,DB,END就是,现在介绍一个比较常用的EQU命令:例如 NUMBER1 EQU R5 表示可以在程序中在用到R5寄存器的地方用NUMBER1来代替,这样的好处是便于结合R5的用途,理解起来更加容易,最常用的伪指令也就是这几个。此外还有一些,这里就不一一解释了。
2.散转指令:这个在处理多条件选择入口方面,很有用,例如今天我们要处理6个按键,就用的这条指令 JMP @A+DPTR.意思是按照A的值转移到不同位置,这个位置的基准点在DPTR中,为此先要设置基准点:例如ORG 0200H (也就是在ROM的512单元)开始安排一系列无条件转移指令,结合A的内容转移到不同的位置去:
ORG 0200H
TODO1:AJMP mmmm
TODO2:AJMP nnnn
TODO3:AJMP xxxx
TODO4:AJMP yyyy
注意AJMP指令要占用2个字节,所以TODO1,TODO2,TODO3,TODO4的起始地址分别是0200H,0202H,0204H,0206H.那么,只要A中的“偏移量”是,0,2,4,6,在执行JMP @A+DPTR后,就根据偏移量的不同分别转到mmmm,nnnn,xxxx,yyyyROM地址去。这样我们处理功能按键就方便了
3再认识条件转移,前面我们多次用到条件转移CJNE----不等则转移(相等则直接执行下一条),在这里其实可以从“不等“进一步判断:如果进位标志C为0,两数前者大于后者,C为1,前者小于后者。
4通常单片机内部进行的都是二进制加法,现在我们做计算器,就要采用“形式上的”十进制,就是内存单元中的数超过9就要进位。当然也可以采用其他方法不过这个便于我们理解。减法,采用补码加法更容易编程,也就是说,把9 - 4 变成 9+ 6 -10 ,( 6=10-4,就是4的10进数补码)10也就是进位,9+6=14,去掉进位就是4,看起来麻烦实际在编程时比处理借位减法更容易。
好了,下面就是这个计算器程序的主要过程:
启动 ---〉初始化-----〉循环显示-----〉按键扫描----〉有键---〉查键,取键值---〉数字键
- | | |
|----------------------------无键 功能键
0。。。9示数字键,A.。。。F是功能键,显然容易从键值判断
数字键要按照作用存放不同的位置;
功能键要按照键值不同作散转处理;
A代表+ ,D代表 - ,B,用作0--99自增,C,撤销刚才键入的数字,E代表=,F代表全部清除。
汇编程序如下:
KADD BIT 70H ;BIT也是伪指令,作用类似EQU,但BIT是指定“位“的代号,把2EH单元70H位用KADD代表
KDEC BIT 71H ;这些都是设立功能键的标志,不一定个个都用到,设置了不用,除了浪费点,无大碍
KCE BIT 72H ;K ADD KDEC,KCE,KEQU,KINC,KCEALL 分别是+,- ,CE,CEALL,=,INC的标志
KCEALL BIT 73H
KEQU BIT 74H
KINC Bit 75H
KzRo Bit 76H
ORG 0
AJMP MAiN
ORG 30H
MAIN: MOV SP, #30H
INIT: MOV 2EH,#0 ;2EH用作标志存储,各个位存放上述标志,先清除
PREDISP: MOV A,2EH
CJNE A,#0,PREDISP2 ;设立50H...57H和60H...67H两组数据存放单元,先看2E单元有无标志如无,
;2EH 为0把50H...57H的数拷贝到显示缓冲40H...47H
MOV 40H,50H ;
MOV 41H,51H ;
MOV 42H,52H ;
MOV 43H,53H
MOV 44H,54H
MOV 45H,55H
MOV 46H,56H
MOV 47H,57H
AJMP DISP ;转显示
PREDISP2: MOV 40H,60H ;如果2EH不是0,数字键是在功能键之后按下的显示60H...67H中的数
MOV 41H,61H ;
MOV 42H,62H ;
MOV 43H,63H
MOV 44H,64H
MOV 45H,65H
MOV 46H,66H
MOV 47H,67H
AJMP DISP
DISP: MOV R1,#47H ;下面是要不显示数字1...9左面的数值以至于成为类似00002345
GET: MOV A,@R1 ;从显缓区右端向左查,把数字1---9左边的0用10H代换10H的字段码是0FFH,不显示
CJNE A,#0,GET1
MOV @R1,#10H
DEC R1
CJNE R1,#3fH, GET
GET1: ;下面开始把显缓区的数字查段码逐位显示
MOV R2,#0FEH
MOV R1,#40H
GET2:MOV A,@R1
MOV DPTR,#DISPTAB
MOVC A,@A+DPTR
MOV P0,A ;LED DATA
MOV P2,R2
ACALL DLY
MOV A,R2
RL A
MOV R2,A
INC R1
CJNE R1, #48H,GET2
MOV R2,#0FEH
MOV R1,#40H
CPL P1.0 ;40H...47H都显示一遍,转入键程序
DSPEND: SJMP KEY
KEY:
MOV P3,#0FH ;先看有无键,方法直接把P3高4位都输出0,检查P3.低4位,
MOV A,P3
ORL A,#0F0H
CJNE A,#0FFH,KEYCHK ;有键详查
MOV P3,#0FFH
AJMP DISP ;无键转显
KEYCHK: ACALL DLY ;查键前先延时消除触点抖动
MOV R0,#4 ;扫描查键
MOV R3,#0EFH ;
NOKEY: MOV A,R3 ;
MOV P3,A
MOV A,P3 ;
ORL A,#0F0H
CJNE A,#0FFH,KEYIN ;有键转移
MOV A,R3 ;
RL A ;
MOV R3,A
DJNZ R0,NOKEY ;
AJMP KEYCHK
KEYIN: MOV P3,#0ffH ;
ACALL DLY ;
MOV R4,A ;以下求键值
KEYVAL: MOV B,#0
MOV A,R4
K1: RRC A
JNC K2
INC B
SJMP K1
K2: MOV A,R3
SWAP A
K3: RRC A
JNC KVALEND
INC B
INC B
INC B
INC B
SJMP K3
KVALEND: ;求出键值在B中
MOV P3,#0FH ;再次查键,等待按键释放
MOV A,P3
ORL A,#0F0H
CJNE A,#0FFH,KVALEND
MOV A,B ;按键释放键值给A
CJNE A,#0AH,KNUM_CTL ;键值不是0AH,是数字键或功能键,进一步查
AJMP KCTL ;键值是0AH,是功能键转移
KNUM_CTL:JNC KCTL ;如果C标志为0,键值大于0AH,转功能键处理
KNUM: JB KCE,KNUM3 ;C为1,键值小于0AH,如果KCE置位,已经按过CE键,转
MOV A,2EH ;看数字键是在功能键前还是后输入
JNZ KNUM2 ;功能键后,转
MOV R0,#56H ;功能键前,先顺序位移56H...50H,
MOV R1,#57H ;
KPUT1: MOV A,@R0
MOV @R1,A
DEC R0
DEC R1
CJNE R0,#4FH,KPUT1
INC R0
MOV @R0,B ;键值输入50H
AJMP KNUMEND
KNUM2: MOV R0,#66H ;功能键后数字键,要存入60H单元;
MOV R1,#67H
KPUT2: MOV A,@R0
MOV @R1,A
DEC R0
DEC R1
CJNE R0,#5FH,KPUT2
INC R0
MOV @R0,B
AJMP KNUMEND
KNUM3: CLR KCE ;KCE键后的输入数字根据其他功能键是否按下(2E单元是否0)决定是覆盖;
MOV A,2EH
JNZ KNUM31
MOV 50H,B ;50H
AJMP KNUMEND
KNUM31: MOV 60H,B 还是覆盖60H
KNUMEND: AJMP PREDISP ;转显示
KCTL: MOV A,B ;功能键处理 ,功能键值从0AH到 0FH,不便直接散转
SUBB A,#0AH ;键值减10,得到0。。。6
RL A ;左移得到0,2,4,6,正是散转所需的偏移量
MOV DPTR,# CTLDO ;
JMP @A+dPtR ;散转喽!见最后,最终转移到下面的KA,KB,KC,KD,KE,KF入口
KA: MOV 2EH,#0 ;+,设立标志即可,真正计算是在=中
SETB KADD
AJMP DISP
KB: MOV 2EH,#0 ;B键处理
KBINC: MOV R0,#50H
MOV A,@R0
INC0: INC A
MOV @R0,A
INC1: CJNE @R0,#10,KIND
MOV @R0,#0
INC R0
MOV A,@R0
Add A,#1
MOV @R0,A
CJNE @R0, #10, INC1
DEC R0
INC2: MOV 50H,#0
MOV 51H,#0
KiIND: AJMP PREDISP
KC: MOV A,2EH ;C键处理
JNZ KC1 ;功能键前删除50H,否则删除 60H
MOV 50H,#0H
SJMP KCEND
KC1: MOV 60H,#0H
KCEND: SETB KCE ;设标志下次输入数字,不位移直接覆盖
AJMP DISP
KD: MOV 2EH,#0 ;减法键仅仅设标志
SETB KDEC
AJMP DISP
KE: JB KADD,KE1 ;=键,如果有加法键标志,转加法
JB KDEC,KE2 ;如果有减法标志,转减法
AJMP DISP ;什么键不按就按等号,转显示
KE1: MOV 2EH,#0 ;加法:清除原有按键标志
ACALL TOADD ;调用加法子程序
AJMP PREDISP ;从头显示
KE2: MOV 2EH,#0 ;清标志
ACALL TODEC ;调减法子程序
AJMP PREDISP ;从头显示
KF MOV A,2EH; ;全清,把50h...57h和60h...67h中的数据全部清除,以便下次计算
JNZ KF1
PUSH 1
MOV R1,#50H
KF0: MOV @R1,#0H
INC R1
CJNE R1,#58H,KF0
MOV R1,#60H
KF01: MOV @R1,#0H
INC R1
CJNE R1,#68H,KF01
POP 1
AJMP KFEND
KF1: PUSH 1
MOV R1,#60H
KF10: MOV @R1,#0H
INC R1
CJNE R1,#68H,KF10
POP 1
KFEND: AJMP PREDISP
TOADD: MOV R0,#50H ;加法子程序
MOV R1,#60H
MOV 49H,#0 ;单元49内存放进位,开始前清除
TOLOOP: MOV A,@R1 ;依次逐位把50h..和60h..中的十进数相加
ADD A,@R0
ADD A,49H ;再加进位
CJNE A,#10,TOADD1;结果不等于10,则转
TOADD0: SUBB A,#10 ;结果等于10,减去10
MOV 49H,#1 ;进位
SJMP TOADD2
TOADD1: JNC TOADD0 ;相加结果大于10,和等于10同样处理
MOV 49H,#0 ;相加结果小于10,不进位
TOADD2: MOV @R0,A ;存放结果,转向高一位相加
INC R0
INC R1
CJNE R0,#58H,TOLOOP ;直到8位加完
MOV R0,#50H
MOV R1,#60H
RET
TODEC: MOV R0,#50H ;减法
MOV R1,#67H ;67h单元存放减数最高位(可以是0)
MOV 2DH,#0 ;单元2dh内存放借位
PROD: MOV A,#10 ;从最高往下求减数补码,
SUBB A,@R1
MOV @R1,A ;用补码代替原有减数
PROD2: DEC R1 ;一直代换到最低位60h单元
CJNE R1,#5fH,PROD
MOV R1,#60H ;从最低位开始,计算 被键数+减数补码-借位
DEC0: MOV A,@R1
ADD A,@R0
SUBB A,2dH
CJNE A,#10,DEC01 ;结果不为10,转
SUBB A,#10 ;结果为10,减10
MOV 2dH,#0 ;清借位
AJMP DEC03
DEC01: JNC DEC02 ;结果>10,和等于10同样处理
MOV 2dH,#1 ;结果小于10,要把借位置1
SJMP DEC03
DEC02: SUBB A,#10
MOV 2DH,#0
DEC03: MOV @R0,A ;促模仿结果,转高位处理,直到最高位
INC R0
INC R1
CJNE R0,#58H,DEC0
MOV R0,#50H
DECEND: MOV 2DH,#0
RET
DLY: MOV R5,#40
L7: MOV R6,#250
L8: DJNZ R6,L8
DJNZ R5,L7
RET
DISPTAB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,10001000B,10000011B,11000110B,10100001B,10000110B,10001110B,0ffH,10111111B
ORG 400H ;散转基准地址
KCTLdo: ;散转到下列位置
AJMP KA ;地址为400h
AJMP KB ;403h
AJMP Kc ;404h
AJMP Kd ;406h
AJMP KE ;408h
AJMP Kf ;40ah
END
[ 本帖最后由 wey05 于 2007-9-5 22:49 编辑 ] |
|