请问下为什么除了1,2亮之外,别的灯也会有弱光,在主程序里加while循环后,又正常了。
1条回答 默认 最新
关注 ![](https://img-blog.csdnimg.cn/f5f82a9b6e794c4ebfce038cc7ad3fd9.png#pic_center =800x)
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#999000 对于嵌入式系统,如果没有运行RTOS,那么程序开发中的 主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。
关键词
: C51,main,程序退出graph LR A1([问题提出]) === A((目 录Contents)) style A fill:#63f,stroke:#ccc,stroke-width:5px,color:#FFF style A1 fill:#9f9,stroke:#3a3,stroke-width:2px A((目 录Contents)) === A2(程序去哪儿了?) style A2 fill:#9f9,stroke:#3a3,stroke-width:2px A2 --- B21([盘古开天辟地]) A2 --- B22(世界尽头) A3([总 结 ]) === A((目 录<br>Contents)) style A3 fill:#36f,stroke:#ccc,stroke-width:3px,color:#FFF
§01 问题提出
一个简单的C51程序如下:
#include <REGX51.H> void test(num) { switch(num) { case 1: P2_0=0; P2_1=0; break; } } void main(void) { test(1); }
程序执行完之后,可以看到实验板上的有两个LED被点亮,另外六个居然微微发亮。
![▲ 图1.1 实验板上的未点亮的LED居然微微发亮](https://img-blog.csdnimg.cn/05d64f1a7a2a4d1f8cda4e217f3f4b9a.png#pic_center =560x)
▲ 图1.1 实验板上的未点亮的LED居然微微发亮
如果在主程序中,增加一个无限循环:
while(1);
,则电路板上的就不再会出现“微微点亮”的现象了。#include <REGX51.H> void test(num) { switch(num) { case 1: P2_0=0; P2_1=0; break; } } void main(void) { test(1); while(1); }
![▲ 图1.2 实验板上后面六个LED就不再点亮了](https://img-blog.csdnimg.cn/7d255289d7d84795abdd6408a5cfbddd.png#pic_center =560x)
▲ 图1.2 实验板上后面六个LED就不再点亮了
上面两种情况的区别,在于第二个程序中 主循环
main()
函数始终没有退出,而第一个程序,main()
函数退出了。似乎前面LED 微微点亮 应该与 主函数 退出之后,单片机都干了些啥有关系。那么就剩下一个问题:
对于普通的嵌入式系统,C语言编程中 main()函数退出之后,程序去哪儿了?
§02 程序去哪儿了?
从上面提问者书写的代码来看,应该是一位C51的爱好者,使用的是C51的编译器,在一款C51开发板上愉快的进行实验。他一开始没有安装嵌入式程序开发的惯例 在主程序
void main(void)
中利用无限循环将程序控制在主程序函数中,就出现了前面实验结果中令人迷惑的情况。注: 佩服他是一个胆大心细的人,观察还挺仔细的。
2.1 盘古开天辟地
对于C语言编程来说,所有的用户程序世界是从主程序
main()
开始的。给用户程序开天辟地的任务是由 一小段 盘古代码STARTUP.A51
。关于C51是如何启动的, 在如下两篇博文中也被测试说明:
下面截取了 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 0E0H B DATA 0F0H SP DATA 81H DPL DATA 82H DPH 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 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 ; 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
上面的代码也被博文 https://blog.csdn.net/tangsun999/article/details/45604507 中进行逐步调试跟踪验证过:
![▲ 图2.1.1 显示LJMP C_START 就是进入 main() 程序](https://img-blog.csdn.net/20130605111957140#pic_center =560x )
▲ 图2.1.1 显示LJMP C_START 就是进入 main() 程序
2.2 世界尽头
由于进入main() 函数是长跳转,所以main函数是不会正常返回到启动程序 STARTUP.A51,那么程序去哪了?
在博文 https://blog.csdn.net/acai1123/article/details/16890933?locationNum=9&fps=1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-8.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.5&utm_relevant_index=11 中作者对于 KEIL编译器和PIC的 MAPLAB编译器对于main函数的最后时光进行了反汇编查看。
2.2.1 Keil编译器
在main函数的最后,程序增加了一下几行代码:
MOV R0, #0x7F CLR A MOV @R0, A DJNZ R0, (3) MOV SP, #0x0C LJMP main
这几条语句,前4条,是将我们单片机的内存的前128个地址清零,第5条,是定义堆栈,第6条,是将程序重新跳转到main函数的首行进行执行。
2.2.2 MAPLAB编译器
PIC 单片机语言程序进行跟踪,发现main() 函数最后一条语句为
reset
,也就是单片机直接复位,这是 MAPLAB编译器根据 PIC 单片机特点增加的复位语句。※ 总 结 ※
对于嵌入式系统,如果没有运行RTOS,那么程序开发中的 主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。
如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。
■ 相关文献链接:
- <input type="checkbox" disabled="" checked="" /> 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
- <input type="checkbox" disabled="" checked="" /> https://blog.csdn.net/ChenGuiGan/article/details/88769619
- <input type="checkbox" disabled="" checked="" /> https://blog.csdn.net/tangsun999/article/details/45604507
- <input type="checkbox" disabled="" checked="" /> https://blog.csdn.net/acai1123/article/details/16890933?locationNum=9&fps=1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-8.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.5&utm_relevant_index=11
● 相关图表链接:
- 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#987000
- 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#987001
- 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#987002
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 1无用
悬赏问题
- ¥15 代写uni代码,app唤醒
- ¥15 全志t113i启动qt应用程序提示internal error
- ¥15 ensp可以看看嘛.
- ¥80 51单片机C语言代码解决单片机为AT89C52是清翔单片机
- ¥60 优博讯DT50高通安卓11系统刷完机自动进去fastboot模式
- ¥15 minist数字识别
- ¥15 在安装gym库的pygame时遇到问题,不知道如何解决
- ¥20 uniapp中的webview 使用的是本地的vue页面,在模拟器上显示无法打开
- ¥15 网上下载的3DMAX模型,不显示贴图怎么办
- ¥15 关于#stm32#的问题:寻找一块开发版,作为智能化割草机的控制模块和树莓派主板相连,要求:最低可控制 3 个电机(两个驱动电机,1 个割草电机),其次可以与树莓派主板相连电机照片如下: