关于Keil C51混合编程和若干个源文件链接的问题

2019-03-24 19:49发布

1  混合编程 之  直接插入 汇编代码
首先是我的DS18B20的编程问题。
上次搞定了那个初始化问题后,接着写好了几个读写时间隙的子程序。
但是,在模拟串行通信上遇到了点问题。
一直以来,都觉得在C51移位是件很困难的事情,特别是带进位位的循环移位,所以很多时候,我能躲就躲。
不过这次,突然给惹毛了。

想起了一直想试试的混合编程。
上网查了查,总共有两种,一种是 直接嵌入 汇编代码,用一个#pragma asm/#pragma endasm搞定
可是,我选择了那两个SRC的选项,像网上说的,又把安装文件下的一个C51S.LIB加载在文件夹下,不仅是我的项目文件夹,也在编译器里加载了,就加在主程序下。
也在安装文件的头文件REG52.H里加了那句什么传说中的 #pragma 4,,具体忘了,反正是网上找着的。直接COPY。

可是编译时死活过不去,一直提示这条信息,还好几条:
ERROR A45:UNDEFINED SYMBOL(PASS - 2)
我点了点,这回出现了一个新鲜的SRC窗口,里面的东西有点像 汇编源程序。
我发现几个挺要命的问题:
源文件里我是这么写的:
/*写一个字节到DS18B20*/
/*发送顺序从LSB到MSB */
/*嵌入汇编模块*/
void Write_Byte(unsigned char value) using 2
{
  unsigned char j = 0;
  ACC = value;

  for(j = 0;j < 8;j++)
  {
     #pragma asm
     RRC A;
     DQ = CY;      
     #pragma endasm
     if(DQ)
       Write_1();
     else
       Write_0();
   }
}
可是到了SRC下,出现了一个很要命的问题:
我一进循环,就发现ACC给他请掉了!!我擦,以前其实我也有隐约察觉到这个问题,好像一进循环有好多东西就不见了。不过貌似都没引起什么问题。
这次,不晓得是否会出问题——不出才怪,把我的ACC请掉了,我还送什么数据?

好吧,即使这个问题不管它。
假如我可以避开使用ACC,比如我进到循环里,,,好吧,那都有点放屁脱裤子了。。。。
其实我上次玩5110(还没搞定)时,我见过一个纯C语法的串行模拟程序,有它我也搞定这个问题。
可是关于 嵌入汇编 这个问题,一直像颗石头憋在我心上,不爽,今天第一次折腾,折腾了老久,网上说的我都试了,不行,希望哪位大侠给指教指教。

另外,当我编译好后,还会弹出一个窗口,上面写着什么
我的SRC文件被外部的什么编辑器编译过了,问我是否确定。
我上网查了查,他说,这是因为我在外部用记事本等东西修改过源文件。。。这么说的话,我唯一动过的就是那个REG52.H头文件,这样的话,应该没啥问题吧?

--------------------
网上有个人说,这个无关程序编译,我想想也觉得问题不大,就不想管它,可是我惊奇地发现,百度上问这个问题的都是在搞 嵌入汇编的。



/*2 关于不同源文件链接*/
/*在IAR EWARM下,我发现这种链接很直接。我甚至可以include .C文件。然而今天我在KEIL里试了试,问题各种多。*/
/*首先说找不到我的文件,后来我把C的改成H文件,好像就解决了这个问题。*/
/*但是这时,他拼命说什么 我重复定义了,我一看是那个头文件里的函数声明。*/
/*额,,这个问题,这个问题,先放下,,我用/**/括起来先。。。。自己都没搞清楚就问人,太对不起观众,太没形象了。*/
/*PS:我之所以折腾这个,是想用在接下来的51DIY的整合上,因为涉及两部分甚至三部分要编写单片机程序,所以,,,,*/
/*其实好吧,到了这一步也是最初我持分任务分人单独完成所要实现的目的。*/ 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
ddllxxrr
1楼-- · 2019-03-24 20:36
keil C语言与汇编语言混合编程

1. C语言中嵌入汇编

1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:

#pragma ASM

; Assembler Code Here

#pragma ENDASM

2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”

和“Assemble SRC File”,使检查框由灰 {MOD}变成黑 {MOD}(有效)状态;

3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中, 该文件必须作为工程的最后文件;

4、编译,即可生成目标代码。

来个实例吧:

#i nclude <reg51.h>

