C51中变量和函数的绝对地址定位问题要点.docx
- 文档编号:15431018
- 上传时间:2023-07-04
- 格式:DOCX
- 页数:29
- 大小:30.13KB
C51中变量和函数的绝对地址定位问题要点.docx
《C51中变量和函数的绝对地址定位问题要点.docx》由会员分享,可在线阅读,更多相关《C51中变量和函数的绝对地址定位问题要点.docx(29页珍藏版)》请在冰点文库上搜索。
C51中变量和函数的绝对地址定位问题要点
C51中变量和函数的绝对地址定位问题:
1. 变量绝对地址定位
1) 在定义变量时使用 _at_ 关键字加上地址就可.
e.g.
unsignedcharidatamyvar_at_0x40;
把变量 myvar 定义在 idata 的 0x40 处, 在 M51 文件中可以找到这麽一行
IDATA 0040H 0001H ABSOLUTE
表示有变量在 idata 的 0x0040 处绝对地址定位.
2) 使用 KeilC 编译器定义绝对地址的变量, 方法待查.
2. 函数绝对地址定位
1) 在程序中编写一函数 myTest
voidmyTest(void)
{
//Addyourcodehere
}
2) 使用 KeilC 编译器定位绝对地址的函数, 打开 Project->OptionsforTarget 菜单,
选中 BL51Locate 选项卡, 在 Code:
中输入:
?
PR?
myTest?
MAIN(0x4000)
把函数 myTest 定位到程序区的 0x4000 处,
再次编译就可以了.
3) 一次定位多个函数的方法
同样地, 在程序中再编写另外一个函数 myTest1
voidmyTest1(void)
{
//Addyourcodehere
}
在 OptionsforTarget 菜单的 BL51Locate 选项卡的 Code:
中输入:
?
PR?
myTest1?
MAIN(0x3900),?
PR?
myTest?
MAIN(0x4000)
把函数 myTest1 定位在程序区的 0x3900 处, 把函数 myTest 定义在程序区的 0x4000处,
重新编译就可以了.
在 M51 文件中可以找到下面的内容:
>>3.objTOReaderRAMSIZE(256)CODE(?
PR?
MYTEST1?
MAIN(0X3900),?
PR?
MYTEST?
MAIN (0X4000))
3665H 029BH ***GAP***
CODE 3900H 0014H UNIT ?
PR?
MYTEST1?
MAIN
3914H 06ECH ***GAP***
CODE 4000H 0014H UNIT ?
PR?
MYTEST?
MAIN
4) 函数的调用:
程序中直接调用函数的方式就不说明了, 这里重点讲使用函数指针调用绝对地址处的函数的方法.
(1) 定义调用的函数原形
typedefvoid(*CALL_MYTEST)(void);
这是一个回调函数的原形, 参数为空.
(2) 定义相应的函数指针变量
CALL_MYTEST myTestCall=NULL;
(3) 函数指针变量赋值, 指向我们定位的绝对地址的函数
myTestCall=0x3900;
指向函数 myTest1
(4) 函数指针调用
if(myTestCall!
=NULL)
{
myTestCall(); // 调用函数指针处的函数 myTest1, 置 PC 指针为 0x3900
}
检查编译生成的 bin 文件, 到 0x3900 处可以看到 myTest1 的内容, 在 0x4000 处可以看到 myTest 的内容,
(5) 其它说明:
如果在 0x3000 到 0x3900 的程序空间没有内容时, 把 myTestCall 的地址指针指到0x3800
(在 0x3000 到 0x3900 之间) 时, 会从 0x3900 处开始执行.
至於在 Load 中调用 AP 中的函数的方法与此类似, 但是相应的参数传递可能要另寻方法.
************************************
keilC51绝对地址访问
在利用keil进行8051单片机编程的时,常常需要进行绝对地址进行访问.特别是对硬件操作,如DAAD 采样 ,LCD 液晶操作,打印操作.等等.
C51提供了三种访问绝对地址的方法:
1. 绝对宏:
在程序中,用“#include
CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD
具体使用可看一看absacc.h便知
例如:
rval=CBYTE[0x0002];指向程序存贮器的0002h地址
rval=XWORD[0x0002];指向外RAM的0004h地址
2._at_关键字
直接在数据定义后加上_at_const即可,但是注意:
(1)绝对变量不能被初使化;
(2)bit型函数及变量不能用_at_指定。
例如:
idatastructlinklist_at_0x40;指定list结构从40h开始。
xdatachartext[25b]_at_0xE000;指定text数组从0E000H开始
提示:
如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。
3. 连接定位控制
此法是利用连接控制指令codexdatapdata\databdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。
附:
(c51)
/*--------------------------------------------------------------------------
ABSACC.H
Directaccessto8051,extended8051andPhilips80C51MXmemoryareas.
Copyright(c)1988-2002KeilElektronikGmbHandKeilSoftware,Inc.
Allrightsreserved.
--------------------------------------------------------------------------*/
#ifndef__ABSACC_H__
#define__ABSACC_H__
#defineCBYTE((unsignedcharvolatilecode*)0)
#defineDBYTE((unsignedcharvolatiledata*)0)
#definePBYTE((unsignedcharvolatilepdata*)0)
#defineXBYTE((unsignedcharvolatilexdata*)0)
#defineCWORD((unsignedintvolatilecode*)0)
#defineDWORD((unsignedintvolatiledata*)0)
#definePWORD((unsignedintvolatilepdata*)0)
#defineXWORD((unsignedintvolatilexdata*)0)
#ifdef__CX51__
#defineFVAR(object,addr)(*((objectvolatilefar*)(addr)))
#defineFARRAY(object,base)((objectvolatilefar*)(base))
#defineFCVAR(object,addr)(*((objectconstfar*)(addr)))
#defineFCARRAY(object,base)((objectconstfar*)(base))
#else
#defineFVAR(object,addr)(*((objectvolatilefar*)((addr)+0x10000L)))
#defineFCVAR(object,addr)(*((objectconstfar*)((addr)+0x810000L)))
#defineFARRAY(object,base)((objectvolatilefar*)((base)+0x10000L))
#defineFCARRAY(object,base)((objectconstfar*)((base)+0x810000L))
#endif
#endif
附:
(c166)
/*--------------------------------------------------------------------------
ABSACC.H
Directaccessto166memoryareasforC166/EC++Version5.
Copyright(c)1992-2004KeilElektronikGmbHandKeilSoftware,Inc.
Allrightsreserved.
--------------------------------------------------------------------------*/
#ifndef__ABSACC_H__
#define__ABSACC_H__
#if(__MODEL__==0)
#defineMVAR(object,addr)(*((objectvolatile*)(addr)))
#defineMARRAY(object,base)((objectvolatile*)(base))
#else
#defineMVAR(object,addr)(*((objectvolatilefar*)(addr)))
#defineMARRAY(object,base)((objectvolatilefar*)(base))
#defineHVAR(object,addr)(*((objectvolatilehuge*)(addr)))
#defineHARRAY(object,base)((objectvolatilehuge*)(base))
#defineXVAR(object,addr)(*((objectvolatilexhuge*)(addr)))
#defineXARRAY(object,base)((objectvolatilexhuge*)(base))
#endif
#endif
以下来自转载:
使用KeilC51软件,可以很方便地将代码或者数据绝对定位到某个地址。
1、代码定位:
方法1:
使用伪指令CSEG。
比如要将MyFunc1定位到代码区C:
0x1000,则新建一个A51文件,添加以下内容:
PUBLICMYFUNC1
CSEGAT1000H
MYFUNC1:
;其它代码
RET
在其它源文件中,就可以调用MyFunc()函数了。
需要注意的是,编译器不检测传递参数的数目,仅检测函数是否有返回值。
方法2:
使用BL51Locate选项。
比如在main.c中定义了一个MyFunc2函数,并且要将该函数定位到代码区C:
0x2000,则从菜单中选择Project->OptionsforTarget'Target1',在弹出的对话框中选择BL51Locate页,在下面的code栏中写上?
PR?
MYFUNC2?
MAIN(0x2000)即可。
如果想定位多个函数,也可以使用*通配符。
2、变量定位:
只有全局变量可以绝对定位,局部变量无法实现绝对定位。
方法1:
使用_at_关键字。
声明一个全局变量unsignedchardataMyBuf1[8]_at_0x20;
方法2:
使用BL51Locate选项。
比如将main.c中定义的所有data型的全局变量定位到数据区D:
0x28开始的空间,则从菜单中
选择Project->OptionsforTarget'Target1',在弹出的对话框中选择BL51Locate页,在下面的data栏中写上?
DT?
MAIN(0x28)即可。
如果是idata,则使用?
ID?
MAIN(0x28),如果是xdata,则使用?
XD?
MAIN(0x28),如果是pdata,则使用?
PD?
MAIN(0x28)
3、堆栈定位:
在STARTUP.A51文件中定义了堆栈区?
STACK,其起始地址同样可以在BL51Locate页中设置,在Stack栏写上?
STACK(0x80)
BL51locate 选项卡中
coderange 和 xdatarange如果不填写,编译默认将程序中相应代码和变量从空间前面取起
网上看到有人提到在keil中使用_at_进行绝对地址定位问题,我简单介绍一下它的用法。
使用_at_关键字对存储器进行绝对地址定位程序如下
#include
charxdataLED_Data[50]_at_0x8000;
main()
{
LED_Data[0]=0x23;
}
在keil中运行以上程序可以在存储器窗口中输入 x:
0x8000 可以看到0x8000地址中的值为0x23.
值得指出的几点是
1.在给变量LED_Data[50]定位绝对地址空间时,不能对其赋初值。
2.charxdataLED_Data[50]_at_0x8000;这条语句不能主函数中。
有些网友提到在按着keil说明中用_at_进行绝对地址定位时,编译会出现错误274,就是将这条语句放在主函数中的原因。
3.keil中地址是自动分配的,所以除非特殊情况否则不提倡使用绝对地址定位。
初学者因帖别注意。
不要把c当作汇编使用。
对需要/RST复位后要保持变量不变,防止意外改变(比如升级到新程序,变量地址可能被编译器优化到其他地方),比较有用!
!
!
!
STARTUP.A51 这个文件有什么用,有必要添加到工程吗?
如果不添加"startup.a51"文件,编译器就会自动加入一段初始化内存以及堆栈等的代码,这时的内存初始化部分你就无法去控制了,当然这在大部分情况下没什么关系。
但是如果你想你的程序在复位后,内存里面的信息依然还保存着(所说的“热复位”),那么你就需要添加该启动文件,并且去里面修改内存初始化部分,不要初始化你需要保留的部分内存。
请问如何在keil编译器里,编程时指定函数的绝对地址 (无内容)
不好意思啊,我还从来没有接触过有这样要求情况,不过从网上其他地方找了一篇你参考一下吧,、函数定位:
假如要把C源文件 tools.c 中的函数
intBIN2HEX(intxx)
{
...
}
放在CODEMEMORY的0x1000处,先编译该工程,然后打开该工程的M51文件,在
*** CODE MEMORY ***
行下找出要定位的函数的名称,应该形如:
CODE xxxxH xxxxH UNIT ?
PR?
_BCD2HEX?
TOOLS
然后在:
Project->OptionsforTarget...->BL51Locate:
Code
中填写如下内容:
?
PR?
_BCD2HEX?
TOOLS(0x1000)
再次Build,在M51中会发现该函数已放在CODEMEMORY的0x1000处了
2、赋初值的变量定位:
要将某变量定位在一绝对位置且要赋初值,此时用 _at_ 不能完成,则如下操作:
在工程中建立一个新的文件,如InitVars.c,在其中对要处理的变量赋初值(假设是code变
量):
charcodemyVer={"COPYRIGHT2001-11"};
然后将该文件加入工程,编译,打开M51文件,若定义的是code型,则在
*** CODE MEMORY ***
下可找到:
CODE xxxxH xxxxH UNIT ?
CO?
INITVARS
然后在:
Project->OptionsforTarget...->BL51Locate:
Code
中填入:
?
CO?
INITVARS(0x200)
再次编译即可。
相应地,如为xdata变量,则InitVars.c中写:
charxdatamyVer={"COPYRIGHT2001-11"};
然后将该文件加入工程,编译,打开M51文件,在
*** XDATA MEMORY ***
下可找到:
XDATA xxxxH xxxxH UNIT ?
XD?
INITVARS
然后在:
Project->OptionsforTarget...->BL51Locate:
Xdata
中填入:
?
XD?
INITVARS(0x200)
再次编译即可。
相应地,若定义的是data/idata等变量,则相应处理即可。
3、若有多个变量或函数要进行绝对地址定位,则应按地址从低到高的顺序排列。
**********************************
PIC51 混编 C18指定数据绝对地址
51:
RSEG是段选择指令,要想明白它的意思就要了解段的意思。
段是程序代码或数据对象的存储单位。
程序代码放到代码段,数据对象放到数据段。
段分两种,一是绝对段,一是再定位段。
绝对段在汇编语言中指定,在用L51联接的时候,地址不会改变。
用于如访问一个固定存储器的i/o,或提供中断向量的入口地址。
而再定位段的地址是浮动的。
它的地址有L51对程序模块连接时决定,C51对源程序编译所产生的段都是再定位段,它都有段名和存储类型。
绝对段没有段名。
说了这么多,大家可能还是不明白段是什么意思。
别急,接着往下看。
例如,你写用C写了一个函数 voidtest_fun(void){ …}, 存在test.c中,用编译器编译以后.SRCFILE中看到:
?
PR?
test_fun?
TESTSEGMENTCODE//(函数放到代码段中)
写这个函数体的时候:
RSEG?
PR?
test_fun?
TEST//选择已定位的代码段为当前段 test_fun:
……//代码
所以函数的表达模式是这样:
?
PR?
函数名?
文件名
而函数名又分:
1:
无参函数 ?
PR?
函数名?
文件名
2:
有参函数 ?
PR?
_函数名?
文件名
3:
再入函数 ?
PR?
_?
函数名?
文件名
又例如 你定义了全局变量 unsignedchardatatemp1,temp2;unsignedcharxdatatemp3;在test.c文件中,编译器会为每个文件分0到多个全局数据段,相同类型的全局变量被存到同一段中。
所以上面会编译成如下:
RSEG?
DT?
TEST
.temp1:
DS1
.temp2:
DS1
;
RSEG?
XD?
TEST
.temp3:
DS1
//下面是各个类型的数据全局段的表示
?
CO?
文件名 //常数段
?
XD?
FILE_NAME//XDATA 数据段
?
DT?
FILE_NAME//DATA 数据段
?
ID?
FILE_NAME//IDATA…..
?
BI?
FILE_NAME//BIT…..
?
BA?
FILE_NAME//BDATA….
?
PD?
FILE_NAME//PDATA…..
看到这里大家应该明白段的意思了吧。
也许你会问,这有什么作用哪?
它就是用在当你需要用汇编语言写一部份程序的时候,把汇编写的函数放在这个问件中,改名xxx.a51,按上面的规则写。
编译就好。
既然知道了段的意思,现在我们回到SEG的用法上来。
A51中有两种段选择指令 :
再定位段选择指令 和 绝对段选择指令. 它们用来选择当前段是再定位段还是绝对段。
使用不同的段选择指令,将使程序定位在不同的地址空间之内。
1:
再定位段的选择指令是:
RSEG 段名
它用来选择一个在前面已经定义过的再定位段作为当前段。
用法就像我们上面的例子,先申明了一个函数段,后面写这个函数段。
2:
绝对段选择指令
CSEG[AT 绝对地址表达式]//绝对代码段
DSEG[AT 绝对地址表达式]//内部绝对数据段
XSEG[AT 绝对地址表达式]//外部绝对数据段
ISEG[AT 绝对地址表达式]//内部间接寻址绝对数据段
BSEG[AT 绝
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C51 变量 函数 绝对 地址 定位 问题 要点