MCS-51系列单片机在目前和今后的相当一段时间内都将是我国的单片机主流机种。但在早期的开发过程中,程序员不得不从深奥的汇编语言开始摸索,同时要求开发人员对硬件亦有相当的子解。相比而言,专用8051系列单片机设计的Franklin C51语言是一种通用的高级结构化的程序设计语言。入门容易,程序可读性强,调试、移植都很方便,故开发效率高,尤其在数值运算处理方便具有很大的优势(这正是ASM51汇编语言的薄弱环节)。不过,C语言虽然也可对计算机的硬件系统进行操作,但在处理特殊I/O口和中断向量方面,不如汇编那样直接、有效。因而,在效率为重的今天,将ASM51汇编与C51语言结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。

1 、汇编与C51的混合编程

一般的做法都是利用C51上手容易、便于理解的优势来编写主程序,在C51语言不便处理或者效率比较低时调用汇编函数。考虑到MCS-51(尤其是 8031内部的资源配置情况:可用的RAM不到256字节,5个固定地址的有限中断源,4个8位并口中实际可作I/O口的只有P1口。因而要求开发都对单片机的内部结构有清楚的了解,并尽可能地统筹安排这些资源。事实也证明,不理解汇编语言是很难写出高效程序的。故笔者的观点是利用汇编语言对I/O接口、中断向量及程序空间分配的茂大优势,让程序员对MCS-51内的第一个字节甚至是每一比特(可位寻址的空间)全部进行统筹安排,设计好各个程序模块,包括 I/O口地址和中断向量地址的处理;同时在具体的数据处理、通信等不需要过多与硬件直接打交道的程序模块中,充分利用C51语言强大高效的编程能力。

最后的关键是如何让汇编模块能正确识别C51函数并调用它来完成相应的功能。ASM51汇编与C51语言之间的调用约定并不简单,而且各种编译器使用的约定不尽相同,甚至还依赖于程序所选择的大、中、小存储模式。通常每个需传递的参数按调用顺序和类型分别由约定的寄存器来传递。如果参数过多或者无足够寄存器可用时,参数的传递将在固定持存储器区域内进行,相同类型的参数共享一个参数传递段,按参数调用顺序递增其存放地址,返回值也由约定的寄存器或地址段返回。由此可见程序调用的效率必将受到接口复杂度的影响。尽管目前的单片机仿真器已经提供了标准接口的全自动转换功能,减少了接口工作量,但在程序的调试及移植中,如果程序员不了解这些接口的各种约定,将对出现的错误不知所措。比如返回值不止一个时,编译器自己就无法正确完成接口配置。这里力荐一种简洁有效的调用方法——无参数化调用。

2 、ASM51无参数化调用C51函数的实现原理

所谓的无参数化调用是指让C51子函数不带任何参数,这样就可以从根本上避开调用参数的传递和返回值的安排等繁琐易出错的问题,只需要简单地在汇编语言开头说明一下外部C51子函数(“EXTRN code()”)。至于C51函数中需要使用的外部参数值及其返回值,完全可以通过加入C51的< absacc.h>头文件来解决。

头文件中的函数原型为:

# define CBYTE((unsigned char *)0x50000L)

# define DBYTE ((unsigned char *)0x50000L)

# define PBYTE ((unsigned char *)0x50000L)

# define XBYTE((unsigned char *)0x50000L)

其中CBYTE定义为寻址CODE程序区;DBYTE定义为寻址DATA数据区;PBYTE定义为寻址相对于MOVX @R0"指令的分页数据XDATA区;XBYTE定义为寻址相对于MOVX @DPTR"指令的分布数据XDATA区。它们的类型决定了绝对地址空间的位置。

引进该头文件后,程序员就可以对8051系列单片机的存储器进行绝对地址的访问,把对参数值和返回值的操作转化为对存储器绝对地址的操作,像纯汇编操作一样,根本不用定义C51函数与汇编接口的参数和返回值的配置,从而提高了调用效率。具体做法是:先在C51函数中定义好传递参数和返回值所需要的各个绝对地址(视程序员自己的空间配置而定),在其它汇编模块中将C51函数中将要使用的参数值放入这些绝对地址中,把被调用C51模块将输出的计算值(可以不止一个)也放入类似的绝对地址中。于是,当C51函数中需要使用某个参数值时,就直接从相应的绝对地址中读取该值;当别的汇编模块中需要使用C51函数返回值时,也直接对存放返回值的绝对地址进行读操作即可。下面以一个调试通过的汇编调用C51函数的简单程序为例进行具体说明。

3 、ASM51无参数化调用C51函数的实现示例

该系统要示然而单片机根据实时采样输入的转速实现机车速度的测量,并可随键盘输入的车轮直径变化实时调整车速,最后将车速和轮径值都显示出来。设计任务很简单,编程中的最大难度就在于车速的计算程序。由于轮径值要求精确到mm(最大值超过了1000),车速的计算结果要保留到小数点后一位,因此需要进行浮点数运算,期间还要完成数的各种进制间的换算。虽然算法简单,但实际用汇编语言实现起来经常考虑不周,调试起来费时费力(笔者调试通过的这段汇编代码长达近400行)。这样,自然就想到调用C51函数了,充发发挥两种语言的优势。先用汇编语言设计好各个模块,包括循环显示车速和轮径值的主程序模块,响应采样转速值和键盘输入两个中断模块,代码如下所示。

EXTRN CODE(CALL1);声明外部C51函数

ORG0000H

LJMPMAIN

ORG0003H

AJMPKEYINPUT;键盘输入中断

ORG000BH

AJMPSETTIME;采样时间到,采样转速值中断

ORG0100H

KEYINPUT:……;键盘输入中断

……;将键盘输入信号保存在

;70h~73h的地址空间中

RETI

ORG0600H

SETTIME:……;采样时间到,采样转速值中断

……;将转速值放置在地址为3Ah的空间中

;紧接着调用外部C51函数CALL1()进

;行车速的计算

LCALLCALL1

RETI

ORG2000H;主程序模块

MAIN:……;首先进行初始化操作

……

;直接从地址空间70h~77h中读取显示数据,循环显示车速和轮径值

END

这些小模块用汇编实现起来不仅容易,而且程序员可以清楚地了解到各个模块的出入口及其相应的功能,实现对程序空间的充分配置。最后用C51语言来实现车速的计算模块CALL1()。以前用汇编编写的近400行代码,一下子被压缩到20~30行(真正的计算代码仅9行),不仅简短易懂,而且几乎就不需要调试了。

下面的代码是计算模块CALL1()及其需要的绝对地址定义。

#pragma code small

#include

#include

#define PI 3.1415926

#define NCIRCLE DBYTE[0x3A] //定义放置转速的绝对地址

#define DIRECT1 DBYTE[0x70] //定义放置轮径千位的绝对地址

#define DIRECT2 DBYTE[0x71] //定义放置轮径百位的绝对地址

#define DIRECT3 DBYTE[0x72] //定义放置轮径十位的绝对地址

#define DIRECT4 DBYTE[0x73] //定义放置轮径个位的绝对地址

#define VELOCITY1 DBYTE[0x74] //定义返回车速的千位绝对地址

#define VELOCITY2 DBYTE[0x75] //定义返回车速的百位绝对地址

#define VELOCITY3 DBYTE[0x76] //定义返回车速的十位绝对地址

#define VELOCITY4 DBYTE[0x77] //定义返回车速的个位绝对地址

voidcall1()

{

floatdata result;

intdata DIRECT;

DIRECT=DIRECT1*1000+DIRECT2*100+DIRECT3*10+DIRECT4;

result=(DIRECT/1000.0)*PI*NCIRCLE*3.6;

VELOCITY1=result/100;

Result=result-VELOCITY1*100;

VELOCITY2=result/10;

result=result-CELOCITY 2*10;

VELOCITY3=result;

result=result-VELOCITY3;

VELOCITY4=result*10;

}

在本例中定义了绝对地址空间70h~77H和3AH。其中3AH存放采样转速值输入模块输入的转速;70H~73H的地址空间中存放键盘输入中断模块中键盘输入的轮径值;而地址为74H~77H的空间中则存放计算模块中的车速计算返回值。尽管需要传递和返回的参数比较多,但通过这些绝对地址的定义,完全解决了原来复杂的汇编与C51之间的调用接口配置。计算模块中需要使用转速和轮径值时,将自动从绝对地址3AH和70H~73H中取值;在循环显示车速和轮径值的主程序模块中则直接读取绝对地址空间70H~77H的各个数据进行循环显示。当然,程序员可以根据自己的空间配置另外定义这些绝对地址。

以上程序代码均已在Dais-52.196P仿真器上顺利调试通过。

由上面的简单程序可以看出这种无参数化调用方法的优越性和有效:从程序代码看,无论是编写C51子程序还是汇编主程序,都与编写纯C51函数或者纯汇编主程序的格式完全一样,从根本上简化了C51与汇编函数之间的接口编程,提高了程序调用的效率;充分利用了汇编与高测验C51语言各自的优点,开发、调试快速方便,通用性强,尤其适合于初学者。对于复杂程序,同样可以利用无参数化方法来帮助实现。这对于提高单片机应用程序的开发效率很有意义。

无参数化调用实质上在C51函数中定义了几个全局变量(绝对地址),依靠它们直接完成参数值的传递和返回值的调用,相当于一种程序员自定义的传递方式,抛弃了传统C与汇编之间的接口约定。只要程序员安排得当,还可以进一步人工实现C51中的动态覆盖重用,提高RAM区的利用效率。由上也可看出:无参数化调用方法要在ASM汇编调用C51函数时才分依速无参数化思想,就违背了利用C51编程,过衷,得不偿失。当然,如果开发人员已经对C51与汇编函数之间的参数传递接口很熟悉,完全可以按接口约定或者由编译器自动完成参数的传递。

c51汇编语言extrn data,ASM51调用C51函数的实现相关推荐

  1. c 汇编语言用标准函数代替,调用C标准库的exit函数

    在上一篇文章中,实现了对大于号(>)的处理,那么对if表达式的编译也就是信手拈来的事了,不解释太多.在本篇中,将会讲述一下如何产生可以调用来自于C语言标准库的exit(3)函数的汇编代码. 在C ...

  2. 汇编语言调用c语言ads,ADS1.2 在汇编代码中调用C函数

    EDA365欢迎您登录! 您需要 登录 才可以下载或查看,没有帐号?注册 x , U) b) }+ U8 \" d/ v( \$ ~  T对于ARM体系来说,不同语言撰写的函数之间相互调用( ...

  3. 【Keil5 C51】AT89C52 做流水灯实验(调用C51的库函数_crol_)

    _crol_ 函数的介绍 Cx51 User's Guide Summary #include <intrins.h>unsigned char _crol_ (unsigned char ...

  4. 在中断函数和MAIN函数中同时调用同一个函数的有趣现象

    此处的信息适用于: C51所有版本 症状 我添加了一个中断处理程序(ISR)到我的项目中,然而我却得到了如下的警告: ***WARNING L15: MULTIPLE CALL TO SEGMENT ...

  5. Go 学习笔记(16)— 函数(02)[函数签名、有名函数、匿名函数、调用匿名函数、匿名函数赋值给变量、匿名函数做回调函数]

    1. 函数签名 函数类型也叫做函数签名,可以使用 fmt.Printf("%T") 格式化参数打印函数类型. package mainimport "fmt"f ...

  6. 读书笔记 effective c++ Item 5 了解c++默认生成并调用的函数

    1 编译器会默认生成哪些函数  什么时候空类不再是一个空类?答案是用c++处理的空类.如果你自己不声明,编译器会为你声明它们自己版本的拷贝构造函数,拷贝赋值运算符和析构函数,如果你一个构造函数都没有声 ...

  7. 【转】Jquery -Ajax 入门练习 Jquery.Ajax 调用后台函数,获取DataTable Json,Asp.net

    直接上图=============最后拷贝源码(图片清楚) ====================================================================== ...

  8. python函数文档说明调用方式_Python 跨.py文件调用自定义函数说明

    0 前言 os.chdir() :用于改变当前python工作的目录到指定的路径 sys.path:是python搜索模块的一个路径集,为list,自定义的包可以把存放路径加进去,之后直接调用包名就行 ...

  9. vue函数如何调用其他函数?_从源码中学Vue(一)生命周期中的钩子函数的那点事儿...

    欢迎来到我的<从源码中学Vue>专题系列文章,更多精彩内容持续更新中,欢迎关注 :) Vue作为当下前端最流行的框架之一,在国内占绝对的优势.所以接下来我们一起来学习它吧! 我不会像其它人 ...

  10. glBegin()和glEnd()之间可调用的函数

    原 glBegin()和glEnd()之间可调用的函数 2016年10月11日 12:44:15 PersonFly_小逗 阅读数 645更多 分类专栏: OPENGL 版权声明:本文为博主原创文章, ...

