今天在网上看到这么一个单片机复位的程序,这个程序据说是一个大三的学生写出来的,不错,写的很有必定的道理,其C编程也达到了必定程度了【小盒子我仍是很敬服这个人的】。下面咱们来看看这个代码:
void main(void)
{
unsignedcharcoderst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};//复位代码
(*((void(*)())(rst)))();//履行上一行代码,将rst数组当函数调用
}
榜首句界说一个数组rst[],数组内数据便是完结复位功用的汇编机器码,详细对应关系为:
clra==0xe4、pushacc==0xc0,0xe0、reti==0x32
能够看出其程序起到复位的作用,彻底便是汇编机器码的劳绩。
而单片机复位的更好办法
clra//铲除ACC=0
pushacc//压0到仓库——8位
pushacc//再压0到仓库——再8位
reti//返回到0地址,重新履行。
这种复位办法比较费事,愈加简略的复位写法是(摘自《C缺点与圈套》):
(*(void(*)())0)();
看过上面更简略的复位办法,让咱们多加考虑一下,为什么要写成0?其他不行吗?换成其他后会是什么样的作用呢?抱着这个主意,我亲身通过KEIL V2.4.0编译后的汇编程序:
能够看出若将(*(void(*)())0)();
改成(*(void(*)())3)();
则程序会跳转到main()函数开端,避开startup文件的初始化……
只所以我说的是会从main()开端,是因为我看过编译后的汇编文件,找到main的实践物理地址罢了,不然我也不会写成3了。呵呵……下面便是编译后的汇编成果
C:0x0003 E4 CLR A
C:0x0004 F508 MOV 0x08,A
C:0x0006 F509 MOV 0x09,A
14: while(1) {
15: if(i == 10) {
16: //( *( ( void (*)( ) ) (rst) ) )(); // 履行上一行代码,将rst数组当函数调用
C:0x0008 E509 MOV A,0x09
C:0x000A 640A XRL A,#0x0A
C:0x000C 4508 ORL A,0x08
C:0x000E 7005 JNZ C:0015
17: ( *( ( void (*)( ) ) (3) ) )(); // 履行上一行代码,将rst数组当函数调用
C:0x0010 120003LCALL main(C:0003)
18: } else {
C:0x0013 80F3 SJMP C:0008
19: i++;
C:0x0015 0509 INC 0x09
C:0x0017 E509 MOV A,0x09
C:0x0019 70ED JNZ C:0008
C:0x001B 0508 INC 0x08
20: }
为了进行给我们一个很好的比较,从视觉上得到必定的感觉,我又再次将3改回成0,我们看看编译后的汇编成果是什么姿态的;
下面的代码是函数(*(void(*)())0)(); 这个编译后的成果
C:0x0003 E4 CLR A
C:0x0004 F508 MOV 0x08,A
C:0x0006 F509 MOV 0x09,A
14: while(1) {
15: if(i == 10) {
16: //( *( ( void (*)( ) ) (rst) ) )(); // 履行上一行代码,将rst数组当函数调用
C:0x0008 E509 MOV A,0x09
C:0x000A 640A XRL A,#0x0A
C:0x000C 4508 ORL A,0x08
C:0x000E 7005 JNZ C:0015
17: ( *( ( void (*)( ) ) (0) ) )(); // 履行上一行代码,将rst数组当函数调用
C:0x0010 120000LCALL C_STARTUP(C:0000)
18: } else {
C:0x0013 80F3 SJMP C:0008
19: i++;
C:0x0015 0509 INC 0x09
C:0x0017 E509 MOV A,0x09
C:0x0019 70ED JNZ C:0008
C:0x001B 0508 INC 0x08
20: }
请我们留意赤色的部分。