0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

单片机led模块定义函数的问题

GReq_mcu168 来源:CSDN 作者:CSDN 2022-03-11 10:10 次阅读

简 介:对于嵌入式系统,如果没有运行RTOS,那么程序开发中的 主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。

01问题提出

今天在CSDN的 单片机led模块定义函数的问题[1]中看到一个有趣的问题。提问者在进行基本的C51编程实验,编写了一个简单的C51程序如下:

#include voidtest(num){ switch(num){ case1:P2_0=0;P2_1=0; break; } } voidmain(void){ test(1); }

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

25a78be2-8f01-11ec-952b-dac502259ad0.png

▲ 图1.1 实验板上的未点亮的LED居然微微发亮

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

#include voidtest(num){ switch(num){ case1:P2_0=0;P2_1=0; break; } } voidmain(void){ test(1); while(1); }

25c67dcc-8f01-11ec-952b-dac502259ad0.png

▲ 图1.2 实验板上后面六个LED就不再点亮了

上面两种情况的区别,在于第二个程序中 主循环main()函数始终没有退出,而第一个程序,main()函数退出了。似乎前面LED微微点亮应该与 主函数 退出之后,单片机都干了些啥有关系。

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

02程序去哪儿了?

从上面提问者书写的代码来看,应该是一位C51的爱好者,使用的是C51的编译器,在一款C51开发板上愉快的进行实验。他一开始没有安装嵌入式程序开发的惯例在主程序void main(void)中利用无限循环将程序控制在主程序函数中,就出现了前面实验结果中令人迷惑的情况。

注:他是一个胆大心细的人,观察还挺仔细的。

2.1 盘古开天辟地

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

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

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

下面截取了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)[3]中进行逐步调试跟踪验证过:

25e5150c-8f01-11ec-952b-dac502259ad0.jpg

▲ 图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函数的最后,程序增加了一下几行代码:

MOVR0,#0x7F CLRA MOV@R0,A DJNZR0,(3) MOVSP,#0x0C LJMPmain

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

2.2.2 MAPLAB编译器

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

※总  结 ※

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

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

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3590

    浏览量

    129459
  • C51
    C51
    +关注

    关注

    5

    文章

    283

    浏览量

    58087

原文标题:程序结束后去哪儿了?

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    51单片机-LED模块

    LED模块是通过74573锁存器芯片与单片机IO口连接,并与数码管共用IO口。
    的头像 发表于 05-23 09:14 8912次阅读
    51<b class='flag-5'>单片机</b>-<b class='flag-5'>LED</b>灯<b class='flag-5'>模块</b>

    定义单片机寄存器操作和模块接口相关的函数

    :/* 定义单片机寄存器操作和模块接口相关的函数, 方便在不同平台间移植 */// 单片机: STM32F103VE,
    发表于 12-13 07:43

    单片机控制的LED灯、最小系统及八路流水灯

    1、 单片机控制一个LED灯的C语言程序范例 单片机控制一个LED灯的C语言程序范例1: //用单片机点亮1个
    发表于 09-06 10:37 23次下载

    51单片机C语言延时函数怎么定义和使用

    比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。 以某晶振为12MHz的单片机为例,晶振为12MHz即一个机器周期为1us。
    发表于 11-16 17:06 8.5w次阅读

    如何使用单片机系统重写printf函数

    本文档的主要内容详细介绍的是如何使用单片机系统重写printf函数
    发表于 07-23 17:37 1次下载
    如何使用<b class='flag-5'>单片机</b>系统重写printf<b class='flag-5'>函数</b>

    51单片机定义端口和定时器中断与蜂鸣器报警程序等函数合集

    本文档的主要内容详细介绍的是51单片机定义端口和全局变量及定时器中断与蜂鸣器报警程序等函数合集免费下载。
    发表于 07-10 17:40 11次下载
    51<b class='flag-5'>单片机</b>的<b class='flag-5'>定义</b>端口和定时器中断与蜂鸣器报警程序等<b class='flag-5'>函数</b>合集

    使用MSP430F5529单片机控制LED同时闪烁的库函数免费下载

    本文档的主要内容详细介绍的是使用MSP430F5529单片机控制LED同时闪烁的库函数免费下载。
    发表于 07-24 08:00 10次下载
    使用MSP430F5529<b class='flag-5'>单片机</b>控制<b class='flag-5'>LED</b>同时闪烁的库<b class='flag-5'>函数</b>免费下载

    单片机模块学习

    单片机的几个寄存器学完了,就是对模块的学习,同时也有一些协议比如iic,spi,单线等等,高级的单片机会用到高级的协议LED数码管键盘串口
    发表于 11-14 14:36 1次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>模块</b>学习

    hc06蓝牙模块接51单片机点亮LED

    hc06蓝牙模块接51单片机点亮LED
    发表于 11-20 19:06 52次下载
    hc06蓝牙<b class='flag-5'>模块</b>接51<b class='flag-5'>单片机</b>点亮<b class='flag-5'>LED</b>

    51单片机 点亮一个LED LED闪烁

    ) //循环 { }}使用51单片机点亮一个LED#include <reg52.h> //51单片机头文件sbit LED=P2^0;
    发表于 11-23 17:06 5次下载
    51<b class='flag-5'>单片机</b> 点亮一个<b class='flag-5'>LED</b> <b class='flag-5'>LED</b>闪烁

    C语言&单片机不定参数个数的函数定义

    在学习使用C语言的时候都会告知main函数是可以接入多个参数的,那么问题来了,不定参数个数的函数如何定义的呢,它是否可以在单片机中使用呢定义
    发表于 11-29 09:51 8次下载
    C语言&<b class='flag-5'>单片机</b>不定参数个数的<b class='flag-5'>函数</b><b class='flag-5'>定义</b>

    串口调用单片机函数(c/c++)[自定义shell]

    调试单片机常用,参考正点原子USMART写了个简单的自用核心内容如下1、C语言(stm32)定义typedef struct ShellFun_CLASS{ void* func; //函数
    发表于 01-13 13:25 1次下载
    串口调用<b class='flag-5'>单片机</b><b class='flag-5'>函数</b>(c/c++)[自<b class='flag-5'>定义</b>shell]

    单片机led模块定义函数程序去哪了

    正常的程序,都不会跳出main,但是,如果跳出了 main 函数,程序到底去哪儿了,你有相关这个问题吗?
    的头像 发表于 08-25 10:42 922次阅读

    如何在单片机中使用malloc函数

    但是每个嵌入式 RTOS 都会有自己的内存管理方式,本文就来聊聊我对 malloc 函数单片机程序设计中的一些看法。 本文并不是要说明在单片机中怎么使用 malloc函数,而是
    的头像 发表于 04-24 09:50 2557次阅读
    如何在<b class='flag-5'>单片机</b>中使用malloc<b class='flag-5'>函数</b>

    单片机用按钮中断函数

    单片机用按钮中断函数  单片机中断是一种能够使单片机响应外部信号的机制,这种机制允许单片机在处理其他任务时去响应中断信号,从而提高
    的头像 发表于 09-01 10:17 1529次阅读