專(zhuān)注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

51系列單片機(jī)的軟件復(fù)位方法

作者:文于鷹   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2013年12月06日   【字體:

      在單片機(jī)系統(tǒng)的應(yīng)用中,我們經(jīng)常需要用到復(fù)位技術(shù)來(lái)實(shí)現(xiàn)抗干擾。有的單片機(jī)(如8098)有專(zhuān)門(mén)的復(fù)位指令,某些增強(qiáng)型MCS-51系列單片機(jī)雖然沒(méi)有復(fù)位指令,但片內(nèi)集成了WATCHDOG電路,可以很容易實(shí)現(xiàn)復(fù)位。而普及型MCS-51系列單片機(jī)(如8031和8032)既無(wú)復(fù)位指令,又不帶硬件WATCHDOS,如果不外接硬件WATCHDOG,就必須采用軟件復(fù)位技術(shù)。所謂軟件復(fù)位就是用一系列指令來(lái)模仿復(fù)位操作。在MCS-51系列單片機(jī)中,只要用指令使程序從起始地址(0x0000)開(kāi)始執(zhí)行,就可以復(fù)位單片機(jī)。本文介紹三種用C語(yǔ)言實(shí)現(xiàn)軟件復(fù)位的簡(jiǎn)單方法

 

方法一:

void Reset(void)

{  unsigned char code rst[ ]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};

(*((void (*)(void))(rst)))();

}

先來(lái)看一下這段程序編譯后的匯編碼:

C:0x0015  E4      CLR    A          //清除ACC=0

C:0x0016  C0E0    PUSH  ACC(0xE0)   //壓0到堆棧——8位

C:0x0018  C0E0    PUSH  ACC(0xE0)   //再壓0到堆棧——再8位

C:0x001A  32      RETI               // 清除中斷激活標(biāo)志并返回到0x0000執(zhí)行

C:0x001B  020015  LJMP   C:0015

可以發(fā)現(xiàn),數(shù)組rst[]中的內(nèi)容恰恰是上面前四行的匯編機(jī)器碼,即程序中將代碼當(dāng)作數(shù)組的數(shù)據(jù)來(lái)存儲(chǔ)。再來(lái)研究后面的那句函數(shù)調(diào)用(*((void (*)(void))(rst)))(),rst是數(shù)組名(即數(shù)組首元素地址),(void(*)(void))是函數(shù)指針的強(qiáng)制類(lèi)型轉(zhuǎn)換運(yùn)算,(void(*)(void))(rst)是將數(shù)組名rst強(qiáng)制轉(zhuǎn)換成一個(gè)無(wú)參數(shù)無(wú)返回值的函數(shù)的指針,指向rst的首地址。只需調(diào)用(*((void (*)(void))(rst)))(),即可將數(shù)組中的數(shù)據(jù)當(dāng)作函數(shù)代碼來(lái)運(yùn)行,因?yàn)闊o(wú)論是數(shù)據(jù)還是代碼都是以二進(jìn)制存儲(chǔ)的,本質(zhì)上是相同的。

方法二:

void Reset(void)

{   ( * ( void (*)( ) )0 ) ( );

}

這段程序摘自《C缺陷與陷阱》,比方法一中的更為簡(jiǎn)潔。與方法一類(lèi)似,它也是使用函數(shù)指針的強(qiáng)制類(lèi)型轉(zhuǎn)換運(yùn)算將函數(shù)指針指向一個(gè)非函數(shù)的地址,但不同的是它直接指向程序起始地址0x0000,方法一先指向數(shù)組rst,再利用數(shù)組中的機(jī)器碼使程序跳轉(zhuǎn)到0x0000。它編譯后的匯編只有一句LCALL  C_STARTUP(C:0000)。

方法三:

void Reset(void)

{  VoidFunc();   //請(qǐng)注意,函數(shù)VoidFunc()在程序中未定義

}

上面的VoidFunc()函數(shù)雖然沒(méi)有定義,但在Keil環(huán)境中編譯時(shí)只是警告,并不報(bào)錯(cuò)。編譯后的匯編碼為L(zhǎng)JMP  C_STARTUP(C:0000),同方法二極為相似,使程序跳轉(zhuǎn)到0x0000開(kāi)始執(zhí)行,同樣實(shí)現(xiàn)了軟件復(fù)位的功能。這種做法最為簡(jiǎn)單,但不符合ANSI C標(biāo)準(zhǔn)中函數(shù)應(yīng)先定義后調(diào)用的要求,在其它某些環(huán)境中可能無(wú)法編譯通過(guò),因此不推薦。

總結(jié)

      我們知道,在MCS-51單片機(jī)的所有指令中,只有RETI指令能清除中斷請(qǐng)求標(biāo)志。因此只有方法一能在中斷子程序中被調(diào)用,方法二和方法三都不能,否則系統(tǒng)復(fù)位后,中斷請(qǐng)求標(biāo)志仍在,可能造成系統(tǒng)剛復(fù)位就錯(cuò)誤地進(jìn)入了中斷子程序。實(shí)際應(yīng)用中應(yīng)根據(jù)實(shí)際情況,選擇合適的方法。

關(guān)閉窗口

相關(guān)文章