页面加载中,请稍候
来源:电子工程世界发布时间:2022-08-28307浏览
询问 AI▲更多精彩内容请点击上方蓝字关注我们吧!
正常的程序,都不会跳出main,但是,如果跳出了 main 函数,程序到底去哪儿了,你有相关这个问题吗?
一、问题提出今天在单片机led模块定义函数中看到一个有趣的问题。提问者在进行基本的C51编程实验,编写了一个简单的C51程序如下:
#include<REGX51.H>
voidtest(num){
switch(num){
case1:P2_0=0;P2_1=0;
break;
}
}
voidmain(void){
test(1);
}
程序执行完之后,可以看到实验板上的有两个LED被点亮,另外六个居然微微发亮。

如果在主程序中,增加一个无限循环:while(1); ,则电路板上的就不再会出现“微微点亮”的现象了。
#include<REGX51.H>
voidtest(num){
switch(num){
case1:P2_0=0;P2_1=0;
break;
}
}
voidmain(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_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单片机程序执行流程(STARTUP.A51)中进行逐步调试跟踪验证过:

由于进入main()函数是长跳转,所以main函数是不会正常返回到启动程序STARTUP.A51,那么程序去哪了?
在博文单片机C语言while(1)的问题中作者对于KEIL编译器和PIC的MAPLAB编译器对于main函数的最后时光进行了反汇编查看。
Keil编译器
在main函数的最后,程序增加了一下几行代码:
MOVR0,#0x7F
CLRA
MOV@R0,A
DJNZR0,(3)
MOVSP,#0x0C
LJMPmain
这几条语句,前4条,是将我们单片机的内存的前128个地址清零,第5条,是定义堆栈,第6条,是将程序重新跳转到main函数的首行进行执行。
MAPLAB编译器
PIC 单片机语言程序进行跟踪,发现main() 函数最后一条语句为 reset,也就是单片机直接复位,这是 MAPLAB编译器根据 PIC 单片机特点增加的复位语句。
总结对于嵌入式系统,如果没有运行RTOS,那么程序开发中的主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。
来源:TsinghuaJoking推荐阅读
干货 | 一份不错的LDO电容选型指南
添加微信回复“进群”
拉你进技术交流群!
国产芯|汽车电子|物联网|新能源|电源|工业|嵌入式…..
在公众号内回复您想搜索的任意内容,如问题关键字、技术名词、bug代码等,就能轻松获得与之相关的专业技术内容反馈。快去试试吧!
如果您想经常看到我们的文章,可以进入我们的主页,点击屏幕右上角「三个小点」,点击「设为星标」。
欢迎扫码关注



新闻来源:电子工程世界,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!

2026-07-06
2026-06-05

2026-07-09