C51嵌入汇编程序
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
貌似现在大学开单片机课都是只学51汇编程序,基本不讲C51,还美其名曰说汇编是根本,其实这些都是bullshit。C语言之所以被越来越多的人采用,就是因为大家都能看懂,而汇编一来每种不同的MCU对应不同的汇编语言,二来真正有心看汇编的人少。但这里要讲的是C51中嵌入汇编程序。
为什么要用汇编程序?
1. 精确。用STC<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />89C51(传统51单片机)12MHz晶振,机器周期为1us(1MHz),如果采用单机器周期的指令时,若NOP,这样就能精确延时。
2. 效率高。用C51的话,就把编译的工作交给了IDE,对于IDE究竟编译成的汇编是怎么样的,大家都不知道,只能仿真时反汇编来看。这样会做了很多不必要的工作,如果追求效率的话,还得用汇编。
下面介绍如何在51单片机C语言中调用汇编程序:
一.函数名的转换及其命名规则
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
二.参数传递
如用C51编写的AD5764R DA采集函数
void Write_DA(char reg, char DAchannel, int DACdata)
第一个参数 reg放在R7
第二个参数DAchannel放在R5
第三个参数DACdata 放在R2和R3
三.函数返回值传递
下面利用C51编译器(Keil)将一个C源文件编译成一个相应的汇编源文件,而不是目标文件,在这个汇编文件中,可清楚地看到每一个参数的传递方法。
step1. 按写普通c51程序方法,建立工程,在里面导入main.和func.c文件。
//main.c
#include "C8051F120.h"
#define uchar unsigned char
extern uchar func(uchar x,uchar y); /*func */
void main(void) /* */
{
func(0x12,0x34); /* func */
}
//func.c
#define uchar unsigned char
uchar func(uchar x,uchar y) /* func */
{
return (x/y); /* x/y */
}
step2. 在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;step3. 根据选择的编译模式,把相应的库文件(如 Small 模式时,是 Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工程的最后文件;
step4. build这个工程后将会产生一个MAIN.SRC的文件,将这个文件改名为FUNC.A51,然后在工程里去掉库文件(如C51S.Lib)和func.c文件,而将FUNC.A51添加到工程里。
//FUNC.A51文件
; COMPILER INVOKED BY:
; C:\Keil\C51\BIN\C51.EXE func.c BROWSE DEBUG OBJECTEXTEND SRC(.\func.SRC)
NAME FUNC
?PR?_func?FUNC SEGMENT CODE
PUBLIC _func
; #define uchar unsigned char
;
; uchar func(uchar x,uchar y) /* 函数func */
RSEG ?PR?_func?FUNC
_func:
USING 0
; SOURCE LINE # 3
;---- Variable 'y?041' assigned to Register 'R5' ----
;---- Variable 'x?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 4
; return (x/y); /* 计算x/y并返回结果 */
; SOURCE LINE # 5
MOV A,R7
MOV B,R5
DIV AB
MOV R7,A
; } ; SOURCE LINE # 6
?C0001:
RET
; END OF _func
END
step5. 检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状
态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。
(参考:如何在 KEIL C51(v6.21) 中调用汇编函数的一个示例
http://www.mcufan.com/article/c2asm2c.html)
在这段汇编函数中有下面四行
NAME FUNC //定义文件名
?PR?_func?FUNC SEGMENT CODE //声明一个段
PUBLIC _func //段入口地址
RSEG ?PR?_func?FUNC //选择定义过的段
SEGMENT指令
SEGMENT 指令用来声明一个再定位段和一个可选的再定位类型。
格式: 再定位段名 SEGMENT 段类型〔再定位类型〕
其中,“再定位段名”用于指明所声明的段。
“段类型”用于指定所声明的段将处的存储器地址空间。
可用的段类型有 CODE、XDATA、DATA、IDATA和BIT。
STACK_SEG SEGMENT IDATA
DATA_SEG SEGMENT DATA
RSEG---再定位段选择指令
再定位段选择指令为RSEG,用于选择一个已在前面定义过的再定位段作为当前段。
格式: RSEG 段名
段名必须是在前面已经声明过的再定位段。
DATA_SEG SEGMENT DATA ;声明一个再定位DATA段
RSEG DATA_SEG ;选择前面声明的再定位DATA段作为当前
上面的“模块名”就是文件名的意思。
函数名又分:
1:无参函数 ?PR?函数名?文件名
2:有参函数 ?PR?_函数名?文件名
3:再入函数 ?PR?_?函数名?文件名
段是程序代码或数据对象的存储单位。程序代码放到代码段,数据对象放到数据段。段分两种,
一是绝对段,一是再定位段。绝对段在汇编语言中指定,在用L51联接的时候,地址不会改变。用于如访问一个固定存储器的i/o,或提供中断向量的入口地址。而再定位段的地址是浮动的。它的地址有L51对程序模块连接时决定。 C51对源程序编译所产生的段都是再定位段,它都有段名和存储类型。 绝对段没有段名。
例如,你写用C写了一个函数 void func(void) { …} , 存在func.c中,用编译器编译以后. SRC FILE中看到:
?PR? func?FUNC SEGMENT CODE //(函数放到代码段中)
写这个函数体的时候:
RSEG ?PR? func?FUNC //选择已定位的代码段为当前段
_func:
…… //代码
又例如 你定义了全局变量
unsigned char data temp1,temp2;
unsigned char xdata temp3;
在test.c文件中,编译器会为每个文件分0到多个全局数据段,相同类型的全局变量被存到同一段中。所以上面会编译成如下:
上面编译出来的汇编还使用了以下两个的伪指令。
DS ---预留存储区命令
格式: 〔标号:〕 DS 表达式值
其功能是从指定地址开始,定义一个存储区,以备源程序使用。
存储区预留的存储单元数由表达式的值决定。
TMP: DS 1
从标号TEP地址处开始保留1个存储单元(字节)。
USING指令
USING指令通知汇编器使用8051的哪一个工作寄存器组。
格式: USING 表达式 (值必须为0-3,默认值为0。)
USING 0
使用第0组工作寄存器。
更多伪指令的使用可以参考下面网页:汇编伪指令注释
http://www.willar.com/forum_view.asp?forum_id=18&view_id=4692
本文还参考了下面文章:
1) Franklin C51和A51函数的相互调用
http://www.avrw.com/article/art_101_3596.htm
2) C51嵌入汇编
http://blog.21ic.com/user1/6084/archives/2009/63605.html
http://blog.ednchina.com/jeddite/260843/message.aspx
4)单片机C和汇编语言混合编程
http://www.docin.com/p-5227805.html
5) KEIL的混合编程操作
http://hi.baidu.com/txz01/blog/item/868ad8d4aeea8309a08bb79c.html/cmtid/7cc6d494e1c9e612d31b7075
5) 用Keil在C中嵌入汇编 - 电子杂院 - 博客大巴
http://kingmoon.blogbus.com/logs/5350441.html
本文实验程序:
C8051F120采用AD5764R DA输出程序(C51)
https://static.assets-stash.eet-china.com/album/old-resources/2010/1/4/331c9fd5-6d14-4414-a147-1ba6af5a8dd2.rar
C8051F120采用AD5764R DA输出程序(C51嵌入汇编)
https://static.assets-stash.eet-china.com/album/old-resources/2010/1/4/e1cc25d8-197d-44b6-90e2-bbb5e44748fd.rar
还有一种直接在C51中嵌入汇编的的方法,具体可以参考
方法与上面的有些类似
1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragma ASM
; Assembler Code Here
#pragma ENDASM
2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 Keil\C51\Lib\C51S.Lib)加入工程中, 该文件必须作为工程的最
后文件;
4、编译,即可生成目标代码。
文章评论(0条评论)
登录后参与讨论