找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 999|回复: 14
收起左侧

51单片机汇编语言sp的问题

[复制链接]
ID:73992 发表于 2024-5-28 09:01 | 显示全部楼层 |阅读模式
请问这种程序结构是否合理。
程序结果不正确。


                ORG        0000H
                LJMP        MAIN


MAIN:
                MOV        SP,#0X30
                LCALL        HBHB
                JMP        MAIN

HBHB:
                PUSH        ACC

                MOV        ACC,#0X01         ;1
                PUSH        ACC

                MOV        ACC,#0X02         ;2
                PUSH        ACC

                MOV        ACC,#0X03         ;3
                PUSH        ACC

                MOV        ACC,#0X04         ;4
                PUSH        ACC

                MOV        ACC,#0X05         ;5
                PUSH        ACC

                MOV        ACC,#0X06         ;6


                MOV        R0,SP                 ;R0保存栈顶
                LCALL        AFAF

                POP        ACC
AFAF:
                PUSH        ACC
                PUSH        SP
                MOV        SP,R0                ;R0释放栈顶

                POP        ACC                        ;6
                MOV        R1,ACC

                POP        ACC                        ;5
                MOV        R2,ACC

                POP        ACC                        ;4
                MOV        R3,ACC

                POP        ACC                        ;3
                MOV        R4,ACC

                POP        ACC                        ;2
                MOV        R5,ACC

                POP        ACC                        ;1
                MOV        R6,ACC


                PUSH        SP
                POP        ACC
                RET

                END

下是仿真结果
无标题.png


回复

使用道具 举报

ID:404160 发表于 2024-5-28 10:27 | 显示全部楼层
  MOV        SP,#0X30这句把程序指针指向了51内部设定的“中断矢量区。一般是把SP赋值为100
回复

使用道具 举报

ID:73992 发表于 2024-5-28 11:02 | 显示全部楼层
飞云居士 发表于 2024-5-28 10:27
MOV        SP,#0X30这句把程序指针指向了51内部设定的“中断矢量区。一般是把SP赋值为100

sp是栈指针,指向128字节内存地址。
您说的是PC程序计数器
回复

使用道具 举报

ID:384109 发表于 2024-5-28 12:40 | 显示全部楼层
先搞懂什么是SP吧
回复

使用道具 举报

ID:858964 发表于 2024-5-28 13:18 | 显示全部楼层
MOV   R0,SP  ;R0保存栈顶
...
MOV   SP,R0  ;R0释放栈顶
这2条指令,保存/释放栈顶指针,无用。
因为栈顶指针随着每次进/出栈作用自动改变。

建议改为:
保存/释放栈项数据,而不是保存/释放栈项指针。
回复

使用道具 举报

ID:624769 发表于 2024-5-28 17:10 | 显示全部楼层
莫名其妙的代码,也不知道到底要干什么,你这么玩SP 不会直接用 R0 指针操作么?反正,最后你是要把指针放到R0保存,还不如直接用R0了……
回复

使用道具 举报

ID:123289 发表于 2024-5-29 15:29 | 显示全部楼层
有此问,说明你对51的指令系统未作认真研读:
1、LCALL nn
指令执行:PC = nn
再:(SP+2)=(PC+3)H,(SP+1)=(PC+3)L,SP=SP+2

2、RET
指令执行:PC=(SP)(SP-1)
再:SP=SP-2

3、PUSH (R)
指令执行:(SP)=(R)
再:SP=SP+1

4、POP (R)
指令执行:SP=SP-1
再:(R)=(SP-1)

(R):特地加了个(),目的:告诉你,这是R指向的地址中的内容。
(SP-1):特地加了个(),目的:告诉你,这是SP-1指向的地址中的内容。

据此,你自行分析程序是否混乱。混乱的主要表现是:RET回不到原先CALL的下一条指令。
建议研读指令系统,51系统也就255个,且许多是类同的。
搞汇编,必须读通读透指令系统。
任何一款单片机,只要你读通了它的指令系统,则它的功能就被你掌握了!!! 也可以说,基本了解了一款新的单片机。不信你试试研读PIC的单片机的指令系统。
回复

使用道具 举报

ID:123289 发表于 2024-5-30 09:22 | 显示全部楼层
SP的位置在81H,是个8位的内部寄存器,通常用于做堆栈指针,指针范围0-255。由于51的堆栈用的是内部寄存器,它只有128或256个字节,所以够用了。
在高级特殊运用中,可以利用SP进行程序重定位,从而增加反汇编破译程序的难度。
回复

使用道具 举报

ID:73992 发表于 2024-5-30 17:57 | 显示全部楼层
yzwzfyz 发表于 2024-5-30 09:22
SP的位置在81H,是个8位的内部寄存器,通常用于做堆栈指针,指针范围0-255。由于51的堆栈用的是内部寄存器 ...

感谢老哥慷慨!这种玩法比较飘逸,适合整点花活。感谢!!
                ORG        0000H
                LJMP        MAIN
MAIN:
                MOV        SP,#0X30
                LCALL        HBHB
                JMP        MAIN
