单片机程序结束后去哪儿了?

发布时间:2024-10-30 16:05:15  
对于嵌入式 系统,如果没有运行RTOS,那么程序开发中的 主函数(main())需要通过某种机制使其永远运行下去,它没有终点。 如果想从main函数中退出, 具体干什么是由所使用的C语言编译器决定的。 【付费】STM32嵌入式资料包

问题提出

在进行基本的C51编程实验,编写了一个简单的C51程序如下:

#include <REGX51.H>
void test(num) { switch(num) { case 1: P2_0=0; P2_1=0; break; }}
void main(void) { test(1);}

程序执行完之后,可以看到实验板上的有两个LED被点亮,另外六个居然微微发亮。

图片

如果在主程序中,增加一个无限循环:while(1); ,则电路板上的就不再会出现“微微点亮”的现象了。

图片

图片
如上图,实验板上后面六个LED就不再点亮了。

上面两种情况的区别,在于第二个程序中主循环main()函数始终没有退出,而第一个程序,main() 函数退出了。

似乎前面LED微微点亮应该与主函数退出之后,单片机都干了些啥有关系。

那么就剩下一个问题:对于普通的嵌入式系统,C语言编程中main()函数退出之后,去哪儿了?

程序去哪儿了?

上面使用的是C51的编译器,在一款C51开发板上进行的实验。他一开始没有按照嵌入式程序开发的惯例:在主程序void main(void) 中利用死循环将程序控制在主程序函数中,就出现了前面实验结果中令人迷惑的情况。

1 开天辟地

对于C语言编程来说,所有的用户程序世界是从主程序 main()  开始的。给用户程序开天辟地的任务是由一小段盘古代码STARTUP.A51。

关于C51是如何启动的, 在如下面博文中也被测试说明:

  • 51单片机程序执行流程(STARTUP.A51管理Main函数的执行)[2]

下面截取了 STARTUP.A51 代码的一段,可以看到盘古在单片机 RESET 之后做了点准备工作(初始化全局变量、堆栈指针)之后,就直接跳转至:?C_START

$NOMOD51;------------------------------------------------------------------------------;  This file is part of the C51 Compiler package;  Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.;  Version 8.01;;  *** <<< Use Configuration Wizard in Context Menu >>> ***;------------------------------------------------------------------------------;  STARTUP.A51:  This code is executed after processor reset.;;  To translate this file use A51 with the following invocation:;;     A51 STARTUP.A51;;  To link the modified STARTUP.OBJ file to your application use the following;  Lx51 invocation:;;     Lx51 your object file list, STARTUP.OBJ  controls;;------------------------------------------------------------------------------; Standard SFR Symbols ACC     DATA    0E0HB       DATA    0F0HSP      DATA    81HDPL     DATA    82HDPH     DATA    83H

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 AIDATALOOP: MOV @R0,A DJNZ R0,IDATALOOPENDIF

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 AXDATALOOP: MOVX @DPTR,A INC DPTR DJNZ R7,XDATALOOP DJNZ R6,XDATALOOPENDIF

IF PPAGEENABLE <> 0 MOV PPAGE_SFR,#PPAGEENDIF

IF PDATALEN <> 0 MOV R0,#LOW (PDATASTART) MOV R7,#LOW (PDATALEN) CLR APDATALOOP: MOVX @R0,A INC R0 DJNZ R7,PDATALOOPENDIF

IF IBPSTACK <> 0EXTRN DATA (?C_IBP)

MOV ?C_IBP,#LOW IBPSTACKTOPENDIF

IF XBPSTACK <> 0EXTRN DATA (?C_XBP)

MOV ?C_XBP,#HIGH XBPSTACKTOP MOV ?C_XBP+1,#LOW XBPSTACKTOPENDIF

IF PBPSTACK <> 0EXTRN DATA (?C_PBP) MOV ?C_PBP,#LOW PBPSTACKTOPENDIF

MOV SP,#?STACK-1

; This code is required if you use L51_BANK.A51 with Banking Mode 4;<h> Code Banking; <q> Select Bank 0 for L51_BANK.A51 Mode 4#if 0 ; <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.EXTRN CODE (?B_SWITCH0) CALL ?B_SWITCH0 ; init bank mechanism to code bank 0#endif;</h> LJMP ?C_START

                END

上面的代码也被博文 51单片机程序执行流程(STARTUP.A51)[3] 中进行逐步调试跟踪验证过:

图片
上图显示LJMP C_START 就是进入 main() 程序。

2 世界尽头

由于进入main() 函数是长跳转。

所以main函数是不会正常返回到启动程序 STARTUP.A51的。

那么程序去哪了?

在博文 单片机C语言while(1)的问题 中作者对于 KEIL编译器和PIC的 MAPLAB编译器对于main函数的最后时光进行了反汇编查看。

3 Keil编译器

在main函数的最后,程序增加了一下几行代码:

MOV R0, #0x7FCLR AMOV @R0, ADJNZ R0, (3)MOV SP, #0x0CLJMP main

这几条语句,前4条,是将我们单片机的内存的前128个地址清零,第5条,是定义堆栈,第6条,是将程序重新跳转到main函数的首行进行执行。

4 MAPLAB编译器

PIC 单片机语言程序进行跟踪,发现main() 函数最后一条语句为 reset,也就是单片机直接复位,这是 MAPLAB编译器根据 PIC 单片机特点增加的复位语句。

总结

如果单片机程序 从main函数中退出,具体干什么是由所使用的C语言编译器决定的。

对于嵌入式系统,如果没有运行RTOS,那么程序开发中的主函数(main())需要通过某种机制使其永远运行下去,它没有终点。

参考资料

[1]

单片机led模块定义函数的问题 : 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]

51单片机程序执行流程(STARTUP.A51管理Main函数的执行) : https://blog.csdn.net/ChenGuiGan/article/details/88769619

[3]

51单片机程序执行流程(STARTUP.A51) : https://blog.csdn.net/tangsun999/article/details/45604507

来源

https://blog.csdn.net/zhuoqingjoking97298/article/details/122836855

文章来源于:单片机与嵌入式    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>