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”,使检查框由灰色变成黑色(有效)状态;

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

4、这点也是本人要重要说明的!即一定要将c:\keil\C51下的STARTUP.A51文件加入项目


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文件中的语句根本没有被编译进去,怎么也找不到原因,郁闷

~~

      最后在网上搜了个试验程序,把我的程序复制过去,可以编译成功,奇怪了,在我的project里就是不行,我注意到我的project编译后

出现一条WARNING:

*** WARNING L7: MODULE >    MODULE:  8.obj (8)

       而同样的程序代码在另外一个project中没有WARNING,肯定是这条WARNING语句导致的,里面提到NAME,难道和名字有关,马上把A51文

件改个名字(原来c文件和a51文件名字一样),编译,哈哈,WARNING不见了,查看汇编代码,一切按预想的进行,唉,一个名字害得我不浅啊

,记住哦,c文件和A51文件不能使用同一个文件名,不过我还不知道为什么会这样,有高手知道得话请告知,还是进行今天的作业吧!

       今天说说带参数传递的函数调用,在C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入

相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的。

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

 

参数类型 char int long/float 通用指针 
第1个 R7 R6&R7 R4-R7 R1-R3 
第2个 R5 R4&R5 R4-R7 R1-R3 
第3个 R3 R2&R3 -- R1-R3


        举个例子吧,void delay(unsigned char i, unsigned int j)  当执行语句delay(10,1000)时,10会存入R7中,1000高位会存入R4中

,低位存入R5中。在汇编语句中从这几个寄存器中取数,再进行操作就行了,说起来也很简单的嘛,呵呵~

       来个最简单的实例吧,没什么意义,傻瓜式的程序:

****************************main.c*********************************************

extern void DELAY(unsigned char i,unsigned int j);

main()

{

DELAY(10,1000);

while(1);

}

**********************DELAY.A51********************************************

?PR?_DELAY?DELAY     SEGMENT CODE

PUBLIC _DELAY

RSEG  ?PR?_DELAY?DELAY

_DELAY:

       DJNZ R4,$

       DJNZ R5,$

       DJNZ R7,$

       RET  

END

还要说的是,函数名前要加下划线,表示是有参数传递的函数调用!

 

4. 函数的返回值传递参数

 

(2)函数返回值所用的寄存器

 

返回值类型 寄存器 说明 
Bit C 由具体标志位返回 
char/unsigned char / 1 byte 指针 R7   
int/unsigned int / 2 byte 指针 R6&R7 高位在R6 
long/unsigned long / 3 byte 指针 R4-R7 高位在R4 
float R4-R7 32bit IEEE格式,指数和符号位在R7 
通用指针 R1-R3 存储类型在R3,高位在R2


实例:

********************main.c****************************************

unsigned int example(unsigned char i)

{

return(i*i);

}

main()

{example(80);

#pragma asm

DJNZ R7,$

DJNZ R6,$

#pragma endasm

while(1);

}

函数返回值在R6,R7中。
 

 


有时候用到需要精确延时之类的子程序时,用C语言比较难控制,这时候就可以在C中嵌入汇编

比较常用的keil中嵌入汇编的方法如下所示:
如图一,在C文件中要嵌入汇编的地方用#pragma asm和#pragma endasm分隔开来,这样编译时KEIL就知道这中间的一段是汇编了。


在有加入汇编的文件中,还要设置编译该文件时的选项


Generate Assembler SRC File 生成汇编SRC文件
 Assemble SRC File 封装汇编文件
 (如图三的状态为选中)
  选上这两项就可以在C中嵌人汇编了,设置后在文件图示中多了三个红色的小方块。


为了能对汇编进行封装还要在项目中加入相应的封装库文件, 在笔者的项目中编译模式是小模式所以选用C51S.LIB。这也是最常用的。这些库

文件是中KEIL安装目录下的LIB目录中。 加好后就可以顺利编译了。(注:我只在7.0以上版本使用过)

 


