福州福建省电子技术研究所(350001)庄文斌 福州北京邮电大学福建分校(350003) 林 颖 来自:电子技术应用
摘要:利用C51全局及外部变量,可实现无参数化调用A51函数,不但避免开了传统C51调用C51时繁琐的接口约定,而且把在A51中所用到的变量全部放至C51程序中而不必考虑变量在内存中的位置,使编程更加简洁。用实例验证了该方法的优越性和有效性。
关键词:C51 A51 汇编语言 无参数化调用
<<电子技术应用>>2001年第7期发表苟帅的文章“ASM51无参数化调用C51函数的实现”,阐述了ASM51无参数化调用C51函数的实现原理并给出实例来验证该方法的优越性和可行性。作者在文章中表明这样一种观点:“利用汇编语言对I/O接口、中断向量及程序空间分配的巨大优势,让程序员对MCS51内的每一字节甚至是每一比特(可位寻址空间)全部进行统筹安排,设计好各个程序模块,包括I/O口地址和中断向量地址的处理;同时在具体数据处理、通信等不需要过多与硬件打交道的程序模块中,充分利用C51语言强大高效的编程能力”。上述观点并没有错,但是对I/O接口、中断向量及程序空间分配及MCS-51内的每一个字节甚至是每一比特(可位寻址空间)全部进行统筹安排,对于大多数程序员来讲恰恰是件不容易的事。地址空间、栈的起始地址和中断向量地址的分配等,经常顾此失彼,这边可行,那边又出问题。其实完全可以把上述繁重的工作交给C51去完成,由C51定义各个变量并自动分配各个变量的空间,而集中精力完成所需功能的A51程序设计。笔者在研制基于C51、插拔式DFLASH存储器的无纸记录仪中,就是利用全局及外部变量实现C51无参数化调用A51函数的,取得了很好的效果。
1 C51无参数化调用A51函数的实现原理
为了说明其原理,必须理解局部变量、全局变量和外部变量的意义。
局部变量:是在函数内部定义的变量,只在定义它的函数内部有效,仅在使用它时,才为它分配内存单元。
全局变量:又称外部变量,是在函数外部定义的变量,可以为多个函数共同使用,其有效作用范围是从它定义的位置开始直到整个程序文件结束。若一个全局变量不是在程序文件开始处定义的,但又希望在它的定义点之前的函数中引用该变量,这时应在引用该变量的函数中用关键字EXTERN将其说明为外部变量。此外如果一个程序模块文件中应用另一个程序模块中定义的变量时,也必须用EXTERN进行说明。全局变量在整个程序的执行过程中都要占用内存单元。
外部变量(EXTERN):使用存储种类说明符EXTERN定义的变量称为外部变量。按照缺省规则,凡在所有函数之前,在函数外部定义的变量都是外部变量,定义时可以不写EXTERN说明符。但是,在一个函数体内说明一个在该函数体外或别的程序模块文件中定义过的外部变量时,则必须使用EXTERN说明符。一个外部变量被定义之后,它就被分配了固定的内存空间。外部变量的生存期为程序的整个执行时间。
C语言允许将大型的程序分解为若干个独立的程序模块,各个模块可分别进行编译,然后将它们连接在一起。如果某个变量需要在所有程序模块文件中使用,只要在一个程序模块中将该变量定义成全局变量,而在其它程序模块中用EXTERN说明该变量是已被定义过的外部变量就可以了。
在C51中定义函数时如果冠以关键字EXTERN即将其明确定义为一个外部函数。
具体方法是:在C51用unsigned char定义的变量,则在A51中必须对应声明该变量在DATA区;在C51用bit定义位变量,则在A51中必须对应声明该变量在可位选区。A51中用关键字EXTRN表示外部变量,对应关系如下:
C51 定义 A51声明
unsigned char varible_name<->EXTRN DATA(varible_name)
bit bit_name <->EXTRN BIT (bit_name)
此外,C51编译器支持在C语言源程序中直接编写8051单片机的中断服务程序,从而减轻采用汇编语言编写中断服务程序的繁锁程度。C51编译器对函数的定义进行了扩展,增加了一个扩展关键字interrupt。定义中断服务函数的一般格式为:
函数类型 函数名(形式参数表) [interrupt n]
[using n]
关键了interrupt后面的n是中断号,取值为0~31,编译器从8n+3处产生中断向量。Using后的n取值为0~3,表示选择那一组寄存器。
2 C51无参数化调用A51函数的实例
研制的无纸记录仪实现的功能是:记录仪有4个通道,每秒采样1次,每个通道每次采样需记录两个字节,根据各个通道的转储速率(从1~255可设定),把采样的数据写入外部数据存储器62256,一旦满512字节,就把512字节一次性写入FLASH MEMORY中。
主程序用C51编程,每秒中断采样程序由A51实现。主程序的主要工作是:把采集到的数据按曲线、棒图和数据送到液晶显示器显示;根据一公平的条件查询数据等。中断程序就是采样4个通道,把在A51采样所写入的单元及所需要的一些位变量在C51定义为全局变量,在A51中这些变量声明为外部变量,在C51调用A51的中断函数必须声明为外部函数。这样就实现了C51无参数化调用A51。
C51主程序如下:
程序名为MYMAIN.C
#include <reg51.h>
#include <absacc.h>
#include <intrins.h>
#define uchar unsigned char
//以下3个函数在采样程序模块ZTDJLY.A51中,名称就是标号
extern void sample(); //中断采样程序
extern void initial(); //AD7715初始化
extern void res_ram(); //外部存储器62256地址指针复位
//以下变量为采样程序模块ZTDJLY.A51中所用到的变量
bit write_alw,vz_bit,fs_bit;//write_alw=1,写放FLASH允许,vz_bit,fs_bit是零标定及满刻度标定的标志
uchar sample_w[12];//4路连零点采样值,每路2个字节共10个字节,另外2个字节作定改62256前把采样值添加通道号处理所需单元
uchar xdata *ram_point;//62256的指针
uchar sa_p,sa_vzt[8];//sa_p为采样当前路,sa_vzt[8]为4路的零点
uchar sa_timer[8]={1,1,1,1,1,1,1,1}; //4路的转储速率,前为子,后为母本
……
void disp_int0() interrupt 0 using 2 //用中断0,使用寄存器2组
{
sample();//C51无参数化调用A51函数
}
main()
{
…
initial();
while(1) //主循环
{
……
}
}
A51程序如下:
NAME ztdjly.a51
ram_cs bit 090h.2 ;p1.2 ;62256片选
b373 bit 090h.1 ;p1.1
bit_dog bit 0b0h.4 ;3.4
;以上3个是AD7715的引脚定义
data_bit bit 0a0h.6 ;P2.6
adsclk_bit bit 0b0h.5 ;P3.5
drdy_bit bit 0b0h.3 ;P3.3
?PR?sample?SAMPLE SEGMENT CODE ;定义程序代码段
EXTRN DATA (sample_w) ;声明外部变量,在C51程序定义分配在DATA区
EXTRN DATA(sa_p)
EXTRN DATA(ram_point)
EXTRN DATA (sa_timer)
EXTRN DATA (sa_vzt)
EXTRN BIT (write_alw) ;声明外部变量,在C51程序定义分配在可位寻址区
EXTRN BIT (vz_bit)
EXTRN BIT (fs_bit)
PUBLIFC sample ;分用符号说明
PUBLIC initial,res_ram
RSEG ?PR?sample?SAMPLE
using 0
initial:;AD7715初始化,该标号即是C51定义外部函数
;initial()的入口地址
……
ret
;
sample: ;采样程序,该标号即是C51定义外部函数
;sample()的入口地址
……
ret
……
res_ram: ;62256指针复位,该标号即是C51定义外部函数res_ram()的入口地址
……
ret
end
在研制无纸记录仪之前,作者用MASM51开发了其他仪表,采样部分有些相同,因此这次A51采样程序并不是重新编写,而是把以前的MASM51程序按A51的规则来修改。以前ASM的程序(数据段部分)如下所示:
bseg
;
write_alw bit 00h;
vz_bit bit 01h
fs_bit bit 02h
ce_bit bit p1.6
ram_cs bit p1.2
b373 bit p1.1
bit_dog bit p1.4
data_bit bit P2.6
sclk_bit bit P3.4
drdy_bit bit p3.3
ends
;
dseg
org 08h
org 28h
sample_w; ds 12
sa_p: ds 1 ;当前通道号
ram_point: ds 2
sa_timer: ds 8 ;0,1,2,3每通道两字节
sa_vzt: ds 8 ;0,1,2,3 vz
ends
;
cseg
org 0h
begin: reti
org 03h
lcall sample
reti
sample:
……
ends
从上述程序可以看出,在采样程序中所用到的变量并不少,定义在数据存储区28H单元起始的空间中。这样安排,对汇编程序没什么问题,但与C51主程序连接的时候,并不一定好,很多时候碰到地址空间溢出的问题(C51主程序编译连接后将近16K字节,CPU采用ATMEL公司的AT89C55WD)。如何调整这些变量的分配,并非容易。另外,C51随时要用到采样单元sample_w[12]的值,如果采用一般的参数传递,将是相当复杂而繁琐的;而采用全局及外部变量实现C51无参数经调用A51函数,极大简化了这些工作,大大提高了工作效率。
本文第2部分的程序,采用Keil公司的Keil C V6.10集成开发工具包完成。所研制的无纸记录仪已经通过福建省科技厅的鉴定