void main(void)

{

P2=1;

#pragma asm

          MOV R7,#10

DEL:MOV R6,#20

          DJNZ R6,$

          DJNZ R7,DEL

#pragma endasm

P2=0;

}

2 . 无参数传递的函数调用

C51调用汇编函数

1.无参数传递的函数调用

先来个例子:其中example.c和example.a51为项目中的两个文件

***********************example.c***********************************************

extern void delay100();

main()

{delay100;}

***********************example.a51***********************************************

?PR?DELAY100 SEGMENT CODE; //        在程序存储区中定义段

PUBLIC DELAY100;      //声明函数

RSEG ?PR?DELAY100;     //函数可被连接器放置在任何地方

DELAY100:

        MOV R7,#10

DEL:      

        MOV R6,#20

        DJNZ R6,$

        DJNZ R7,DEL

        RET

END

在example.c文件中,先声明外部函数,然后直接在main中调用即可。

在example.a51中,

?PR?DELAY100 SEGMENT CODE;        作用是在程序存储区中定义段,DELAY100为段名,?PR?表示段位于程序存储区内

PUBLIC DELAY100;           作用是声明函数为公共函数

RSEG ?PR?DELAY100;          表示函数可被连接器放置在任何地方,RSEG是段名的属性

段名的开头为PR,是为了和C51内部命名转换兼容,命名转换规律如下:

CODE -?PR?

XDATA-?XD

DATA-?DT

BIT-?BI

PDATA-?PD

3. 有参数传递的函数调用

           记住哦,c文件和A51文件不能使用同一个文件名,不过我还不知道为什么会这样,有高手知道得话请告知。

              今天说说带参数传递的函数调用,在C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的。

         不同类型的数据及其传递参数的寄存器如下表所示:

  

 在C和汇编混合编程的时候,存在C语言和汇编语言的变量以及函数的接口问题。

在C程序中定义的变量,编译为.asm文件后,都被放进了.bss区,而且变量名的前面都带了一个下划线。在C程序中定义的函数,编译后在函数名前也带了一个下划线。例如:

extern int num就会变成 .bss _num, 1

extern float nums[5]就会变成.bss _nums, 5

extern void func ( )就会变成 _func,

一  汇编和C的相互调用可以分以下几种情况:

(1) 汇编程序中访问c程序中的变量和函数。

在汇编程序中,用_XX就可以访问C中的变量XX了。访问数组时,可以用_XX+偏移量来访问,如_XX+3访问了数组中的XX[3]。

在汇编程序调用C函数时,如果没有参数传递,直接用_funcname 就可以了。如果有参数传递, 则函数中最左边的一个参数由寄存器A给出,其他的参数按顺序由堆栈给出。返回值是返回到A寄存器或者由A寄存器给出的地址。同时注意,为了能够让汇编语言 能访问到C语言中定义的变量和函数,他们必须声明为外部变量,即加extern 前缀。

(2) c程序中访问汇编程序中的变量

如果需要在c程序中访问汇编程序中的变量,则汇编程序中的变量名必须以下划线为首字符,并用global使之成为全局变量。

如果需要在c程序中调用汇编程序中的过程,则过程名必须以下划线为首字符,并且,要根据c程序编译时使用的模式是stack-based model还是register argument model来正确地编写该过程,使之能正确地取得调用参数。

(3) 在线汇编

在C程序中直接插入 asm(“ *** ”),内嵌汇编语句,需要注意的是这种用法要慎用,在线汇编提供了能直接读写硬件的能力,如读写中断控制允许寄存器等,但编译器并不检查和分析在线汇编语言,插入在线汇编语言改变汇编环境或可能改变C变量的值可能导致严重的错误。

二 汇编和C接口中寻址方式的改变:

需 要注意的是,在C语言中,对于局部变量的建立和访问,是通过堆栈实现的,它的寻址是通过堆栈寄存器SP实现的。而在汇编语言中,为了使程序代码变得更为精 简,TI在直接寻址方式中,地址的低7位直接包含在指令中,这低7位所能寻址的具体位置可由DP寄存器或SP寄存器决定。具体实现可通过设置ST1寄存器 的CPL位实现,CPL=0,DP寻址,CPL=1,SP寻址。在DP寻址的时候,由DP提供高9位地址,与低7位组成16位地址;在SP寻址的时候, 16位地址是由SP(16位)与低7位直接相加得来。

