简 介: 对于嵌入式系统,如果没有运行rtos,那么程序开发中的 主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的c语言编译器决定的。
01 问题提出
今天在csdn的 单片机led模块定义函数的问题[1] 中看到一个有趣的问题。提问者在进行基本的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()函数退出之后,程序去哪儿了?
02 程序去哪儿了?
从上面提问者书写的代码来看,应该是一位c51的爱好者,使用的是c51的编译器,在一款c51开发板上愉快的进行实验。他一开始没有安装嵌入式程序开发的惯例在主程序void main(void) 中利用无限循环将程序控制在主程序函数中,就出现了前面实验结果中令人迷惑的情况。
注:他是一个胆大心细的人,观察还挺仔细的。
2.1 盘古开天辟地
对于c语言编程来说,所有的用户程序世界是从主程序 main() 开始的。给用户程序开天辟地的任务是由 一小段 盘古代码 startup.a51。
关于c51是如何启动的, 在如下面博文中也被测试说明:
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_c51startupstartup1:if idatalen 0 mov r0,#idatalen - 1 clr aidataloop: mov @r0,a djnz r0,idataloopendifif 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,xdataloopendifif ppageenable 0 mov ppage_sfr,#ppageendifif pdatalen 0 mov r0,#low (pdatastart) mov r7,#low (pdatalen) clr apdataloop: movx @r0,a inc r0 djnz r7,pdataloopendifif ibpstack 0extrn data (?c_ibp) mov ?c_ibp,#low ibpstacktopendifif xbpstack 0extrn data (?c_xbp) mov ?c_xbp,#high xbpstacktop mov ?c_xbp+1,#low xbpstacktopendifif pbpstack 0extrn data (?c_pbp) mov ?c_pbp,#low pbpstacktopendif mov sp,#?stack-1 ljmp ?c_start end 上面的代码也被博文 51单片机程序执行流程(startup.a51) 中进行逐步调试跟踪验证过:
▲ 图2.1.1 显示ljmp c_start 就是进入 main() 程序 2.2 世界尽头 由于进入main() 函数是长跳转,所以main函数是不会正常返回到启动程序 startup.a51,那么程序去哪了?
在博文 单片机c语言while(1)的问题 中作者对于 keil编译器和pic的 maplab编译器对于main函数的最后时光进行了反汇编查看。
2.2.1 keil编译器 在main函数的最后,程序增加了一下几行代码:
mov r0, #0x7fclr amov @r0, adjnz r0, (3)mov sp, #0x0cljmp main 这几条语句,前4条,是将我们单片机的内存的前128个地址清零,第5条,是定义堆栈,第6条,是将程序重新跳转到main函数的首行进行执行。
2.2.2 maplab编译器 pic 单片机语言程序进行跟踪,发现main() 函数最后一条语句为 reset,也就是单片机直接复位,这是 maplab编译器根据 pic 单片机特点增加的复位语句。
总 结
对于嵌入式系统,如果没有运行rtos,那么程序开发中的 主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。
如果想从main函数中退出,具体干什么是由所使用的c语言编译器决定的。
原文标题:程序结束后去哪儿了?
文章出处:【微信公众号:嵌入式arm】欢迎添加关注!文章转载请注明出处。
三相四线制供电系统中线的作用
数字万用表如何检测电解电容?
【新专利介绍】能够进行多路切换传输的无线压力变送器
首款无线充电笔记本Latitude 7285开卖:1750美元起
深度剖析医疗物联网16大应用场景
编写一个简单的C51程序
华硕ARES战神卡轻松挑落两项3DMark Vantage世
安华高科技首次在40nm硅芯上取得20 Gbps的SerDe
电烙铁漏电的原因_电烙铁漏电如何处理
基于PXA255处理器和LTV350QV-F05实现GPS显示系统的设计
共赴新征程 维谛Vertiv:按下山东“新基建”发展加速键
澎湃微荣获“MCU创新先锋奖”
Dash与加密货币平台VegaWallet在区块链支付协议应用上开展合作
漫步者M0pro拆解 内外双修形神兼备
健身中心使用无源UHF RFID解决方案 旨在管理管理毛巾并防止毛巾丢失
高性能制冷红外焦平面探测器项目荣获湖北省科技进步一等奖
LoRa模块参数配置失败的原因
干货合集!六位嘉宾精彩观点,带你读懂半导体发展新风向
特斯拉发布第5级自动驾驶,什么概念?
国产在线测流,看中海达新“水平”