| EXTRN CODE (func) |
;外部函数func声明 | |
| EXTRN DATA (?func?BYTE) |
;外部函数func局部变量传送段声明 | |
| funca51 SEGMENT CODE |
;funca51代码代声明 | |
| VAR SEGMENT DATA |
;局部变量段声明 | |
| STACK SEGMENT IDATA |
;堆栈段声明 | |
|
|
| a_v: |
DS 2 |
;用于存放第一个int参数的变量 | |
| b_v: |
DS 2 |
;用于存放第二个int参数的变量 | |
| result: |
DS 1 |
;存放func函数char结果的变量 | |
|
|
|
|
|
RSEG funca51 |
;funca51代码段起始 | |
|
|
| START: |
MOV |
SP,#STACK-1 |
;初始化堆栈 | |
|
MOV ?func?BYTE+0,a_v+0 |
;取第一个int参数 | |
|
|
|
MOV |
?func?BYTE+2,b_v+0 |
;取第二个int参数 | |
|
|
|
|
|
|
|
|
|
|
|
分别用C51和A51编译器对上述func51.C和ASM51.A51编译,再执行连接L51 ASM51.OBJ,func51.OBJ NOOVERLAY,即可实现在ASM51中调用C函数func。连接时选择NOOVERLAY是为了禁止数据段和位段的覆盖。
3.2 在C51中调用汇编程序
下面以8051和DS1820接口程序为例来说明在C中调用汇编程序的方法。Dallas公司的DS1820是一种数字式温度计,它与微控制器接口只需一根I/O线,所有的命令、状态和9位温度读数均通过单线双向传送。虽然该器件的硬件接口十分简单,但对读/写时序中的时间片精度要求严格,因而,本例接口程序采用汇编语言编写,主程序及修正温度值的计算部分用C语言编写。本例假定读者对DS1820有所了解,不然请参阅Dallas公司有关DS1820的数据资料。 以下是8051微控制器与DS1820接口的C源程序,本程序要求8051的P1.0与DS1820连接,工作频率12MHz。清单中error(char)和display(char *)分别是错误处理和LCD显示处理函数,限于篇幅未给出。 |
| #include <reg51.h> |
| #include <stdio.h> |
| #include <math.h> |
| extern WDS1820(unsigned char x); |
/* 写DS1820命令外部函数声明 */ |
| extern RDS1820(unsigned char *pt); |
/* 读DS1820数据外部函数声明 */ | |
| extern bit RTDS1820(void); |
/* 复位DS1820外部函数声明 */ |
| extern Delay15(unsigned char n); |
/* 延时15μs外部函数声明 */ |
| sbit P1_0=P1^0; |
/* sbit对象P1.0声明 */ | |
| void main (void) |
/* 主函数 */ | |
| { |
| unsigned data int i; |
| float data tempF; |
| unsigned char data temp[10],disbuf[10]; /* 存放温度数据和显示数据的局部数组变量声明 */ |
| if(RTDS1820()!=1) error(0x3); |
/* 复位并判DS1820是否存在 */ | |
| Delay15(0xff); |
/* 延时约15×255μs */ |
| WDS1820(0xcc); |
WDS1820(0x44); |
/* 向DS1820发跳读ROM和启动温度变换命令 */ | |
|
|
| do{ Delay15(0xff);i++;}while(i<=400); |
/* 延时约1.5秒钟 */ | |
| if(RTDS1820()!=1) error(0x3); |
/* 复位并判DS1820是否存在 */ | |
| Delay15(0xff); |
/* 延时约15×255μs */ | |
| WDS1820(0xcc); WDS1820(0xbe); |
/* 向DS1820发跳读ROM和读9字节数据命令 */ |
| RDS1820(&temp); |
/* 9字节数据读入数组temp */ | |
| tempF=(((temp[1]<<8)+temp[0])>>1)-0.25+((temp[7]-temp[6])/temp[7]); /* 温度值修正计算 */ |
| sprintf(&disbuf,"T=%+4.1f%c",tempF,‘C‘); |
/* 按T=±XXX.X C格式组织数据送disbuf */ |
| display(&temp); |
/* 数据送LCD显示 */ | |
| } |
|
以下是用A51宏汇编编写的DS1820接口源程序清单,共有4个子程序,其中 RTDS 1820无参数传递,但具有bit对象的返回值,DELAY15和WDS1820带有一个经R7传递的无符号char类参数,RDS1820带有一个经R7传递的1字节指针类参数。 |
| NAME RW1820 ;定义模块名 |
| ?PR?RDS1820?RW1820 SEGMENT CODE |
;RDS1820子程序代码段声明 | |
| ?PR?WDS1820?RW1820 SEGMENT CODE |
;WDS1820子程序代码段声明 |
| ?PR?RTDS1820?RW1820 SEGMENT CODE |
;RTDS1820子程序代码段声明 | |
| ?PR?DELAY15?RW1820 SEGMENT CODE |
;DELAY15子程序代码段声明 | |
| PUBLIC |
| RTDS1820,_WDS1820,_RDS1820,_DELAY15 |
;公开函数名以便C模块可调用它们 | |
| RSEG ?PR?RDS1820?RW1820_RDS1820: ;RDS1820代码段起始,完成9字节温度数据的读取 |
|
|
|
MOV A,R7 |
;取经R7传递的数组temp首址(C中定义) | |
|
|
| RD18201:MOV R2,#8 ;置1字节位移位计数器初值 | |
| RD18202:SETB P1.0 ;P1.0置为高电平 |
| NOP |
| NOP |
| CLR P1.0 ;P1.0置为低电平 |
| NOP |
| NOP |
| SETB P1.0 ;P1.0置为高电平,准备输入数据 |
| MOV R7,#1 ;延时15μs |
| LCALL DELAY15 |
| MOV C,P1.0 ;P1.0状态读入位累加器 |
| RRC A ;累加器A右移 |
| DJNZ R2,RD18202 ;判一个字节是否读完 |
| MOV @R0,A ;保存结果 |
| INC R0 ;地址指针加1 |
| DJNZ R1,RD18201 ;判9字节是否读完 |