For embedded systems, if there is no RTOS running, the main function main()
in program development needs to use some mechanism to keep running happily forever; it has no endpoint. If you want to exit the main
function, what happens specifically is determined by the C language compiler used.
1. The Question Raised
Today, I saw an interesting question in the microcontroller LED module definition function. 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);
}
After the program executed, 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 will no longer appear on the circuit board.
#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 situations is that in the second program, the main loop main()
function never exits, while in the first program, the main()
function exits. It seems that the previously dimly lit LEDs should be related to what the microcontroller does after the main function exits.
So, one question remains: For ordinary embedded systems, what happens to the program after the main()
function exits in C programming?
2. Where Does the Program Go?
From the code written by the questioner, it can be seen that he is a C51 enthusiast using the C51 compiler, happily conducting experiments on a C51 development board. Initially, he did not install the convention of embedded program development, using an infinite loop in the main program void main(void)
to keep the program controlled within the main function, which led to the confusing results observed earlier.
“
Note: He is a bold and meticulous person, and observes quite carefully.
”
2.1 The Creation of the World
In C programming, all user program worlds begin with the main program main()
. The task of creating the user program world is performed by a small piece of startup code STARTUP.A51
.
The execution flow of the 51 microcontroller program (managed by STARTUP.A51
for the execution of the Main
function)
Below is an excerpt from the STARTUP.A51
code, which shows that after the microcontroller RESET
, it does some preparatory work (initializing global variables, stack pointer) and then directly jumps to:<span>?C_START</span>
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 step-debugged and verified in the blog post about the execution flow of the 51 microcontroller program (STARTUP.A51
).

2.2 The End of the World
Since entering the main()
function is a long jump, the main
function does not normally return to the startup program STARTUP.A51
. So where does the program go?
In the blog post about the problem of while(1)
in microcontroller C language, the author viewed the disassembly of the final moments of the main
function in the KEIL compiler and the PIC MAPLAB
compiler.
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
The first four statements clear the first 128 addresses of the microcontroller’s memory, the fifth defines the stack, and the sixth jumps the program back to the first line of the main
function for execution.
MAPLAB Compiler
In the PIC microcontroller language program tracking, 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 use some mechanism to keep running happily forever; it has no endpoint. If you want to exit the main
function, what happens specifically is determined by the C language compiler used.
1. No)
2. Why Can’t I Draw the Schematic Well? These Tips to Know
3. How Do Embedded Devices Display IP Location?
4. RISC-V Facing MCU/MPU, RTOS, but Facing Challenges…
5. A Method for Self-Updating Firmware in Microcontrollers!
6. The Xuan Tie Cup RISC-V Application Innovation Competition Officially Starts, Registration Now Open!
Disclaimer: This article is a network reprint, and the copyright belongs to the original author. If there are any copyright issues, please contact us, and we will confirm the copyright based on the copyright certificate you provide and pay remuneration or delete the content.