
Introduction: For embedded systems, if there is no RTOS running, the main function (main()) in program development needs to keep running indefinitely through some mechanism; it has no endpoint. If you want to exit the main function, what to do specifically is determined by the C language compiler used.
Keywords: C51, main, program exit
01 Problem Statement
Today, I saw an interesting question in CSDN’s Single Chip Microcontroller LED Module Definition Function Problem[1]. The questioner was conducting basic C51 programming experiments and wrote a simple C51 program as follows:
#include <REGX51.H>
void test(num) {
switch(num) {
case 1: P2_0=0; P2_1=0;
break;
}
}
void main(void) {
test(1);
}
The program executed successfully, and it was observed that two LEDs on the experimental board were lit, while the other six were surprisingly dimly lit.

If an infinite loop is added in the main program: while(1);, then the “dimly lit” phenomenon on the circuit board will no longer occur.
#include <REGX51.H>
void test(num) {
switch(num) {
case 1: P2_0=0; P2_1=0;
break;
}
}
void main(void) {
test(1);
while(1);
}

The difference between the two cases above is that in the second program, the main loop main() function never exits, while in the first program, the main() function exited. It seems that the dimly lit LEDs should be related to what the microcontroller does after the main function exits.
So there remains one question: For ordinary embedded systems, after the main() function exits in C language programming, where does the program go?
02 Where Does the Program Go?
From the code written by the questioner, it seems they are a C51 enthusiast, happily experimenting on a C51 development board with the C51 compiler. They initially did not install the embedded program development convention in the main program void main(void) to keep the program under control in the main function with an infinite loop, leading to the confusing experimental results mentioned earlier.
Note: They are a bold and meticulous person, and their observations are quite careful.
2.1 Pangu Creates the World
In C language programming, all user program worlds start with the main program main(). The task of creating the world for user programs is done by a small piece of Pangu code STARTUP.A51.
Regarding how C51 starts, it has also been tested and explained in the following blog:
- Execution Flow of 51 Microcontroller Program (STARTUP.A51 Manages Main Function Execution)[2]
Below is an excerpt from the STARTUP.A51 code, which shows that after the microcontroller RESET, Pangu does some preparatory work (initializing global variables, stack pointer) and then jumps directly to: ?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
The above code has also been debugged and verified step by step in the blog Execution Flow of 51 Microcontroller Program (STARTUP.A51)[3].

2.2 The End of the World
Since entering the main() function is a long jump, the main function will not normally return to the startup program STARTUP.A51. So where does the program go?
In the blog The While(1) Problem in Microcontroller C Language, the author analyzed the last moments of the main function for both the KEIL compiler and the PIC MAPLAB compiler by disassembling the code.
2.2.1 Keil Compiler
At the end of the main function, the program adds a few lines of code:
MOV R0, #0x7F
CLR A
MOV @R0, A
DJNZ R0, (3)
MOV SP, #0x0C
LJMP main
These statements, the first four, clear the first 128 addresses of our microcontroller’s memory, the fifth defines the stack, and the sixth jumps the program back to the beginning of the main function for execution.
2.2.2 MAPLAB Compiler
In tracking the PIC microcontroller language program, it was found that the last statement of the main() function is reset, which means the microcontroller directly resets. This reset statement is added by the MAPLAB compiler based on the characteristics of the PIC microcontroller.
※ Conclusion ※
For embedded systems, if there is no RTOS running, the main function (main()) in program development needs to keep running indefinitely through some mechanism; it has no endpoint.
If you want to exit the main function, what to do specifically is determined by the C language compiler used.
References
[1]
Single Chip Microcontroller LED Module Definition Function Problem: https://ask.csdn.net/questions/7640604?utm_medium=distribute.pc_feed_v2.none-task-ask-ask_personrec_tag-3.pc_personrecdepth_1-utm_source=distribute.pc_feed_v2.none-task-ask-ask_personrec_tag-3.pc_personrec
[2]
Execution Flow of 51 Microcontroller Program (STARTUP.A51 Manages Main Function Execution): https://blog.csdn.net/ChenGuiGan/article/details/88769619
[3]
Execution Flow of 51 Microcontroller Program (STARTUP.A51): https://blog.csdn.net/tangsun999/article/details/45604507