用C语言写的程序为求模块化,一般函数数量较多,函数调用的嵌套层数也多,要从一个较深的嵌套立刻跳出到主函数,是非常困难的。用break或者return是跳不出来的,一般的解决方法或是使用C51的库函数setjmp()和longjmp()实现长跳转,但是这两个函数在中断函数内部是无能为力的;再或是在C函数中嵌入汇编。虽然用汇编指令可以实现程序的长距离跳转,但是这种方法的调试过程十分烦琐,而且程序的可移植性差。对于习惯用C51编程而不想用汇编的设计者,该部分程序是一个难题。
我们可以利用keil软件的绝对地址跳转,((void(code *)(void))0x00)(); keil软件编译时会转换成jmp 0x00,就跳到指定的绝对地址了;
但这又有些不方便,我们想跳到任何我们想跳到的地方去,而程序一改动,绝对地址又会变,所以我们需要一个函数能够取得我们要跳转的绝对地址,但又不能直接读取程序计数器PC(绝对地址);
方法还是有的:因为单片机c语言调用函数或者进入中断时,都要线把PC压入堆栈去,而SP值是可以读的,因此调用函数,把堆栈里的值(PC)读出保存,作为跳转的据对地址;例程如下:
ff0()
{
....................................
JmpAddr=Get_Jmp_Addr();//------------取要跳转地址
.........................................
}
long Get_Jmp_Addr(void)
{ long address;
address=*((unsigned char *)SP);
address <<= 8;
address+=*((unsigned char *)(SP-1));
return address+5;
}
ff1()
{
.........................
((void(code *)(void))JmpAddr)();
................................
}
希望对大家有帮助!!
另 转 其实uboot里面就有例子,不过今天看到一个TI的,也贴出来,实际差不了多少:
定义:
Uint32 gEntryPoint;
static void (*APPEntry)(void);
用法:
APPEntry = (void (*)(void)) gEntryPoint;
(*APPEntry)();