由于在C语言的环境下,局部变量的寻址必须通过SP寄存器实现,在混合编程的时候,为了使汇编语言不影响堆栈寄存器SP,通常的方式是在汇编环境中使用DP方式寻址,这样可以使二者互不干扰。编程中只要注意对CPL位正确设置即可

1 .word 的意思就相当与C语言里的int,char等定义一个变两的宽度

2. 编译错误原因有2:

a.如果在汇编里面定义.global(全局符号),那么在C语言里面应该用extern声明,以引用该符号。

b.在汇编里面声明的时候,符号前应加下划线,如 FIQ_Addr: .word EXTint_FIQ 应为: FIQ_Addr: .word _EXTint_FIQ 在C语言里面应用extern声明。 另外,一中方法是,用.ref 代替.global 来声明符号,这样就不用在C源程序里面用extern声明了。 两种方法结果相同。 我讲的是用C和汇编混编程用法,至于C++变量如何翻译成汇编符号可以用仿真器,自己去看,原则类似.



汇编与C语言混合编程的关键问题


1 C程序变量与汇编程序变量的共用

    为了使程序更易于接口和维护,可以在汇编程序中引用与C程序共享的变量:

    .ref_to_dce_num,_to-dte_num,_to_dce_buff,_to_dte_buff

    在汇编程序中引用而在C程序可直接定义的变量:

    unsigned char to_dte_buff[BUFF_SIZE];     //DSP发向PC机的数据

    int to_dte_num;                           //缓冲区中存放的有效字节数

    int to_dte_store;                         //缓冲区的存放指针

    int to_dte_read;                          //缓冲区的读取指针

    这样经过链接就可以完成对应。

    2 程序入口问题

    在C程序中,程序的入口是main()函数。而在汇编程序中其入口由*.cmd文件中的命令决定,如:-e main_start;程序入口地址为 main _start。这样,混合汇编出来的程序得不到正确结果。因为C到ASM的汇编有默认的入口c-int00,从这开始的一段程序为C程序的运行做准备工作。这些工作包括初始化变量、设置栈指针等,相当于系统壳不能跨越。这时可在*.cmd文件中去掉语句:-e main_start。如仍想执行某些汇编程序,可以C函数的形式执行,如:

    main_start();             //其中含有其他汇编程序

    但前提是在汇编程序中把_main_start作为首地址,程序以rete结尾(作为可调用的函数)的程序段,并在汇编程序中引用_main_start,即.ref _main_start。

    3 移位问题

    在C语言中把变量设为char型时,它是8位的,但在DSP汇编中此变量仍被作为16位处理。所以会出现在C程序中的移位结果与汇编程序移位结果不同的问题。解决的办法是在C程序中,把移位结果再用0X00FF去“与”一下即可。

    4 堆栈问题

    在汇编程序中对堆栈的依赖很小,但在C程序中分配局部变量、变量初始化、传递函数变量、保存函数返回地址、保护临时结果功能都是靠堆栈完成。而C编译器无法检查程序运行时堆栈能否溢出。

    5 程序跑飞问题

    编译后的C程序跑飞一般是对不存在的存储区访问造成的。首先要查.MAP文件与memory map图对比,看是否超出范围。如果在有中断的程序中跑飞,应重点查在中断程序中是否对所用到的寄存器进行了压栈保护。如果在中断程序中调用了C程序,则要查汇编后的C程序中是否用到了没有被保护的寄存器并提供保护(在C程序的编译中是不对A、B等寄存器进行保护的)。
辛昕
2楼-- · 2019-03-24 21:48
好长啊。。。
开头那部分,跟我看到的一样。
下面的好长,慢慢看。
辛昕
3楼-- · 2019-03-24 22:15
如果你看到我最近发的一个关于LCmeter的一步一步完善的那个帖子,你就知道了。
其实,其实,多个c源文件的链接编译,非常简单。
只要写好头文件就OK了。
最多,包含的时候,不要用尖括号,要用双引号就好了。。

至于混合编程,先押下吧。
忽然觉得,很多事情都是要到真的逼到面前的时候才会解决的。
比如曾经想玩MSP430的时候,我用的改造无线鼠标做申请,结果放下了很久,至今不知道USB协议是何物。
眼下,上班写的最后一个子程序快完成了,下一步老板让我做一下USB的,你看,就碰上了。

一周热门 更多>