簡 介: 對(duì)于嵌入式系統(tǒng),如果沒有運(yùn)行RTOS,那么程序開發(fā)中的 主函數(shù)(main())需要通過某種機(jī)制使其永遠(yuǎn)愉快的運(yùn)行下去,它沒有終點(diǎn)。如果想從main函數(shù)中退出,具體干什么是由所使用的C語言編譯器決定的。
01 問題提出
今天在CSDN的 單片機(jī)led模塊定義函數(shù)的問題[1] 中看到一個(gè)有趣的問題。提問者在進(jìn)行基本的C51編程實(shí)驗(yàn),編寫了一個(gè)簡單的C51程序如下:
#include
voidtest(num){
switch(num){
case1:P2_0=0;P2_1=0;
break;
}
}
voidmain(void){
test(1);
}
??程序執(zhí)行完之后,可以看到實(shí)驗(yàn)板上的有兩個(gè)LED被點(diǎn)亮,另外六個(gè)居然微微發(fā)亮。
??如果在主程序中,增加一個(gè)無限循環(huán):while(1);
,則電路板上的就不再會(huì)出現(xiàn)“微微點(diǎn)亮”的現(xiàn)象了。
#include
voidtest(num){
switch(num){
case1:P2_0=0;P2_1=0;
break;
}
}
voidmain(void){
test(1);
while(1);
}
??上面兩種情況的區(qū)別,在于第二個(gè)程序中 主循環(huán) main()
函數(shù)始終沒有退出,而第一個(gè)程序,main()
函數(shù)退出了。似乎前面LED 微微點(diǎn)亮 應(yīng)該與 主函數(shù) 退出之后,單片機(jī)都干了些啥有關(guān)系。
那么就剩下一個(gè)問題:對(duì)于普通的嵌入式系統(tǒng),C語言編程中 main()函數(shù)退出之后,程序去哪兒了?
02 程序去哪兒了?
從上面提問者書寫的代碼來看,應(yīng)該是一位C51的愛好者,使用的是C51的編譯器,在一款C51開發(fā)板上愉快的進(jìn)行實(shí)驗(yàn)。他一開始沒有安裝嵌入式程序開發(fā)的慣例在主程序void main(void)
中利用無限循環(huán)將程序控制在主程序函數(shù)中,就出現(xiàn)了前面實(shí)驗(yàn)結(jié)果中令人迷惑的情況。
注:他是一個(gè)膽大心細(xì)的人,觀察還挺仔細(xì)的。
2.1 盤古開天辟地
??對(duì)于C語言編程來說,所有的用戶程序世界是從主程序 main()
開始的。給用戶程序開天辟地的任務(wù)是由 一小段 盤古代碼 STARTUP.A51
。
??關(guān)于C51是如何啟動(dòng)的, 在如下面博文中也被測(cè)試說明:
- 51單片機(jī)程序執(zhí)行流程(STARTUP.A51管理Main函數(shù)的執(zhí)行)
??下面截取了 STARTUP.A51 代碼的一段,可以看到盤古在單片機(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)中進(jìn)行逐步調(diào)試跟蹤驗(yàn)證過:
▲ 圖2.1.1 顯示LJMP C_START 就是進(jìn)入 main() 程序
2.2 世界盡頭
??由于進(jìn)入main() 函數(shù)是長跳轉(zhuǎn),所以main函數(shù)是不會(huì)正常返回到啟動(dòng)程序 STARTUP.A51,那么程序去哪了?
??在博文 單片機(jī)C語言while(1)的問題 中作者對(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
??這幾條語句,前4條,是將我們單片機(jī)的內(nèi)存的前128個(gè)地址清零,第5條,是定義堆棧,第6條,是將程序重新跳轉(zhuǎn)到main函數(shù)的首行進(jìn)行執(zhí)行。
2.2.2 MAPLAB編譯器
??PIC 單片機(jī)語言程序進(jìn)行跟蹤,發(fā)現(xiàn)main() 函數(shù)最后一條語句為 reset
,也就是單片機(jī)直接復(fù)位,這是 MAPLAB編譯器根據(jù) PIC 單片機(jī)特點(diǎn)增加的復(fù)位語句。
總??結(jié)
對(duì)于嵌入式系統(tǒng),如果沒有運(yùn)行RTOS,那么程序開發(fā)中的 主函數(shù)(main())需要通過某種機(jī)制使其永遠(yuǎn)愉快的運(yùn)行下去,它沒有終點(diǎn)。
如果想從main函數(shù)中退出,具體干什么是由所使用的C語言編譯器決定的。
原文標(biāo)題:程序結(jié)束后去哪兒了?
文章出處:【微信公眾號(hào):嵌入式ARM】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6037文章
44569瀏覽量
636140 -
C語言
+關(guān)注
關(guān)注
180文章
7606瀏覽量
137052 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4333瀏覽量
62721
原文標(biāo)題:程序結(jié)束后去哪兒了?
文章出處:【微信號(hào):gh_c472c2199c88,微信公眾號(hào):嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論