
對于嵌入式系統,如果沒有運行RTOS,那么程序開發中的主函數main()需要通過某種機制使其永遠愉快的運行下去,它沒有終點。如果想從main函數中退出,具體干什么是由所使用的C語言編譯器決定的。
今天在單片機led模塊定義函數中看到一個有趣的問題。提問者在進行基本的C51編程實驗,編寫了一個簡單的C51程序如下:
#include?
void?test(num)?{
????switch(num)?{
????????case?1:?P2_0=0;?P2_1=0;?
????????????break;
????}
}
void?main(void)?{
????test(1);
}
程序執行完之后,可以看到實驗板上的有兩個LED被點亮,另外六個居然微微發亮。

如果在主程序中,增加一個無限循環:while(1); ,則電路板上的就不再會出現“微微點亮”的現象了。
#include?
void?test(num)?{
????switch(num)?{
????????case?1:?P2_0=0;?P2_1=0;?
????????????break;
????}
}
void?main(void)?{
????test(1);
????while(1);
}

上面兩種情況的區別,在于第二個程序中主循環 main()函數始終沒有退出,而第一個程序,main()函數退出了。似乎前面LED微微點亮 應該與主函數退出之后,單片機都干了些啥有關系。
那么就剩下一個問題:對于普通的嵌入式系統,C語言編程中main()函數退出之后,程序去哪兒了?
從上面提問者書寫的代碼來看,應該是一位C51的愛好者,使用的是C51的編譯器,在一款C51開發板上愉快的進行實驗。他一開始沒有安裝嵌入式程序開發的慣例 在主程序void main(void)中利用無限循環將程序控制在主程序函數中,就出現了前面實驗結果中令人迷惑的情況。
“注:他是一個膽大心細的人,觀察還挺仔細的。
”
對于C語言編程來說,所有的用戶程序世界是從主程序main()開始的。給用戶程序開天辟地的任務是由一小段盤古代碼STARTUP.A51。
51單片機程序執行流程(STARTUP.A51管理Main函數的執行)
下面截取了STARTUP.A51 代碼的一段,可以看到盤古在單片機RESET之后做了點準備工作(初始化全局變量、堆棧指針)之后,就直接跳轉至:?C_START
?NAME?????C_STARTUP
?C_C51STARTUP???SEGMENT???CODE
?STACK??????????SEGMENT???IDATA
????????????????RSEG?????STACK
????????????????DS??????1
????????????????EXTRN?CODE?(?C_START)
????????????????PUBLIC???C_STARTUP
????????????????CSEG????AT??????0
?C_STARTUP:?????LJMP????STARTUP1
????????????????RSEG?????C_C51STARTUP
STARTUP1:
IF?IDATALEN?<>?0
????????????????MOV?????R0,#IDATALEN?-?1
????????????????CLR?????A
IDATALOOP:??????MOV?????@R0,A
????????????????DJNZ????R0,IDATALOOP
ENDIF
IF?XDATALEN?<>?0
????????????????MOV?????DPTR,#XDATASTART
????????????????MOV?????R7,#LOW?(XDATALEN)
??IF?(LOW?(XDATALEN))?<>?0
????????????????MOV?????R6,#(HIGH?(XDATALEN))?+1
??ELSE
????????????????MOV?????R6,#HIGH?(XDATALEN)
??ENDIF
????????????????CLR?????A
XDATALOOP:??????MOVX????@DPTR,A
????????????????INC?????DPTR
????????????????DJNZ????R7,XDATALOOP
????????????????DJNZ????R6,XDATALOOP
ENDIF
IF?PPAGEENABLE?<>?0
????????????????MOV?????PPAGE_SFR,#PPAGE
ENDIF
IF?PDATALEN?<>?0
????????????????MOV?????R0,#LOW?(PDATASTART)
????????????????MOV?????R7,#LOW?(PDATALEN)
????????????????CLR?????A
PDATALOOP:??????MOVX????@R0,A
????????????????INC?????R0
????????????????DJNZ????R7,PDATALOOP
ENDIF
IF?IBPSTACK?<>?0
EXTRN?DATA?(?C_IBP)
????????????????MOV??????C_IBP,#LOW?IBPSTACKTOP
ENDIF
IF?XBPSTACK?<>?0
EXTRN?DATA?(?C_XBP)
????????????????MOV??????C_XBP,#HIGH?XBPSTACKTOP
????????????????MOV??????C_XBP+1,#LOW?XBPSTACKTOP
ENDIF
IF?PBPSTACK?<>?0
EXTRN?DATA?(?C_PBP)
????????????????MOV??????C_PBP,#LOW?PBPSTACKTOP
ENDIF
????????????????MOV?????SP,#?STACK-1
????????????????LJMP?????C_START
????????????????END
上面的代碼也被博文51單片機程序執行流程(STARTUP.A51)中進行逐步調試跟蹤驗證過:

由于進入main()函數是長跳轉,所以main函數是不會正常返回到啟動程序STARTUP.A51,那么程序去哪了?
在博文單片機C語言while(1)的問題中作者對于KEIL編譯器和PIC的MAPLAB編譯器對于main函數的最后時光進行了反匯編查看。
Keil編譯器
在main函數的最后,程序增加了一下幾行代碼:
MOV?R0,?#0x7F
CLR?A
MOV?@R0,?A
DJNZ?R0,?(3)
MOV?SP,?#0x0C
LJMP?main
這幾條語句,前4條,是將我們單片機的內存的前128個地址清零,第5條,是定義堆棧,第6條,是將程序重新跳轉到main函數的首行進行執行。
MAPLAB編譯器
PIC 單片機語言程序進行跟蹤,發現main() 函數最后一條語句為 reset,也就是單片機直接復位,這是 MAPLAB編譯器根據 PIC 單片機特點增加的復位語句。
對于嵌入式系統,如果沒有運行RTOS,那么程序開發中的主函數(main())需要通過某種機制使其永遠愉快的運行下去,它沒有終點。如果想從main函數中退出,具體干什么是由所使用的C語言編譯器決定的。
1.中國芯片替代方案公司名單公布(70個類別)
2.為什么原理圖總畫不好?這些技巧要知道
3.嵌入式設備如何顯示IP屬地?
4.RISC-V面向MCU/MPU、RTOS,但面臨挑戰。。。
5.單片機固件自更新的一個方法!
6.玄鐵杯RISC-V應用創新大賽正式開賽,現開放報名!

免責聲明:本文系網絡轉載,版權歸原作者所有。如涉及作品版權問題,請與我們聯系,我們將根據您提供的版權證明材料確認版權并支付稿酬或者刪除內容。