最新文章

  1. JAVA多线程之Synchronized、wait、notify实例讲解
  2. 清华特奖答辩前10出炉,两名CS学生3篇顶会一作,有人周读3000页英文论文!
  3. gRPC 网关,针对 HTTP 2.0 长连接性能优化,提升吞吐量
  4. html5 css 笔记,HTML5+CSS3笔记
  5. C语言百度翻译API的使用,c语言怎么翻译? 程序怎么运行?
  6. 1-3 数组的反序输出
  7. 视觉与听觉相结合的深度跨域情绪识别
  8. android简易跑马灯
  9. 一维非齐次热传导方程的紧致差分格式(附Matlab代码)
  10. 初学者福利:分享五个免费的 Python 学习网站,抓紧收藏吧
  11. 逍遥模拟器1 android,逍遥安卓模拟器5.1.1
  12. Java家庭收支记账程序
  13. 全网疯传,谷歌BAT员工「LeetCode刷题手册」,1400+超详细算法题讲解。
  14. 如何学IT?零基础入门自学Java编程系列:java简介跟计算机常识
  15. 软件工程-笔记(未整理)
  16. python pymysql cursors_怎么Pythonpymysql.cursors从mysql存储过程获取INOUT返回结果
  17. PS不能存储,因为程序错误
  18. Android之UiAutomator测试框架源码分析(第三篇:UiDevice功能介绍)
  19. 项目的开发流程(大公司)
  20. FPGA从入门到精通(4) - MUX

热门文章

  1. DOTFUN XML Silverlight中文留言簿Beta V1.0 即将上线!
  2. Html页面增加返回顶部图标和隐藏出现
  3. 前端面试有这几篇就够了--HTML篇
  4. 2018 ideal 链接数据_利用 IDEA HTTP 请求文件访问 API 接口
  5. linux自带python_【经验总结】linux 安装python (替换系统自带的python版本)
  6. jquery $.post 超时_详解如何实现前端jquery中的ajax方法,看这一篇就够了
  7. BNU 斩(超级大水题)
  8. Sum nyoj 欧拉定理简单运用(数论入门)
  9. html tab标签_如何用HTML写一个网页
  10. 【POJ2352】Stars(树状数组模版题)