簡(jiǎn) 介:對(duì)于嵌入式系統(tǒng),如果沒(méi)有運(yùn)行RTOS,那么程序開(kāi)發(fā)中的 主函數(shù)(main())需要通過(guò)某種機(jī)制使其永遠(yuǎn)愉快的運(yùn)行下去,它沒(méi)有終點(diǎn)。如果想從main函數(shù)中退出,具體干什么是由所使用的C語(yǔ)言編譯器決定的。
01問(wèn)題提出
今天在CSDN的 單片機(jī)led模塊定義函數(shù)的問(wèn)題[1]中看到一個(gè)有趣的問(wèn)題。提問(wèn)者在進(jìn)行基本的C51編程實(shí)驗(yàn),編寫(xiě)了一個(gè)簡(jiǎn)單的C51程序如下:
#include
程序執(zhí)行完之后,可以看到實(shí)驗(yàn)板上的有兩個(gè)LED被點(diǎn)亮,另外六個(gè)居然微微發(fā)亮。
▲ 圖1.1 實(shí)驗(yàn)板上的未點(diǎn)亮的LED居然微微發(fā)亮
如果在主程序中,增加一個(gè)無(wú)限循環(huán):while(1);,則電路板上的就不再會(huì)出現(xiàn)“微微點(diǎn)亮”的現(xiàn)象了。
#include
▲ 圖1.2 實(shí)驗(yàn)板上后面六個(gè)LED就不再點(diǎn)亮了
上面兩種情況的區(qū)別,在于第二個(gè)程序中 主循環(huán)main()函數(shù)始終沒(méi)有退出,而第一個(gè)程序,main()函數(shù)退出了。似乎前面LED微微點(diǎn)亮應(yīng)該與 主函數(shù) 退出之后,單片機(jī)都干了些啥有關(guān)系。
那么就剩下一個(gè)問(wèn)題:對(duì)于普通的嵌入式系統(tǒng),C語(yǔ)言編程中 main()函數(shù)退出之后,程序去哪兒了?
02程序去哪兒了?
從上面提問(wèn)者書(shū)寫(xiě)的代碼來(lái)看,應(yīng)該是一位C51的愛(ài)好者,使用的是C51的編譯器,在一款C51開(kāi)發(fā)板上愉快的進(jìn)行實(shí)驗(yàn)。他一開(kāi)始沒(méi)有安裝嵌入式程序開(kāi)發(fā)的慣例在主程序void main(void)中利用無(wú)限循環(huán)將程序控制在主程序函數(shù)中,就出現(xiàn)了前面實(shí)驗(yàn)結(jié)果中令人迷惑的情況。
注:他是一個(gè)膽大心細(xì)的人,觀察還挺仔細(xì)的。
2.1 盤(pán)古開(kāi)天辟地
對(duì)于C語(yǔ)言編程來(lái)說(shuō),所有的用戶程序世界是從主程序main()開(kāi)始的。給用戶程序開(kāi)天辟地的任務(wù)是由 一小段盤(pán)古代碼STARTUP.A51。
關(guān)于C51是如何啟動(dòng)的, 在如下面博文中也被測(cè)試說(shuō)明:
51單片機(jī)程序執(zhí)行流程(STARTUP.A51管理Main函數(shù)的執(zhí)行)[2]
下面截取了STARTUP.A51代碼的一段,可以看到盤(pán)古在單片機(jī) RESET 之后做了點(diǎn)準(zhǔn)備工作(初始化全局變量、堆棧指針)之后,就直接跳轉(zhuǎn)至:?C_START
NAME?C_STARTUP ?C_C51STARTUPSEGMENTCODE ?STACKSEGMENTIDATA RSEG?STACK DS1 EXTRNCODE(?C_START) PUBLIC?C_STARTUP CSEGAT0 ?C_STARTUP:LJMPSTARTUP1 RSEG?C_C51STARTUP STARTUP1: IFIDATALEN<>0 MOVR0,#IDATALEN-1 CLRA IDATALOOP:MOV@R0,A DJNZR0,IDATALOOP ENDIF IFXDATALEN<>0 MOVDPTR,#XDATASTART MOVR7,#LOW(XDATALEN) IF(LOW(XDATALEN))<>0 MOVR6,#(HIGH(XDATALEN))+1 ELSE MOVR6,#HIGH(XDATALEN) ENDIF CLRA XDATALOOP:MOVX@DPTR,A INCDPTR DJNZR7,XDATALOOP DJNZR6,XDATALOOP ENDIF IFPPAGEENABLE<>0 MOVPPAGE_SFR,#PPAGE ENDIF IFPDATALEN<>0 MOVR0,#LOW(PDATASTART) MOVR7,#LOW(PDATALEN) CLRA PDATALOOP:MOVX@R0,A INCR0 DJNZR7,PDATALOOP ENDIF IFIBPSTACK<>0 EXTRNDATA(?C_IBP) MOV?C_IBP,#LOWIBPSTACKTOP ENDIF IFXBPSTACK<>0 EXTRNDATA(?C_XBP) MOV?C_XBP,#HIGHXBPSTACKTOP MOV?C_XBP+1,#LOWXBPSTACKTOP ENDIF IFPBPSTACK<>0 EXTRNDATA(?C_PBP) MOV?C_PBP,#LOWPBPSTACKTOP ENDIF MOVSP,#?STACK-1 LJMP?C_START END
上面的代碼也被博文 51單片機(jī)程序執(zhí)行流程(STARTUP.A51)[3]中進(jìn)行逐步調(diào)試跟蹤驗(yàn)證過(guò):
▲ 圖2.1.1 顯示LJMP C_START 就是進(jìn)入 main() 程序
2.2 世界盡頭
由于進(jìn)入main() 函數(shù)是長(zhǎng)跳轉(zhuǎn),所以main函數(shù)是不會(huì)正常返回到啟動(dòng)程序 STARTUP.A51,那么程序去哪了?
在博文單片機(jī)C語(yǔ)言while(1)的問(wèn)題中作者對(duì)于 KEIL編譯器和PIC的 MAPLAB編譯器對(duì)于main函數(shù)的最后時(shí)光進(jìn)行了反匯編查看。
2.2.1 Keil編譯器
在main函數(shù)的最后,程序增加了一下幾行代碼:
MOVR0,#0x7F CLRA MOV@R0,A DJNZR0,(3) MOVSP,#0x0C LJMPmain
這幾條語(yǔ)句,前4條,是將我們單片機(jī)的內(nèi)存的前128個(gè)地址清零,第5條,是定義堆棧,第6條,是將程序重新跳轉(zhuǎn)到main函數(shù)的首行進(jìn)行執(zhí)行。
2.2.2 MAPLAB編譯器
PIC 單片機(jī)語(yǔ)言程序進(jìn)行跟蹤,發(fā)現(xiàn)main() 函數(shù)最后一條語(yǔ)句為reset,也就是單片機(jī)直接復(fù)位,這是 MAPLAB編譯器根據(jù) PIC 單片機(jī)特點(diǎn)增加的復(fù)位語(yǔ)句。
※總??結(jié) ※
對(duì)于嵌入式系統(tǒng),如果沒(méi)有運(yùn)行RTOS,那么程序開(kāi)發(fā)中的 主函數(shù)(main())需要通過(guò)某種機(jī)制使其永遠(yuǎn)愉快的運(yùn)行下去,它沒(méi)有終點(diǎn)。
如果想從main函數(shù)中退出,具體干什么是由所使用的C語(yǔ)言編譯器決定的。
審核編輯 :李倩
-
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3630瀏覽量
129792 -
C51
+關(guān)注
關(guān)注
5文章
284瀏覽量
58306
原文標(biāo)題:程序結(jié)束后去哪兒了?
文章出處:【微信號(hào):mcu168,微信公眾號(hào):硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
定義與單片機(jī)寄存器操作和模塊接口相關(guān)的函數(shù)
單片機(jī)控制的LED燈、最小系統(tǒng)及八路流水燈
51單片機(jī)C語(yǔ)言延時(shí)函數(shù)怎么定義和使用
如何使用單片機(jī)系統(tǒng)重寫(xiě)printf函數(shù)
![如何使用<b class='flag-5'>單片機(jī)</b>系統(tǒng)重寫(xiě)printf<b class='flag-5'>函數(shù)</b>](https://file.elecfans.com/web1/M00/9E/1C/o4YBAF02uxWAKWETAAI75dv1pvw201.png)
51單片機(jī)的定義端口和定時(shí)器中斷與蜂鳴器報(bào)警程序等函數(shù)合集
![51<b class='flag-5'>單片機(jī)</b>的<b class='flag-5'>定義</b>端口和定時(shí)器中斷與蜂鳴器報(bào)警程序等<b class='flag-5'>函數(shù)</b>合集](https://file.elecfans.com/web1/M00/9B/D9/o4YBAF0lYS2ALd2MAAREMAnbIbc608.png)
使用MSP430F5529單片機(jī)控制LED同時(shí)閃爍的庫(kù)函數(shù)免費(fèi)下載
![使用MSP430F5529<b class='flag-5'>單片機(jī)</b>控制<b class='flag-5'>LED</b>同時(shí)閃爍的庫(kù)<b class='flag-5'>函數(shù)</b>免費(fèi)下載](https://file.elecfans.com/web1/M00/9E/7D/pIYBAF03yHSARRHEAAWHiO7Okvs650.png)
單片機(jī)模塊學(xué)習(xí)
![<b class='flag-5'>單片機(jī)</b><b class='flag-5'>模塊</b>學(xué)習(xí)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
51單片機(jī) 點(diǎn)亮一個(gè)LED LED閃爍
![51<b class='flag-5'>單片機(jī)</b> 點(diǎn)亮一個(gè)<b class='flag-5'>LED</b> <b class='flag-5'>LED</b>閃爍](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
C語(yǔ)言&單片機(jī)不定參數(shù)個(gè)數(shù)的函數(shù)定義
![C語(yǔ)言&<b class='flag-5'>單片機(jī)</b>不定參數(shù)個(gè)數(shù)的<b class='flag-5'>函數(shù)</b><b class='flag-5'>定義</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
串口調(diào)用單片機(jī)函數(shù)(c/c++)[自定義shell]
![串口調(diào)用<b class='flag-5'>單片機(jī)</b><b class='flag-5'>函數(shù)</b>(c/c++)[自<b class='flag-5'>定義</b>shell]](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
單片機(jī)led模塊定義函數(shù)程序去哪了
如何在單片機(jī)中使用malloc函數(shù)
![如何在<b class='flag-5'>單片機(jī)</b>中使用malloc<b class='flag-5'>函數(shù)</b>](https://file1.elecfans.com/web2/M00/82/2B/wKgZomRF3-OABuXVAAEWmxRADY8851.jpg)
評(píng)論