HBHB:
                PUSH        ACC
                MOV        ACC,#0X01         ;1
                PUSH        ACC
                MOV        ACC,#0X02         ;2
                PUSH        ACC
                MOV        ACC,#0X03         ;3
                PUSH        ACC
                MOV        ACC,#0X04         ;4
                PUSH        ACC
                MOV        ACC,#0X05         ;5
                PUSH        ACC
                MOV        ACC,#0X06         ;6
                PUSH        ACC
                MOV        R0,SP                 ;R0保存栈顶
                LCALL        AFAF

                MOV        A,#0X30                 ;PC返回
                ADD        A,#0X03
                MOV        SP,A
                POP        ACC
                RET
AFAF:
                PUSH        ACC
                MOV        SP,R0                ;R0释放栈顶
                POP        ACC                        ;6
                MOV        R1,ACC
                POP        ACC                        ;5
                MOV        R2,ACC
                POP        ACC                        ;4
                MOV        R3,ACC
                POP        ACC                        ;3
                MOV        R4,ACC
                POP        ACC                        ;2
                MOV        R5,ACC
                POP        ACC                        ;1
                MOV        R6,ACC

                MOV        A,R0                ;
                ADD        A,#0X03                ;PC返回
                MOV        SP,A
                POP        ACC
                RET

                END
回复

使用道具 举报

ID:73992 发表于 2024-5-30 21:13 | 显示全部楼层
188610329 发表于 2024-5-28 17:10
莫名其妙的代码,也不知道到底要干什么,阏饷赐鍿P 不会直接用 R0 指针操作么?反正,最后你是要把指针放 ...

址应用场景有细微的不同,
回复

使用道具 举报

ID:879809 发表于 2024-5-30 22:01 | 显示全部楼层
               POP        ACC                        ;6
                MOV        R1,ACC
用一句话就行了
               POP        AR1                        ;6

这汇编学的也太水了。
回复

使用道具 举报

ID:73992 发表于 2024-6-2 23:35 | 显示全部楼层
yzwzfyz 发表于 2024-5-30 09:22
SP的位置在81H,是个8位的内部寄存器,通常用于做堆栈指针,指针范围0-255。由于51的堆栈用的是内部寄存器 ...

以下是移植到stm32的程序,写这个程序用了4天。前两天处理32变砖,后两天迷茫直到最后才调试出来。
“栈传递参数”一年多之前就有需求。在诸多朋友和老哥的指导下,直到现在才解决
;栈传参数测试        stm32
        AREA        DATA,CODE,READONLY
               
                                AREA        MASTER,CODE,READONLY
                                EXPORT        __main
                                ENTRY
               
__main

GG        BL        CCDE             ;调用CCDE
        B        GG


CCDE
        PUSH        {R4-R11,LR}
        MOV        R0,SP                        ;保存该程序栈
       
        LDR        R4,=0X11111111        ;数据压入栈A
        PUSH        {R4}
        LDR        R5,=0X22222222
        PUSH        {R5}
        LDR        R6,=0X33333333
        PUSH        {R6}
        LDR        R7,=0X44444444
        PUSH        {R7}
        LDR        R8,=0X55555555
        PUSH        {R8}
        LDR        R9,=0X66666666
        PUSH        {R9}
        LDR        R10,=0X77777777
        PUSH        {R10}
        LDR        R11,=0X88888888
        PUSH        {R11}
               
        MOV        R1,SP                        ;保存栈顶A
       
        BL        CCEF                        ;调用CCEF
       
        MOV        SP,R0                        ;恢复该程序栈
        POP                {R4-R11,LR}
        BX        LR
       
CCEF
        PUSH        {R4-R11,LR}
        MOV        R2,SP                        ;保存该程序栈
       
        MOV        SP,R1                        ;指向栈A
        POP        {R4}                ;取A栈值
        POP        {R5}
        POP        {R6}                ;取A栈值
        POP        {R7}
        POP        {R8}                ;取A栈值
        POP        {R9}
        POP        {R10}                ;取A栈值
        POP        {R11}
       
        MOV        SP,R2                        ;恢复该程序栈
        POP        {R4-R11,LR}
        BX        LR
       
        END

无标题.png

回复

使用道具 举报

ID:879809 发表于 2024-6-3 21:22 | 显示全部楼层
ARM函数调用有现成的应用程序二进制接口 (ABI) 规约,R0/R1是参数/结果寄存器,R2/R3是参数寄存器,如果有更多的入口参数才需要压栈。我就不懂你学了两年ARM汇编,还在搞这种重复发明轮子的无聊工作,而且你的轮子远远没有现成的标准轮子好用,除了浪费你的生命还有何等意义?
回复

使用道具 举报

ID:73992 发表于 2024-6-4 21:25 | 显示全部楼层
rundstedt 发表于 2024-6-3 21:22
ARM函数调用有现成的应用程序二进制接口 (ABI) 规约,R0/R1是参数/结果寄存器,R2/R3是参数寄存器,如果有 ...

程序需要对70多只引脚进行设置,寄存器直接赋值不易修改,也不不易检查。
单引脚赋值,一个LTORG又不够,超范围了。
因为引脚设置程序重复度高,所以用这种方法。用R0至R3传sp参数,确实是偷懒了,会尽量修改。
我很期望能有老师纠正我写的程序,程序之间的结构,写法等等,不然进步太慢。以下是部分程序,
  您提到的造轮子,三言两语不知道怎么回答。 无标题.png 无标题1.png

回复

使用道具 举报

ID:57657 发表于 2024-6-4 21:32 | 显示全部楼层
51单片机的SP是个堆栈寄存器,PUSH/POP/CALL/RET/RETI等指令、中断触发都会改变该寄存器的值,具体见数据手册。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表