汇编与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等寄存器进行保护的)。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一本关于 Intel 80C51 以及广大的 51 系列单片机的书 这本书介绍给读者一些 新的技术 使你的 8051 工程和开发过程变得简单 请注意 这本书的目的可不是教你各种 8051 嵌入式系统的解决方法 为使问题讨论更加清晰 在适当的地方给出了程序代码 我们以讨论项目的方法来说 明每章碰到的问题 所有的代码都可在附带的光盘上找到 你必须熟系 C 和 8051汇编 因 为本书不是一本C和汇编的指导书 你可以买到不少关于ANSI C的书 最佳选择当然是Intel 的数据书 可从你的芯片供应商处免费索取 和随编译工具附送的手册 附送光盘有我为这本书编写和收集的程序 这些程序已经通过测试 这并不意味着 你可以随时把这些程序加到你的应用系统或工程 有些地方必须首先经过修改才能结合 到你的程序 这本书将教你充分使用你的工具 如果你只有 8051 的汇编程序 你也可以学习该书和 使用这些例子 但是你必须把 C 语言的程序装入你的汇编程序 这对懂得 C 语言和 8051 汇编程序指令的人来说并不是一件困难的事 如果你有 C 编译器的话 那恭喜你 使用 C 语言进行开发是一个好的决定 你会发现 使用 C 进行开发将使你的工程开发和维护的时间大大减少 如果你已经拥有 Keil C51 那 你已经选择了一个非常好的开发工具 我发现 Keil 软件包能够提供最好的支持 本书支持 Keil C 的扩展 如果你有其它的开发工具像 Archimedes 和 Avocet 这本书也能很好地为 你服务 但你必须根据你所用的开发工具改变一些 Keil 的特殊指令 在书的一些地方有硬件图 实例程序在这些硬件上运行 这些图绘制地不是很详细 主要是方框图 但足以使读者明白软件和硬件之间的接口。
【实验题目】 在RAM执行程序代码 【实验目的】 掌握片外RAM扩展方法(重点是硬件接法,而程序操作很简单)。 弄清楚什么是“哈佛存储结构”和“冯·诺依曼存储结构”。 【硬件接法】 P1.2接交流蜂鸣器。 请认真参考硬件电路图RAM的接法。RAM映射到地址“0x8000~0xBFFF”,共16KB。 【实验原理】 8051单片机本来是“哈佛存储结构”,程序ROM和片外数据RAM位于完全分开的存储空间。/WR和/RD信号用于访问片外数据RAM。当使用片外程序ROM时,/PSEN管脚负责读取程序代码或固定数表。通常ROM不可写,所以未安排ROM的写信号。ROM和RAM共用地址和数据总线,但读写选通信号是分开的,所以在逻辑上分属两个不同的64KB空间,总共128KB。另外片内数据RAM和SFR空间又与前两者有别,是独立编址的。在软件上,访问不同的存储空间采用不同的指令,如“MOVX A,@DPTR”、“MOVC A,@A+DPTR”、“MOV A,@Ri”等。 注意,/PSEN和/RD可以经过“与门”后再接到RAM的/OE。这样,代码和数据都位于相同的地址空间,在RAM也可以跑程序,用“MOVC”和“MOVX”指令都能访问RAM的存储单元。如果把程序代码加载到片外RAM,然后用“LJMP”指令跳转过去就能在RAM执行程序代码。 【说明:片内Flash的引导程序】 这是一个比较复杂的程序,其还牵涉到了C51嵌入汇编的用法。对大多数初学者来说,只要了解其工作过程即可,不必深究。如果您确实对其感兴趣,请自行仔细研究。 该引导程序位于片内Flash,其作用是通过串行口加载HEX格式的程序文件,并自动转换成BIN格式,然后保存到片外RAM,最后跳转过去执行。RAM起始地址为0x8000。引导完毕后,蜂鸣器鸣叫,并等待按下K4键。K4按下后,才开始执行。 【说明:在片外RAM运行的程序】 编写在片外RAM运行的程序与编写正常的A51或C51程序基本相同,但是需要做一些小的调整。正常的程序起始地址总是0x0000,但现在片外RAM的起始地址是0x8000,因此要在原有程序的基础上重新设置起始地址。 对于A51编程,找到ORG命令,修改复位地址和全部断向量入口地址,使它们都偏移0x8000。例如复位地址为0x0000要改成0x8000,定时器T0断入口地址0x000B要改成0x800B,等等。重新编译,生成HEX程序文件,备用。 而对于C51编程,设置的项目稍多一些,步骤如下: 第一,打开Keil C51安装目录“C:\Keil\C51\LIB”,找到文件“STARTUP.A51”,将其复制到您的工程文件夹下,然后右击项目管理窗口的“Source Group1”添加该文件。另一种方法是:在新建工程选择“CPU”后,当出现是否添加启动文件对话框时选择“是”,则文件“STARTUP.A51”会自动被加入。 第二,双击项目管理窗口里的“STARTUP.A51”,找到“CSEG AT 0”这一行,将起始地址“0”改成“0x8000”,保存。 第三,设置片外程序ROM的起始地址和大小。打开编译环境设置(点击工具栏的那个绿色按钮进入该设置),在“Off-chip Code memory”Eprom(在这里,Eprom实际上已被RAM代替)栏第一行填入0x8000和0x3000(共12KB空间)。 第四,程序有可能用到xdata数据,因此还要设置片外数据RAM的起始地址和大小。可以在“Off-chip Xdata memory”Ram栏第一行填入0xB000和0x1000,留足空间(有4KB呀!)。 第五,设置断向量。打开“Options fo Target”设置里的“C51”选项页,找到“Interrupt vectors at...”项,修改为“0x8000”。 OK,所有设置都已完成,重新编译,生成HEX程序文件,备用。 【实验步骤】 1、ISP下载开关扳到“01”,用Flash Magic软件下载程序文件“HexLoader.hex”,暂时不要运行。 2、打开串行调试助手软件ZLGCOMView,操作如下: 勾“HEX发送”(非常重要!); 通信口:选择实际的串行口(通常为COM1); 波特率:4800; 数据位:8; 停止位:1; 点击“打开文件”装入文件夹“在片外RAM运行的程序”下的一个程序文件(HEX格式),在这些程序,所有起始地址都已经预先设置好了; 按实验箱上单片机的RST键,会看到显示“Ready”; 点击“发送文件”,程序开始下载到片外RAM; 下载完毕,出现“OK, press K4...”,蜂鸣器同时鸣叫; 按一次实验箱上的K4键,程
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值