标题:
51单片机汇编版本,关于工作寄存器R1在程序运行过程中无缘无故被修改的问题
[打印本页]
作者:
anyint
时间:
2017-11-14 17:27
标题:
51单片机汇编版本,关于工作寄存器R1在程序运行过程中无缘无故被修改的问题
附上软件代码:TEMP EQU 07H ;地址不要乱定 R7
硬件上:P3.0、P3.1口接了按键,P1口接了LED灯
问题:程序当中第一种模式ONE,里面的延时部分,有一个工作寄存器R1,在按键处理子程序KEYPRO中修改了之后,程序应该是一直保持修改之后的值的,但是显示的子程序循环执行几个来回后,R1发生了改变,好像恢复到初值了,显示(流水灯)的速度又快了。请教大佬们,R1工作寄存器的值变化是什么原因造成的?小弟不才,希望是代码错了,求大佬们指点迷津,感激不尽
ORG 000H
AJMP MAIN
ORG 100H
;********;
;主程序;
;********;
MAIN: MOV R0,#000H ;初始化LED模式为0
MOV R1,#00AH ;初始化LED的速度
MOV R2,#0FEH ;LED初始状态
MOV R5,#0FFH
WHILE: LCALL KEYSCAN ;按键扫描
S1: LCALL KEYPRO ;按键处理
S2: LCALL SHOW ;显示函数
JMPEND: AJMP WHILE
;********;
;显示子程序;
;********;
SHOW: MOV A,R0
RL A
MOV DPTR,#JMPTAB
JMP @A+DPTR
RET
;********;
;按键扫描子程序;
;********; ;03H = 0000 0011B
KEYSCAN: MOV P3,#03H ;给端口置高电平,读取端口状态必须先置端口为高电平
MOV A,P3 ;读入P3的状态也就是按键的状态
ORL A,#0FCH ;0FCH = 1111 1100B
CPL A ;取反
JZ S2 ;如果A键态为00,则无按键填过直接做显示部分
MOV TEMP,A ;保存临时键值
LCALL DELAY10MS;消抖
MOV A,P3
ORL A,#0FCH
CPL A
CJNE A,TEMP,S2 ;判断如果第二次读取的按键值和第一次读取的按键值不相等
MOV R5,A ;保存键值
RET
;********;
;按键处理子程序;
;********;
KEYPRO: MOV A,R5 ;把按键值给A
CJNE A,#001H,IFK2 ;如果键状态为K1,则
CJNE R0,#002H,K1PRO ; R0 = 0000 0000B #0000 0010B
MOV R0,#000H
SJMP KEYPROEND
IFK2: CJNE A,#002H,KEYPROEND
CJNE R1,#0FAH,K2PRO
MOV R1,#00AH
SJMP KEYPROEND
K1PRO: INC R0
SJMP KEYPROEND
K2PRO: MOV A,R1
ADD A,#00AH
MOV R1,A
SJMP KEYPROEND
KEYPROEND: RET
;********;
;延时10ms子程序;
;********;
DELAY10MS: ;@11.0592MHz
PUSH 30H
PUSH 31H
MOV 30H,#18
MOV 31H,#230
NEXT:
DJNZ 31H,NEXT
DJNZ 30H,NEXT
POP 31H
POP 30H
RET
;********;
;分支1子程序;
;********;
ONE:
MOV A,R2 ;R2是P1初始状态LED 1111 1110B = 0FEH
MOV P1,A
MOV A,R1
MOV R3,A
;MOV P1,A
L1: LCALL DELAY10MS
DJNZ R3,L1
MOV A,R2
RL A
MOV R2,A
AJMP JMPEND
;********;
;分支2子程序;
;********;
TWO: MOV P1,#00FH
SJMP $
AJMP JMPEND
;********;
;跳转程序表;
;********;
JMPTAB: AJMP ONE
AJMP TWO
END
复制代码
作者:
yzwzfyz
时间:
2017-11-15 13:35
请教一下,堆栈存从哪里开始?堆栈里的数据何时会发生变化?
作者:
anyint
时间:
2017-11-15 21:43
yzwzfyz 发表于 2017-11-15 13:35
请教一下,堆栈存从哪里开始?堆栈里的数据何时会发生变化?
查阅一下51汇编的书籍,堆栈的一开始初始化的地址我忘记,堆栈地址可以改的,给sp赋值即可。MOV SP,060H。堆栈的数据,当你调用子程序了就会压栈,返回的时候就出栈。或者直接对堆栈进行操作PUSH或者POP
作者:
anyint
时间:
2017-11-15 21:56
问题已找到,谢谢老师和同学以及论坛的大佬们。这个代码逻辑上应该对的,但是存在一个问题就是主程序明明调用了按键扫描子程序 LCALL KEYSCAN,但是在这个按键扫描的子程序里,我写了一个判断数据是否相等跳转的命令 CJNE A,TEMP,S2,而这个跳转的地址S2确实主程序里的,因此在按键子程序还没有RET返回就已经跳转到另外一个子程序里面了,此时堆栈就溢出,调用了却没有执行返回,调用的时候会压栈的,那么返回就是出栈,如果没有返回就会使得堆栈溢出,程序多跑几次直接复位。总结就是:调用了子程序一定要返回,不能调用了子程序再跳转到另外一个子程序,这样返回那句命令就废了。(如果调用了子程序,在自己的子程序里跳转是可以的)哈哈开心解决了一个很不容易发现的问题。再一次感谢老师同学以及论坛的大佬们。
附上正确的代码:
TEMP EQU 07H ;地址不要乱定 R7
ORG 000H
AJMP MAIN
ORG 100H
;********;
;主程序;
;********;
MAIN: MOV R0,#000H ;初始化LED模式为0
MOV R1,#00AH ;初始化LED的速度
MOV R2,#0FEH ;LED初始状态
MOV R5,#0FFH ;初始化键代码
MOV R6,#008H ;初始化计数器
WHILE: LCALL KEYSCAN ;按键扫描
LCALL KEYPRO ;按键处理
LCALL KEYAGIN ;按键弹起
AJMP SHOW ;显示函数
JMPEND: AJMP WHILE
;********;
;显示子程序;
;********;
SHOW: MOV A,R0
RL A
MOV DPTR,#JMPTAB
JMP @A+DPTR
;********;
;按键扫描子程序;
;********; ;03H = 0000 0011B
KEYSCAN: MOV P3,#03H ;给端口置高电平,读取端口状态必须先置端口为高电平
MOV A,P3 ;读入P3的状态也就是按键的状态
ORL A,#0FCH ;0FCH = 1111 1100B
CPL A ;取反
JZ ONKEY ;如果A键态为00,则无按键填过直接做显示部分
MOV TEMP,A ;保存临时键值
LCALL DELAY10MS;消抖
MOV A,P3
ORL A,#0FCH
CPL A
CJNE A,TEMP,ONKEY ;判断如果第二次读取的按键值和第一次读取的按键值不相等
MOV R5,A ;保存键值
AJMP KSEND
ONKEY: MOV R5,#000H
KSEND: RET
;********;
;按键处理子程序;
;********;
KEYPRO: MOV A,R5 ;把按键值给A
CJNE A,#000H,DOWNKEY
AJMP KEYPROEND
DOWNKEY: CJNE A,#001H,IFK2 ;如果键状态为K1,则
CJNE R0,#003H,K1PRO ;
MOV R0,#000H
MOV R2,#0FEH
SJMP KEYPROEND
IFK2: CJNE A,#002H,KEYPROEND
CJNE R1,#0FAH,K2PRO
MOV R1,#00AH
SJMP KEYPROEND
K1PRO: INC R0
MOV R2,#0FEH
SJMP KEYPROEND
K2PRO: MOV A,R1
ADD A,#00AH
MOV R1,A
SJMP KEYPROEND
KEYPROEND: RET
;********;
;按键弹起子程序;
;********;
KEYAGIN: MOV A,R5
CJNE A,#000H,KEYTQ
AJMP NOKEYTQ
KEYTQ: MOV P3,#03H
KEYTA: MOV A,P3
ORL A,#0FCH
CPL A
CJNE A,TEMP,KEYCH
SJMP KEYTA
KEYCH: NOP
NOKEYTQ: RET
;********;
;延时10ms子程序;
;********;
DELAY10MS: ;@11.0592MHz
PUSH 30H
PUSH 31H
MOV 30H,#18
MOV 31H,#230
NEXT:
DJNZ 31H,NEXT
DJNZ 30H,NEXT
POP 31H
POP 30H
RET
;********;
;分支1子程序;
;********;
ONE:
MOV A,R2 ;R2是P1初始状态LED 1111 1110B = 0FEH
MOV P1,A
MOV A,R1
MOV R3,A
L1: LCALL DELAY10MS
DJNZ R3,L1
MOV A,R2
RL A
MOV R2,A
AJMP JMPEND
;********;
;分支2子程序;
;********;
TWO: MOV A,R2
CLR C
MOV P1,A
MOV A,R1
MOV R3,A
L2: LCALL DELAY10MS
DJNZ R3,L2
MOV A,R2
RLC A
MOV R2,A
DJNZ R6,TWOEND
MOV R6,#009H
MOV R2,#0FFH
TWOEND: AJMP JMPEND
;********;
;分支3子程序;
;********;
THREE: MOV P1,#00FH
MOV A,R1
MOV R3,A
L3: LCALL DELAY10MS
DJNZ R3,L3
MOV P1,#0F0H
MOV A,R1
MOV R3,A
L4: LCALL DELAY10MS
DJNZ R3,L4
AJMP JMPEND
;********;
;分支4子程序;
;********;
FOUR: MOV P1,#0C3H
MOV A,R1
MOV R3,A
L5: LCALL DELAY10MS
DJNZ R3,L5
MOV P1,#03CH
MOV A,R1
MOV R3,A
L6: LCALL DELAY10MS
DJNZ R3,L6
AJMP JMPEND
;********;
;跳转程序表;
;********;
JMPTAB: AJMP ONE
AJMP TWO
AJMP THREE
AJMP FOUR
END
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1