单片机汇编语言问题? 单片机汇编语言100例
单片机汇编语言问题
看这个简单的程序:ORG 0000H
LJMP ST
ORG 0100H
ST:MOV P2,#00H /P2口控制数码管,让所有的数码管都有效。/
MOV P0,#0A4H /P0口控制输出字/
SJMP $ /原地踏步/
END在这里,SJMP是死循环,但是我们发现如果没有SJMP,无论我们设计的控制字是多少,数码管显示的数字都是8.而且有闪动,我们并没有给它延时,而且根据理论,此处没有延迟,数码管应瞬时进入结束,人根本看不出数码管的显示,就是无显示.。我们说,这个程序既然SJMP是死循环,那么END就是无效的,程序中的END根本不执行,它只在程序进行汇编时有效。当你的电脑编完汇编程序时,电脑要编译一下,把你的汇编代码转换成16进制机器码,然后把这个机器码文件通过烧写器烧进CPU中。当进行代码转换时,电脑只要一看到END,就停止转换,无论它后面还有没有汇编代码。望采纳
单片机汇编语言的几个疑问
1、如果程序代码空间不紧张的话,建议你全部使用LJMP,或者如果跳转的目标段程序相隔很近,也可以使用SJMP。个人认为AJMP最麻烦:其机器码所标注的地址位从A10到A0,计11位,000H~7FFH,也就是说跳转到的地址与当前地址的A10到A0必须一样,比如:
原来AJMP地址为:07F8H,目标地址:07F0H,如果调试软件修改后,变为
AJMP地址为:0800H,目标地址:07F8H,A11不一样,不在一页范围,此时还得将其改成LJMP,否则编译出错。其实就省了一个字节,执行时间上都是2个机器周期,没区别,所以犯不上。如果像此例,使用SJMP倒是个较好的选择,只是要求你对代码间的间隔有数才行。
总之,尽量用LJMP吧。
2、二者区别其实就是转移的目标是绝对地址,还是针对当前转移指令所在地址的相对偏移量
【绝对转移】51中只有AJMP、LJMP是绝对转移指令,都是直接跳转到固定地址。我们平时写的比如LJMP MAIN语句,源程序中并未表示出这一点,假设MAIN标志的程序段是从0102H开始的,此句编译后的机器码是02 01 02,02代表LJMP跳转,后两个字节0102则为目标地址,由于使用了2个字节指明目标地址,所以其范围就是整个64K的空间,没有限制;AJMP在这一点上就要差些,只能在所在的2K页内跳转。
【相对转移】剩下的转移指令都是相对转移指令,包括SJMP,它们是以当前语句的下一条语句所在地址为准,PC值向前或向后偏移数个字节地址开始执行,偏移量范围从-128到+127,以补码方式存在。比如
ORG 0100H
NO1: CLR A
SJMP NO1
编译后地址及机器码:
0100H: 0E4H (CLR A)
0101H: 80H 0FDH (SJMP NO1,从0103跳回0100,倒退3字节,3的补码即取反+1=FDH
0103H: 00H
3、要想能高效的调试大的汇编程序,首先要求程序本身的编制应该规范。关于这一点我有些感触,就算是经验吧,供参考(我曾经用汇编做过50多K机器码的程序)。
单片机的执行其实是单一线程的,一般只有两种情况会偏离原来的流程,一种是中断服务子程序,注意别忘了使用RETI;还有就是普通子程序,别忘了使用RET;再加上注意出栈、入栈操作,而且该操作因成对并保证先进后出原则,这样的话才真正做到模块化编程,调试时才能不理睬其它部份,单独调试某个模块,提高效率。这一点C语言就比较好,以函数方式实现,少写括号编译通不过,不像汇编,少些个RET照样能通过。
另外,编写程序时应养成一种习惯:对程序体中的寄存器操作尽量不要直接使用其地址,比如:MOV 30H,A,这里直接写30H不好,因为大的汇编程序对寄存器地址的调整是很常见的现象,一旦修改,程序中每个地方都要改,容易遗漏,一旦遗漏,非常难找原因的。可以用EQU伪指令对其定义,程序体中使用。同样,这一点C语言要好的多,至少不需要去分配寄存器了。
还有一个最容易出错的地方,就是关于标志位C:比如CJNE指令,它的判断是会影响C标志位的,如果程序后面有对C标志位判断的语句又没有考虑这种情况,问题极难查。很多人包括我自己会忽略这种细节。这类问题只能靠细致了。
最后谈谈调试
调试过程一般都是逐个模块(子程序)分别调试,完成一个再检查下一个,不能指望一上来就正确。调试完后还要多次、多人测试,自己有时形成了固定思维,发现不了问题。
终极方法:分部仿真设断点甚至于单步执行。对一些外部输入可以采用到断电后修改寄存器数值的方法来模拟。当然最理想的情况是不用,只是初期恐怕是免不了的。比如对上面所说的C标志位问题,我个人当初几乎都是这样找出的问题
大的汇编程序的调试确实比较麻烦,首先要求你对软件流程很清晰,对单片机的运行模式也要很了解。至于你现在的程序如果有问题,我建议还是采用仿真设断点的方式来找问题,尤其是如果搞单片机的时间不长的话,这样其实可能更快些。
希望所说能对你有所帮助。
单片机汇编语言的几个问题
前3个的理解都是对的,最后一个有点问题
应该是把R0的内容送到SFR中地址为90H的单元,因为高128字节的内部RAM地址和SFR重叠,SFR只能直接寻址,高128B的RAM只能间接寻址
初学者关于单片机汇编语言的问题
///////////////////////////////////
LJMP跟LCALL是在任何情况下都能用,
但是他们的指令长度不同,用a的可以节省一些空间
AJMP 占用2字节 运行周期2
SJMP 占用2字节 运行周期2
LJMP 占用3字节 运行周期2
ACALL 占用2字节 运行周期2
LCALL 占用3字节 运行周期2
//////////////////////////////////////
MCS-51的控制转移类指令,共17条,分为无条件转移指令、条件转移指令、子程序调用和返回指令、空操作指令等四类。
无条件转移指令(共4条)
LJMP addr16 ; PC〈—— addr16
AJMP addr11 ; PC〈—— PC+2 , PC10-0〈—— addr11
SJMP rel ; PC〈—— PC+2 , PC 〈—— PC+rel
JMP @A+DPTR ; PC〈—— A+DPTR
第一条指令称为长转移指令(Long Jump);
第二条指令叫作绝对转移指令(Absolute Jump);
第三条指令称作短转移指令(Short Jump);
第四条指令是变址寻址转移指令(散转指令)。
显然,每条指令均以改变程序计数器PC(Program Counter)中的内容为宗旨。
(1)长转移指令(64KB范围内转移指令)
长转移指令的功能是:把指令码中的目标地址addr16装入程序计数器PC,使机器执行下一条指令时无条件转移到addr16处执行程序,不影响任何标志。由于addr16是一个16位二进制地址(地址范围为0000H—FFFFH),因此长转移指令一条可以在64KB范围内转移的指令。为了使程序设计方便易编,addr16常采用标号地址(如:LOOP、LOOP1、MAIN、START、DONE、NEXT1……)表示,只有在上机执行前才被汇编(或代真)为16位二进制地址。
长转移指令为三字节,双周期指令。
上机试试吧!很直观的! For Example: LJMP F886H
注意:
在下载的这个8051DEBUG软件中,不支持标号,且程序状态字PSW(Program State Word)中的D0位,即奇偶标志位P,与正确的正好相反,这一点是错误的,用的时候留意一下。
只要记好:累加器ACC中1的个数为奇数,则P=1;否则P=0。
(2)绝对转移指令(2KB范围内的转移指令)
绝对转移指令是一条双字节双周期指令,11位地址addr11(a10—a0)在指令中的分布是:
a10 a9 a8 0 0 0 1|a7 a6 a5 a4 a3 a2 a1 a0,其中,00001B是操作码。在程序设计中,11位地址也可以用符号表示,但在上机执行前必须按照上述指令格式加以代真。
绝对转移指令执行时分为两步:
第一步是取指令操作,程序计数器PC中内容被加1两次;
第二步是把PC加2后的高5为地址PC15—PC11和指令代码中低11位构成目标转移地址:PC15—PC11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0
其中,a10—a0的地址范围是全“0”——全“1”。因此,绝对转移指令可以在2KB范围内向前或向后跳转。
如果把单片机64KB寻址区分成32页(每页2KB),则PC15—PC11(00000B—11111B)称为页面地址(即:0页—31页),a10— a0称为页内地址,但应注意:AJMP指令的目标转移地址不是和AJMP指令地址在同一个2KB区域,而是应和AJMP指令取出后的PC地址(即:PC+2)在同一个2KB区域。例如:若AJMP指令地址为2FFEH,则PC+2=3000H,故目标转移地址必在3000H—37FFH这 2KB区域中。
例如:MGH2001:AJMP addr11,
其中,MGH2001为AJMP addr11指令的标号地址,由该指令在程序存储器中的位置确定,addr11为11位地址,试分析该指令执行后的情况以及指令码的确定方法。
解:设MGH2001=3100H,addr11=10110100101B,则根据上述指令码格式可得绝对转移指令的格式码为:1 0 1| 0 0 0 0 1|1 0 1 0 0 1 0 1|(a10 a9 a8|操作码|a7—a0|)
即:A1A5H。该指令执行后:
PC15——PC11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0
PC= 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 1 B =35A5H
即:程序转移到35A5H处执行。
(3)短转移指令(-126—+129范围内的转移指令)
短转移指令的功能是先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。因此,短转移指令是一条相对转移指令,是一条双字节双周期指令,指令码格式为:80H rel(操作码 地址偏移量),这里,80H是SJMP指令的操作码;rel是地址偏移量,在程序中也常采用符号地址,上机运行前才被代真成二进制形式。
遇到具体问题时,头脑中一定要清楚一个关系式:目标转移地址=源地址+2+rel
(4)变址寻址转移指令(只能在256个存储器单元内转移)
这是一条单字节双周期无条件转移指令。
在指令执行之前,用户应预先把目标转移地址的基地址送入DPTR,目标转移地址对基地址的偏移量放在累加器A中。在指令执行时,MCS-51单片机把DPTR中基地址和累加器A中地址偏移量相加,以形成目标转移地址送入程序计数器PC中。
通常,DPTR中基地址是一个确定的值,常常是一张转移指令表的起始地址,累加器A中之值为表的偏移量地址,机器通过变址寻址转移指令便可实现程序的分支转移