keil for arm中:
static const uint8_t s_acBmpLogo030[len] __attribute__((at(0X800F000)))={0x80,0xC0,0xC0,0xC0,0xC0,0x80,xxxxxxx}
案例演示
下面我们用一个例子演示一下,比如:
将一个全局变量放到0x20000000处;
将一个const常量放置到0x00001000处
将func函数放置到0x00000100起始处
只需要照下面写:
int value __attribute__((section(".ARM.__at_0x20000000"))) = 0x33;
const char ziku[] __attribute__((section(".ARM.__at_0x00001000"))) = {0x1, 0x2, 0x3};
void func (void) __attribute__((section(".ARM.__at_0x00000100")));
void func (void) {
int i;
for (i = 0; i < 100; i++){
}
}
也就是说:对于变量,在其后边加修饰;而对于函数,在声明处加修饰,注意,是在声明处,不是在函数定义处!!!
学习STM32也会遇到这样的绝对定位的问题如下:
uint8_t UART_RX_BUF[1024] __attribute__ ((at(0X20001000))); //就是将串口接收的数据定位到RAM中起始地址为0X20001000;
绝对定位要么定位到flash、要么定位到RAM,这里我们将定位在flash进行说明。
MDK如何实现将数据存储到FLASH指定地址?
我们在烧录数据的时候,一般是从0x08000000开始按照顺序烧录到flash里面的,如何让数据能够定义到绝对地址如0800F000,就必须保证文件内数据也是存储在该地址,为了实现这个目的,MDK在生成文件时会填充0x00字段,从而确保能够将数据定义到
从实际情况也能验证这个原理,我以我的测试代码为例:
const u16 gFlashDefValue4[512] __attribute__((at(0x0800F000))) = {0x1111, 0x1111, 0x1111, 0x0111, 0x0111,0x0111};
KEILC51中
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_指定。
例如:
idata struct link list _at_ 0x40;指定list结构从40h开始。
xdata char text[25b] _at_0xE000;指定text数组从0E000H开始
提示:如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。
3. 连接定位控制
此法是利用连接控制指令code xdata pdata \data bdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。
2、变量定位:
只有全局变量可以绝对定位,局部变量无法实现绝对定位。
方法1:使用_at_关键字。声明一个全局变量unsigned char data MyBuf1[8] _at_ 0x20;
方法2:使用BL51 Locate选项。比如将main.c中定义的所有data型的全局变量定位到数据区D:0x28开始的空间,则从菜单中
选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下面的data栏中写上?DT?MAIN(0x28)即可。
如果是idata,则使用?ID?MAIN(0x28),如果是xdata,则使用?XD?MAIN(0x28),如果是pdata,则使用?PD?MAIN(0x28)
Keil C51中变量和函数的绝对地址定位问题:
1. 变量绝对地址定位
1) 在定义变量时使用 _at_ 关键字加上地址就可.
e.g.
unsigned char idata myvar _at_ 0x40;
把变量 myvar 定义在 idata 的 0x40 处, 在 M51 文件中可以找到这麽一行
IDATA 0040H 0001H ABSOLUTE
表示有变量在 idata 的 0x0040 处绝对地址定位.
2) 使用 KeilC 编译器定义绝对地址的变量, 方法待查.
2. 函数绝对地址定位
1) 在程序中编写一函数 myTest
void myTest(void)
{
// Add your code here
}
2) 使用 KeilC 编译器定位绝对地址的函数, 打开 Project -> Options for Target 菜单,
选中 BL51 Locate 选项卡, 在 Code: 中输入:
?PR?myTest?MAIN(0x4000)
把函数 myTest 定位到程序区的 0x4000 处,
再次编译就可以了.
3) 一次定位多个函数的方法
同样地, 在程序中再编写另外一个函数 myTest1
void myTest1(void)
{
// Add your code here
}
在 Options for Target 菜单的 BL51 Locate 选项卡的 Code: 中输入:
?PR?myTest1?MAIN(0x3900), ?PR?myTest?MAIN(0x4000)
把函数 myTest1 定位在程序区的 0x3900 处, 把函数 myTest 定义在程序区的 0x4000 处,
重新编译就可以了.
注意不同定位之间用逗号隔开
在 M51 文件中可以找到下面的内容:
>> 3.obj TO Reader RAMSIZE (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) 定义调用的函数原形
typedef void (*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 中的函数的方法与此类似, 但是相应的参数传递可能要另寻方法.
1、函数定位:
假如要把C源文件 tools.c 中的函数
int BIN2HEX(int xx)
{
...
}
放在CODE MEMORY的0x1000处,先编译该工程,然后打开该工程的M51文件,在
* * * C O D E M E M O R Y * * *
行下找出要定位的函数的名称,应该形如:
CODE xxxxH xxxxH UNIT ?PR?_BCD2HEX?TOOLS
然后在:
Project->Options for Target ...->BL51 Locate:Code
中填写如下内容:
?PR?_BCD2HEX?TOOLS(0x1000)
再次Build,在M51中会发现该函数已放在CODE MEMORY的0x1000处了
2、赋初值的变量定位:
要将某变量定位在一绝对位置且要赋初值,此时用 _at_ 不能完成,则如下操作:
在工程中建立一个新的文件,如InitVars.c,在其中对要处理的变量赋初值(假设是code变
量):
char code myVer = {"COPYRIGHT 2001-11"};
然后将该文件加入工程,编译,打开M51文件,若定义的是code型,则在
* * * C O D E M E M O R Y * * *
下可找到:
CODE xxxxH xxxxH UNIT ?CO?INITVARS
然后在:
Project->Options for Target ...->BL51 Locate:Code
中填入:
?CO?INITVARS(0x200)
再次编译即可。
相应地,如为xdata变量,则InitVars.c中写:
char xdata myVer = {"COPYRIGHT 2001-11"};
然后将该文件加入工程,编译,打开M51文件,在
* * * X D A T A M E M O R Y * * *
下可找到:
XDATA xxxxH xxxxH UNIT ?XD?INITVARS
然后在:
Project->Options for Target ...->BL51 Locate:Xdata
中填入:
?XD?INITVARS(0x200)
再次编译即可。相应地,若定义的是data/idata等变量,则相应处理即可。
3、若有多个变量或函数要进行绝对地址定位,则应按地址从低到高的顺序排列。
使用KeilC51软件,可以很方便地将代码或者数据绝对定位到某个地址。
1、代码定位:
方法1:使用伪指令CSEG。比如要将MyFunc1定位到代码区C:0x1000,则新建一个A51文件,添加以下内容:
PUBLIC MYFUNC1
CSEG AT 1000H
MYFUNC1:
;其它代码
RET
在其它源文件中,就可以调用MyFunc()函数了。需要注意的是,编译器不检测传递参数的数目,仅检测函数是否有返回值。
方法2:使用BL51 Locate选项。比如在main.c中定义了一个MyFunc2函数,并且要将该函数定位到代码区C:0x2000,则从菜单中选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下面的code栏中写上?PR?MYFUNC2?MAIN(0x2000)即可。
如果想定位多个函数,也可以使用*通配符。
2、变量定位:
只有全局变量可以绝对定位,局部变量无法实现绝对定位。
方法1:使用_at_关键字。声明一个全局变量unsigned char data MyBuf1[8] _at_ 0x20;
方法2:使用BL51 Locate选项。比如将main.c中定义的所有data型的全局变量定位到数据区D:0x28开始的空间,则从菜单中
选择Project->Options for Target 'Target1',在弹出的对话框中选择BL51 Locate页,在下面的data栏中写上?DT?MAIN(0x28)即可。
如果是idata,则使用?ID?MAIN(0x28),如果是xdata,则使用?XD?MAIN(0x28),如果是pdata,则使用?PD?MAIN(0x28)
3、堆栈定位:
在STARTUP.A51文件中定义了堆栈区?STACK,其起始地址同样可以在BL51 Locate页中设置,在Stack栏写上?STACK(0x80)
还可以通过汇编实现
// my.a51
public my_flash_var
cseg at 0F100H
my_flash_var:
db 55h
end
然后C声明
// flash.c
extern unsigned char code my_flash_var;
BL51 locate 选项卡中
code range 和 xdata range如果不填写,编译默认将程序中相应代码和变量从空间前面取起
---------------------
作者:zyboy2000
来源:CSDN
原文:https://blog.csdn.net/zyboy2000/article/details/5731325
版权声明:本文为博主原创文章,转载请附上博文链接!