ARM汇编如何返回分支起始位置?程序跳转后无法回归问题求助
问题分析与解决方案
看起来你遇到的问题是BlinkBoth函数执行完毕后无法回到主循环的分支起始位置,而是直接流入了Wait循环的代码里。这是因为你的BlinkBoth函数缺少返回主调用点的关键指令,同时主循环的闭环逻辑也需要补全。
具体问题拆解:
- 当你用
blne BlinkBoth调用BlinkBoth时,ARM会把当前下一条指令的地址存入lr(链接寄存器),但你的BlinkBoth函数执行完最后一条swi SWI_SETLED后,没有任何指令把lr的值送回pc(程序计数器),导致程序不会返回主循环,而是继续执行后续的Wait标签代码。 - 主循环没有添加循环跳转指令,程序执行一次按键检查后就会直接结束,无法持续检测按键状态。
修改后的完整代码:
MainLoop: ; 主循环标签,实现持续检测按键 swi SWI_CheckBlue cmp r0, #0 blne BlinkBoth ; 调用BlinkBoth,lr保存此处下一条指令地址 b MainLoop ; 回到主循环开头,持续检测按键 BlinkBoth: mov r0,#(LEFT_LED|RIGHT_LED) swi SWI_SETLED ldr r3,=500 BL Wait ; 调用Wait,lr保存mov r0,#0的地址 mov r0,#0 swi SWI_SETLED ldr r3,=500 ; 让灭灯状态也持续500时间单位(可按需移除) BL Wait mov pc, lr ; 关键:将lr中的主循环地址加载到pc,返回分支起始位置 Wait: stmfd sp!,{r0-r5,lr} ; 保存寄存器与lr,避免上下文混乱 ldr r4,=0x00007FFF @mask for 15-bit timer SWI SWI_GetTicks @Get start time and r1,r0,r4 @adjusted time to 15-bit Wloop: SWI SWI_GetTicks @Get current time and r2,r0,r4 @adjusted time to 15-bit cmp r2,r1 blt Roll @rolled above 15 bits sub r5,r2,r1 @compute easy elapsed time bal CmpLoop Roll: sub r5,r4,r1 @compute rolled elapsed time add r5,r5,r2 CmpLoop:cmp r5,r3 @is elapsed time < delay? blt Wloop @Continue with delay ldmfd sp!,{r0-r5,pc} ; 恢复寄存器,pc=lr,返回Wait的调用点
关键修改说明:
- 添加
MainLoop标签和b MainLoop指令:让程序持续循环检测按键状态,不会执行一次就结束。 - 在
BlinkBoth函数末尾添加mov pc, lr:这会把blne BlinkBoth时存入lr的主循环指令地址加载到pc,确保执行完闪烁逻辑后回到主循环的分支位置。 - 补充灭灯后的等待逻辑:让LED的亮、灭状态都保持固定时长,闪烁效果更符合预期(不需要的话可以删除对应的
ldr r3,=500和BL Wait)。
内容的提问来源于stack exchange,提问作者EmmanoelD97
相关产品推荐
相关产品推荐

