慎用51单片机中的RET指令
来源:互联网 发布:ie8中文版官方mac 编辑:程序博客网 时间:2024/06/05 11:17
题目:已知有四个按键依次连接单片机中的P3口的0到3的IO口,有四个LED灯连接P1的0到3 IO口,写一程序,满足以下条件:当按下按一个按键,对应的LED会发亮,比如
按下P3.0的按键,连接P1.0的LED就发亮。y
以下是我同学编写的程序:
org 0000h
mov P1,#0ffh
loop:
jnb P3.0,led1;*
jnb P3.1,led2;*
jnb P3.2,led3;*
jnb P3.3,led4;*
ljmp loop
led1:
clr P1.0
ret
led2:
clr P1.1
ret
led3:
clr P1.2
ret
led4:
clr P1.3
ret
end
程序的意图是,制造一个死循环,不断检查按键是否按下,如果按下,就令对应的灯亮。程序经过测试,能够满足题目的要求。
但是,问题出现在上面带*号的那一部分代码,程序意图是想要当P3的某个位为0的时候,就调用LED灯的子程序,执行CLR P1.0语句,再返回到原来程序调用子程序的地方继续执行代码。
我对的子程序的理解是:在一个地方启动一段代码,当这段代码运行完毕之后,就返回到原来的地方继续运行剩下的代码。
那么CPU单片机是如何返回原来的地址的呢?
首先,当程序执行到A处进入子程序时,将A的下一个条指令(即PC+2所指的地方)压入栈中,即将栈指针SP+1,PCL进栈,SP再加1,PCH进栈。
然后,把PC的值改为子程序代码的入口。
子程序执行完毕之后,从栈中弹出原来的PC值,赋值给当前的PC寄存器。
最后,程序返回到原来调用子程序的地方的下一条指令继续运行。
(详细步骤请查看RET和ACALL,LCALL指令)
上面的代码很明显想调用一个子程序,但是51单片机中,只有ACALL和LCALL指令会在跳转前讲PC+2值压栈,其他跳转指令都不会。
代码中使用了JNB作为跳转指令,所以并没有压栈,但是当跳转之后遇到RET,还是一如既往地弹栈,这样,只有出,没有进,会导致堆栈不平衡。
但为什么这个程序依然有效呢?
这个因为SP初始指针指向了一个空白的单元(全是0),所以,当遇到RET后,把PC寄存器给初始化,程序由头开始重新执行,阴差阳错地满足的题目的要求。
所以RET指令必须和ACALL和LCALL配套使用,才能组成为真正意义上的子程序
- 慎用51单片机中的RET指令
- 51 单片机汇编语言:利用 RET 指令实现多路分支
- 51单片机 ret和reti
- 单片机汇编指令中RETI和RET的区别
- 单片机汇编指令中RETI和RET的区别
- RET指令
- RET指令
- ret指令
- RET指令
- 单片机中的NOP指令
- 单片机中的NOP指令
- 汇编指令ret正解
- ret和retf指令
- CALL和RET指令
- call和ret指令
- call 和 ret 指令
- CALL和RET指令
- Call指令与ret指令
- VC++6.0中注释多行代码的快捷键
- redo重做日志管理
- RHEL6.1 中VNC部署
- tyvj-1017 并查集
- Windows 7驱动开发系列(一)--前言&&WIN7的新特性
- 慎用51单片机中的RET指令
- STL string 类用法总结
- 《那些年啊,那些事——一个程序员的奋斗史》——44
- Tomcat 目录结构 标签含义
- java程序设计与问题解决(高级篇)-读书笔记-2
- Windows 7驱开发系列(二)--用户模式与内核模式
- 什么是中断?什么是异常?
- 手机端数据缓存机制
- 网络数据包发送接收全过程