51单片机子程序中使用JMP(AJMP,LJMP,SJMP)指令 执行RET能不能回到主程序?

还有就是中断程序中使用JMP(AJMP,LJMP,SJMP)指令,执行RETI能不能回到中断跳转前的程序位置.
请不要复制一堆不相干的东西来胡弄人..
CALL(ACALL,LCALL)调用中使用了JMP(AJMP,LJMP,SJMP)指令,最后使用RET能不能回到CALL(ACALL,LCALL)调用前的位置?
CALL(ACALL,LCALL)指令中调用CALL(ACALL,LCALL),多少次就会出错?

JMP(AJMP,LJMP,SJMP)指令,是转移指令,它们在转移的时候,并不保留当前的地址,所以使用RET指令,是无法回到原来的位置的。

使用LCALL、ACALL指令,就是调用子程序的指令,是可以用RET指令返回的,因为LCALL、ACALL指令保存了原来的地址,可供RET使用。

另外,中断程序中是可以使用JMP指令的,但是要保证,要尽快使用RETI返回原来的断点,否则就一直处于中断之中,CPU以后就不会再相应同级别的中断了。
------------------------
问题补充:
...,最后使用RET能不能回到CALL(ACALL,LCALL)调用前的位置?
可以。
...,多少次就会出错?
LCALL、ACALL指令保存了原来的地址,是存放到堆栈里面。
51单片机的堆栈,是在片内RAM中,空间是有限的。
空间究竟有多大,和你的栈底初始化的地址有关,另外,堆栈中,还会保存其它的内容。所以,保存返回地址的空间究竟能有多大,需要你自己计算。
多少次会出错,是和你编写的程序有关的。
你可以用keil软件来调试,把你的程序单步的运行走一遍,即可知道堆栈空间的使用情况了。
温馨提示:答案为网友推荐,仅供参考
第1个回答  2010-04-06
我仔细看了一下所有人的回答,有根本没看懂楼主问题答非所问的,也有回答的差不离的,我来切一下重点好了。
楼主这所有问题其实归根结底就是一个问题,堆栈和SP(堆栈指针)的问题
CALL指令执行时,就是先把当前程序指针压入堆栈并使SP加1,然后开始执行CALL指令调用的子程序,当遇到RET指令时,把前面压入堆栈的程序指针取出并SP减1(出栈),然后就回到CALL程序调用前位置了。
JMP指令并不会把程序指针压入堆栈更不会影响SP(当然自己在JMP后用PUSH指令除外)。自然CALL调用后使用JMP指令跳转,最后遇到RET指令一样能回到CALL程序调用前位置。就算你在JMP指令后使用PUSH指令,只要和POP成对出现,还是会回到调用前的位置,不成对?这堆栈不能这么用的。。飞了。。飞了。
中断其实和CALL指令时一样的道理,至于用RETI就如张庚(3楼)兄弟说的中断是要多处理一些标志位。
至于调用CALL多少次出错,这还是堆栈和SP的问题。
如我上面所写,CALL指令一次就得压栈一次,而你在RET指令前又来一次CALL指令,那么还得压一次,这样一直下去堆栈指针愈来愈大,就会占用程序所要使用的RAM地址,自然肯定会出错,一半51单片机默认SP为07H,而一般编程RAM地址20H开始就会被程序占用,一算就知道了,大概10几20次吧,如果你中间还是用堆栈那么就少点,如果你的程序占用RAM的地址靠后那么就多点,不过一般够用是肯定的了本回答被提问者采纳
第2个回答  2010-04-03
JMP是跳转指令,只要在合法范围内随便用,跟RET和CALL指令没多大关系,
RET和CALL才是一对,当使用CALL指令调用一个函数并把程序指针SP入栈记录当前执行位置,比如说循环延时程序时,程序转去执行子程序,程序执行到RET指令时出栈SP,返回程序执行原位置。

至于JMP指令能不能用RET返回,应该是不能的,JMP只是跳转不是调用,当执行JMP命令的时候CPU修改程序指针SP为跳转地址。他和RET指令没关系。

RETI命令和RET命令作用差不多,当CPU响应中断后,转去执行中断函数,中断函数执行到RETI命令时指示CPU中断函数结束,程序返回原位置执行,RETI与RET的区别就是前者用于中断函数的返回,后者用于一般函数的返回。

至于CALL指令执行多少次会出错,根据CPU架构不同这个有所不同,具体芯片应该可以在芯片手册里面查到。

以上JMP和CALL的说法只是象征性的概念,不代表具体指令,希望多你有所帮助。
第3个回答  2010-04-03
我个人觉得你好像把这些指令的功能弄混了,JMP(AJMP,LJMP,SJMP)指令这些指令时单纯的跳转指令,比如JMP loop 这条指令,就是程序跳转到LOOP这个地方去执行,并没有什么返回不返回的说法,除非执行过程中遇到别的指令。这几个指令的区别的跳转的距离,有短跳转,长跳转,这些你去看看指令表应该就知道了。
至于ret 是专门给子程序调用的时候用的,当你调用一个子程序,子程序执行完之后,必须要写一个ret 这个指令,用来返回你调用子程序的那句程序的位置,以便程序继续运行。
而RETI 是专门给中断子程序使用的,是用来做中断返回用的。
这两个指令跟JMP没有关系,使用的时候在子程序里依然可以使用JMP,但需要注意的是你用完JMP就不会返回到原来的地方,所以一般在子程序使用JMP不会超出本子程序的范围,否则可能会造成程序跑飞,乱套了。
CALL(ACALL,LCALL)调用中使用了JMP(AJMP,LJMP,SJMP)指令,最后使用RET能不能回到. 这个问题跟我刚才说的一样。

CALL(ACALL,LCALL)调用前的位置?
这个给你举例说吧:
.....
mov a,#00h
call loop ;这里就是call调用之前的位置
mov r1,#21h ;这里是call调用之后返回的位置
......
loop:
jc c
mov a,#01h
ret

CALL(ACALL,LCALL)指令中调用CALL(ACALL,LCALL),多少次就会出错?
这个问题我还没遇到过,一般在call中继续用call调用子程序不会出什么错误,除非你做的地址有重复,或者使用的寄存器有冲突,或者堆栈没有设计好,才会出错的,

我的回答基本就这些,这是第一次给别人回答,这些都是我自己的理解,因为我刚学的时候也遇到过类似的问题,不知道能不能对你有所帮助。
第4个回答  2010-03-31
汇编语言的这种跳转指令最直接了,跟着顺一遍就ok了

一般是调用后,ret回主程序,这个的原理在于在call的时候,自动的把当前程序运行的位置存入堆栈,等于执行了一个PUSH,ret的时候自动出站,把地址吐出来并跳到该位置

中断程序的reti和ret的不同在于它还涉及开关中断允许标志

楼主自己可以推断一下,只要你JMP出去还在ret之前JMP回来,没有影响到该状态下的堆栈顺序就ok可以。这个常见的,当你的子程序或者中断程序里有判断分支的时候,常常会用判断性的跳转语句

单片机相对很接近硬件,只要把它各个指令执行的原理理清了,这个小东西怎么工作的,就可以灵活的利用汇编语言来控制了
相似回答