编写一个简单的C51程序

发布者:keiss2018最新更新时间:2023-07-17 来源: elecfans关键字:编写  C51  程序 手机看文章 扫描二维码
随时随地手机看文章

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


01 问题提出

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

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

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


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

#includevoidtest(num){switch(num){case1:P2_0=0;P2_1=0;break;
}
}voidmain(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_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)中进行逐步调试跟踪验证过:

915c6e02-92f3-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,#0x7FCLRA
MOV@R0,A
DJNZR0,(3)
MOVSP,#0x0CLJMPmain

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


2.2.2 MAPLAB编译器

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


总结

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


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


关键字:编写  C51  程序 引用地址:编写一个简单的C51程序

上一篇:51单片机最小系统的构成与绘制
下一篇:51单片机对智能温控器的设计

推荐阅读最新更新时间:2024-11-11 11:38

数据极值查找程序设计
  数据极值查找就是在指定的数据区中找出最大值(或最小值)。      极值查找操作的主要内容是进行数值大小的比较,从这批数据中找出最大值(或最小值)并存于某一单元中。       片内RAM中存放一批数据,查找出最大值并存放于首地址中。设RO中存放首地址,R2中存放字节数,程序框图如图所示。 程序如下:
[单片机]
数据极值查找<font color='red'>程序</font>设计
C程序中的缓冲输入设计
缓冲输入,很早之前就听说过这个概念,一直不怎么理解。后来,一听到缓冲,脑子就昏沉沉的。其实,缓冲输入也没啥大不了的,只要有打破砂锅想到底的精神,就能扫除以前所有的似是而非。 缓冲输入(buffered input ),就是说输入时键入的一系列字符不是直接发给程序,而是被存放在一个叫做缓冲区的临时存储单元里。也就是说,这些字符以序列(sequence)的形式暂存于缓冲区,然后等程序一个一个地取(fetch one by one)。 那么,这些字符是怎样进入缓冲区的呢?通过enter键。不过别忘了,enter建也是一个字符,所以,缓冲区里的字符串总是应该以enter键结束的。(当然,还有另外一种情况,键盘缓冲区是有空间限制的,填满之后
[单片机]
12864图形点阵液晶显示模块51程序
// 12864图形点阵液晶显示模块程序 (不带字库) // 根据金鹏电子程序修改 #include stdio.h #include reg52.h #include absacc.h #define disp_off 0x3e // 显示关 #define disp_on 0x3f // 显示开 #define disp_x 0xb8 // 页地址 #define disp_z 0xc0 // 行地址 #define disp_y 0x40 // 列地址 #define comm 0 // 命令 #define dat 1 // 数据 #define lc
[单片机]
stc单片机不断电下载程序
stc单片机支持串口isp程序下载,不必使用专用下载器,仅使用串口就能下载程序。但每次下载程序都要断电再上电,比较麻烦。 下面介绍一种不需断电就能下载程序的方法,在程序调试时比较方便。 基本原理: stc单片机有专用的复位寄存器,通过对该寄存器写入不同的数值可以实现单片机热启动复位。 寄存器功能如下图所示: 由上图可以看出只要满足某个条件,向ISP_CONTR写入0x60,就可以实现从ISP监控区软启动启动 某个条件设置为:当串口接收到0xaa数据时,单片机执行ISP_CONTR=0x60; 指令,从ISP监控区软启动启动。 演示程序如下: //*************************STC12C541
[单片机]
stc单片机不断电下载<font color='red'>程序</font>
lcd12864显示遥控键值读取程序
LCD 12864显示遥控键值读取程序 #include reg51.h #include intrins.h #define uchar unsigned char #define uint unsigned int /*TS12864A-3 端口定义*/ #define LCD_data P0 //数据口 sbit LCD_RS = P2^0; //寄存器选择输入 sbit LCD_RW = P2^1; //液晶读/写控制 sbit LCD_EN = P2^2; //液晶使能控制 sbit LCD_PSB = P2^3; //串/并方式控制 sbit LCD_R
[单片机]
4*4矩阵键盘模块程序的调用
产生.lib文件的方法:选择 工程 目标target属性 输出 产生库文件*.lib,修改完后,编译一下程序,无措后,就在工程目录下产生一个.lib文件,到时要用到这个模块程序时,直接把.c和.lib文件拷贝到所在的目录下,再把.c的文件加载到工程文件里就OK了。 /* *************************************************************************************** 摘 要: 4*4小键盘模块程序,供以后其他程序调用.其中P2口高四位接键盘列,P2口低四位接键盘行, 版 本: V1.0 完成日期: 2008.4.28 作 者: ZHOUSFE
[单片机]
如何在C51文件和汇编语言文件中相互调用?
如何在C51文件和汇编语言文件中相互调用对方文件中的函数? 答:汇编语言文件中对于函数的调用方法,与调用汇编语言中的函数一样,如: LCALL DISPLAY 在C语言文件中调用汇编语言中的函数,必须先声明再调用。声明格式如下: extern 返回值类型 函数名(参数表); 例如: extern unsigned char right_shift ( char, char );
[单片机]
基于单片机的温湿度实时监控的程序设计
51单片机STC89C52RC是本方案的选用芯片,以其8位处理和极低的价格来看,是很适合进行本次实验。LCD显示屏本次选用的型号是1602A。 在实现51单片机实现温湿度传感器实时监控并LCD显示的基础功能后,还可以通过单片机的串口通信和WIFI模块或者Zigbee模块进行物联网连接,使设备连接互联网,再通过TCP连接进行物联网的一整套方案,包括手机APP实时监控数据,也可以是手机APP远程开启风扇来调节温度或者湿度,但这些不在本次方案中细说,本人已经实现上述功能,只是技术不完善,所以不在此公布。 51单片机内部程序: C #include#include#include#include#include#include t
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved