新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > ASM5无参数化调用C51函数的实现

ASM5无参数化调用C51函数的实现

作者:时间:2012-03-08来源:网络收藏

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

1 汇编与C51的混合编程

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

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

2 ASM51C51函数的实现原理

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

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函数

ORG 0000H

LJMP MAIN

ORG 0003H

AJMP KEYINPUT ;键盘输入中断

ORG 000BH

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

ORG 0100H

KEYINPUT:…… ;键盘输入中断

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

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

RETI

ORG 0600H

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

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

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

;行车速的计算

LCALL CALL1

RETI

ORG 2000H ;主程序模块

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

……

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

END


上一页 1 2 下一页

评论


相关推荐

技术专区

关闭