keil c51代码及RAM变量定址问题

iwillalwaysloveyou 2009-07-29 10:34:26
我想把部分模块的代码集中放到固定起始位置,

并且这部分代码所使用的RAM变量(包括全局变量和局部变量),放到其他模块RAM变量的前面,

能做到吗?
...全文
1682 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
GC80 2009-08-18
  • 打赏
  • 举报
回复
to iwillalwaysloveyou,
我也有过这样的疑问,基本上在KEIL工具上,要想函数的临时变量不要采用固定的地址,只有可重入(reentrant),不过可重入后代码就变大许多,可以说keil没有考虑好把部分模块打包lib后时,采用堆栈这种模式来调用,或者是没有优化好吧。
IAR Embedded Workbench for MCS-51就基本可以解决这个问题,IAR编译出来的程序,局部变量采用的堆栈的模式,是完全可以满足你的要求。
只有写过一些MASKROM程序的人才有这样的体会,我们现在就在用IAR的模式,IAR就是入门难一点,IAR有点GCC的风格,程序的连接过程完全能有开发者自主控制住你的程序。
pigeon0411 2009-08-13
  • 打赏
  • 举报
回复
在KEIL FOR ARM中,我是用分散加载文件来做的,用分散加载文件可以任意分配指定你想要的变量,模块所处的位置。

KEIL C51可能也有这样的功能,你可以查查相关帮助文档。
LanceJin 2009-08-12
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 iwillalwaysloveyou 的回复:]
引用 24 楼 jlctt 的回复:
重入函数非迫不得已不会用,说实话我写了C51的代码如果以行来计算的话,起码有个二三十万行吧,还没有用过reentrant,但是了解是必要的.还有局部变量是可以指到不同区域的,如XDATA, 固定地址你能确定吗?


局部变量是可以指到不同区域,这个没错。
我所说的固定,指的是芯片掩膜之后。

我需要把某些模块的全局变量和局部变量全部集中起来放到一个固定位置。

[/Quote]如果你指的变量是函数体内部的局部变量,通常是分配在RAM空间的,同样的函数如果在不同的地方调用,局部变量也不一定是固定的。如果你指的变量是说一个模块的变量,在函数体外声明,要固定地址还是有办法的,除了_at_外,还可以用以下(原文出自http://leency0000.spaces.live.com/default.aspx?_c02_owner=1)方式定位:

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、若有多个变量或函数要进行绝对地址定位,则应按地址从低到高的顺序排列。
cokewei 2009-08-12
  • 打赏
  • 举报
回复
你看看我说的这种方式能不能解决你的问题:
1,你可以看一下bootload的初始化代码,中断函数入口地址都是定义在0地址开始的地方,你可以把你的模块函数入口地址放在接下去的地方就可以通过把绝对地址赋值给指向函数的指针来调用你的函数了。建议可以看下stm32 usb IAP的示例,里面是通过绝对地址跳转到真正的main()函数,你就能明白了。
2,keil中有个定义变量后面加上__at(地址)的方式把你的变量定义到指定的位置,你可以试一下定义在最前面。
iwillalwaysloveyou 2009-08-11
  • 打赏
  • 举报
回复
最好是能通过改编译选项解决问题
iwillalwaysloveyou 2009-08-11
  • 打赏
  • 举报
回复
不使用跟具体平台绑定的代码
schlafenhamster 2009-08-11
  • 打赏
  • 举报
回复
至于代码位置要从.map文件中得到。再利用函数指针写一个头文件给用户就可以了。
schlafenhamster 2009-08-11
  • 打赏
  • 举报
回复
Absolute Variable Location.
Variables may be located at absolute memory locations in your C program
source modules using the _at_ keyword. The usage for this feature is:
type memory_space variable_name _at_ constant;
where:
memory_space is the memory space for the variable. If missing from the
declaration, the default memory space is used. Refer to
“Memory Models” on page 94 for more information about
the default memory space.
type is the variable type.
variable_name is the variable name.
constant is the address at which to locate the variable.
The absolute address following _at_ must conform to the physical boundaries of
the memory space for the variable. The Cx51 compiler checks for invalid
address specifications.
//例子:
struct link
{
struct link idata *next;
char code *test;
};
struct link list idata _at_ 0x40; /* list at idata 0x40 */
char xdata text[256] _at_ 0xE000; /* array at xdata 0xE000 */
int xdata i1 _at_ 0x8000; /* int at xdata 0x8000 */
void main ( void ) {
link.next = (void *) 0;
i1 = 0x1234;
text [0] = 'a';
}
//但:
2. Functions and variables of type bit cannot be located at an absolute address
iwillalwaysloveyou 2009-08-11
  • 打赏
  • 举报
回复
我看了编译器手册,没有提供支持,应该是没什么好办法解决这个问题
iwillalwaysloveyou 2009-08-11
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 jlctt 的回复:]
重入函数非迫不得已不会用,说实话我写了C51的代码如果以行来计算的话,起码有个二三十万行吧,还没有用过reentrant,但是了解是必要的.还有局部变量是可以指到不同区域的,如XDATA, 固定地址你能确定吗?
[/Quote]

局部变量是可以指到不同区域,这个没错。
我所说的固定,指的是芯片掩膜之后。

我需要把某些模块的全局变量和局部变量全部集中起来放到一个固定位置。
LanceJin 2009-08-01
  • 打赏
  • 举报
回复
重入函数非迫不得已不会用,说实话我写了C51的代码如果以行来计算的话,起码有个二三十万行吧,还没有用过reentrant,但是了解是必要的.还有局部变量是可以指到不同区域的,如XDATA, 固定地址你能确定吗?
shuiyan 2009-07-29
  • 打赏
  • 举报
回复
你用什么做开发?计算机的二进制码?还是汇编?

“需要把多个文件的变量地址集中到一起”,为什么?什么客户(项目)需求得出这样的设计要求的?
Great_Bug 2009-07-29
  • 打赏
  • 举报
回复
如果你喜欢用汇编语言,这些地址都可以明确指定....请参考KEIL的文档...
iwillalwaysloveyou 2009-07-29
  • 打赏
  • 举报
回复
我需要把多个文件的变量地址集中到一起
iwillalwaysloveyou 2009-07-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 shuiyan 的回复:]
只用过变量(全局或局部)定义时指定地址,但是没有专门限制一定要在最前面。

什么样的需求会有这样的奇怪的限制?

模块代码的指定位置没用过。
[/Quote]

之所以放在前面是为了方便,不一定要放到最前。
iwillalwaysloveyou 2009-07-29
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 great_bug 的回复:]
全局变量容易控制,局部变量由编译器自动分配,不好控制.....好像也不用费事去控制它...
[/Quote]

我现在就是需要去控制
shuiyan 2009-07-29
  • 打赏
  • 举报
回复
只用过变量(全局或局部)定义时指定地址,但是没有专门限制一定要在最前面。

什么样的需求会有这样的奇怪的限制?

模块代码的指定位置没用过。
iwillalwaysloveyou 2009-07-29
  • 打赏
  • 举报
回复
考虑到空间及效率问题,不使用重入函数。

楼上你用Keil C51开发过程序吗?
C51的非重入函数局部变量的地址是固定的。
LanceJin 2009-07-29
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 iwillalwaysloveyou 的回复:]
掩膜芯片,同时提供ROM和EEPROM,

我的cos代码最终是要放到ROM里,

现在想支持后下载cos替换ROM里的cos,

并且后下载的cos能重用ROM里的部分代码
[/Quote]

这个也不用这么复杂吧,你要重用的那些代码是不会再修改的吧,直接将这些代码放到ROM中指定位置直接调用不就行了。一个芯片有很多应用,芯片不可能提供所有应用代码,将固定的模块功能打包成lib就行了。用户应用代码可以放在外部存储芯片上,Mask ROM提供基本应用的Code.
LanceJin 2009-07-29
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 iwillalwaysloveyou 的回复:]
我想重用ROM里的代码
[/Quote]


keil支持重入函数

重入函数,又叫再入函数,是一种可以在函数体内不直接或间接调用其自身的一种函数。
再入函数可被递归调用,无论何时,包括中断函数在内的任何函数都可以调入。再入函数在
C51编译时使用的是模拟栈。
函数说明: 函数名(形式参数表) reentrant
注意事项:
1、再入函数不能传递bit类型参数。
2、与PL/M51兼容的函数不能具有reentrant,这样也不能调用再入函数。
3、在编译时:再入函数建立的是模拟堆栈区,small模式下模拟堆栈区位于idata
区,compact模式下模拟堆栈区位于pdata区,large模式下模拟堆栈区位于xdata区.
4、在同一程序中可以定义和使用不同存储器模式的再入函数,任意模式的再入函数不能调
用不同存储器模式的再入函数,但可以调用普通函数。
5、实际参数可以传递给间接调用的再入函数。无再入属性的间接调用函数不能包含调用参
加载更多回复(14)
---------------------------------- Keil C51语言使用技巧及实战_周立功书籍 ---------------------------------- PDF文件,带书签功能,阅读非常方便,不是精品我不发. -----------目录------------------- 介绍 第一章 硬件 1 概述 2存储区结构 2.1 CODE 区 2.2 DATA 区 2.3 特殊功能寄存器 2.4 IDATA区 2.5 XDATA区 3 位操作和布尔逻辑 4 寻址方式 5 处理器状态 6 电源控制 6 中断系统 6.1 中断优先级寄存器 6.2 中断使能寄存器 6.3 中断延迟 6.4 外部中断信号 7 内置定时/计数器 7.1 定时器工作方式 0 和方式 1 7.2 定时器工作方式 2 7.3 定时器工作方式 3 7.4 定时器 2 8 内置 UART 8.1 UART模式0 8.2 UART模式1 8.3 UART模式2 9 其它功能 9.1 I2C 9.2 A/D转换 9.3 看门狗 10 设计 11 实现 第二章 用 C 对 8051 编程 1 为什么要用高级语言 2 C 语言的一些要点 2.1 结构 2.2 联合 2.3 指针 2.4 类型定义 3 Keil C和ANSI C 3.1 数据类型 3.2 特殊功能寄存器 4 存储类型 4.1 DATA 区 4.2 BDATA区 4.3 IDATA段 4.4 PDATA和XDATA段 5 指针 6 中断服务 6.1 指定中断服务程序使用的寄存器组 7 再入函数 8 使用 Keil C 时应做的和应该避免的 8.1 采用短变量 8.2 使用无符号类型 8.3 避免使用浮点指针 8.4 使用位变量 8.5 用局部变量代替全局变量 8.6 为变量分配内部存储区 8.7 使用特定指针 8.8 使用调令 8.8 使用宏替代函数 9 存储器模式 10 混合存储模式 11 运行库 12 动态存储分配 13 结论 第三章 使用软件补充硬件 1 介绍 2 使用小存储模式 3 使用液晶驱动 3.1 LCD驱动接口 4 显示数据 4.1 定制 printf 函数 5 使用定时计数器来计时 6 使用系统时标做用户接口 7 改进时钟软件 8 优化内部 RAM 的使用 9 完整的程序 10 使用看门狗定时器 12 保存系统数据 13 结论 第四章 在 8051 上使用汇编和 C 1 介绍 2 增加段和局部变量 3 设置变量地址 4 结合C和汇编 5 内联汇编代码 6 提高编译器的汇编能力 7 仿真多级中断 8 时序问题 9 结论 第五章 系统调试 1 介绍 2 通过系统设计来帮助调试 3 使用调试端口 4 使用Monitor-51 5 利用I/0端口进行调试 6 使用ICE 7 结论 第六章 中断系统 1 介绍 2 中断驱动系统和查寻系统 3 中断的电平和边沿触发 3.1 电平触发中断 3.2 边沿触发方式 4 共用中断 6 扩充外部中断数 7 中断服务程序 8 结论 第7章 串行口 1 介绍 2 慢速串行口和PC的接口 3 高速串行I/O 4 结论 第八章 8051的网络设计 1 复合串行端口 2 队列实行 3 使用内置定时器作TDMA控制 3 保持节点器件同步 4 CSMA网络 5 结论 第九章 控制编译和连接 1 把C代码转变成Keil C代码 2 把汇编代码转换成Keil汇编代码 3 使用using关键字 4 控制连接覆盖过程 5 使用64K或更多RAM 6 使用64K以上的代码空间 7 结论 第十章 8051的模糊控制 1 介绍 2 什么是模糊逻辑 3 模糊系统的结构 4 模糊控制使用的场合 5 进行模糊控制 6 模糊功能的实现 7 方案调整 8结论 总结 ----------------------------------
Keil C51使用详解 第一节 系统概述... 6 第二节 Keil C51单片机软件开发系统的整体结构... 6 第三节 Keil C51工具包的安装... 7 1. C51 for Dos 7 2. C51 for Windows的安装及注意事项:... 7 第四节 Keil C51工具包各部分功能及使用简介... 7 1. C51与A51. 7 2. L51和BL51. 8 3. DScope51,Tscope51及Monitor51. 8 4. Ishell及uVision. 9 第二章 Keil C51软件使用详解... 10 第一节 Keil C51编译器的控制指令... 10 1. 源文件控制类... 10 2. 目标文件(Object)控制类:... 10 3. 列表文件(listing)控制类:... 10 第二节 dScope51的使用... 11 1. dScope51 for Dos 11 2. dScope for Windows 12 第三节 Monitor51及其使用... 13 1. Monitor51对硬件的要求... 13 2. Mon51的使用... 13 3. MON51的配置... 13 4. 串口连接图:... 13 5. MON51命令及使用... 14 第四节 集成开发环境(IDE)的使用... 14 1. Ishell for Dos的使用... 14 2. uVision for windows的使用... 15 第三章 Keil C51 vs 标准C.. 15 第一节 Keil C51扩展关键字... 15 第二节 内存区域(Memory Areas):... 16 1. Pragram Area:... 16 2. Internal Data Memory: 16 3. External Data Memory. 16 4. Speciac Function Register Memory. 16 第三节 存储模式... 16 1. Small模式... 16 2. Compact模式... 17 3. large模式... 17 第四节 存储类型声明... 17 第五节 变量或数据类型... 17 第六节 位变量与声明... 17 1. bit型变量... 17 2. 可位寻址区说明20H-2FH.. 18 第七节 Keil C51指针... 18 1. 一般指针... 18 2. 存储器指针... 18 3. 指针转换... 18 第八节 Keil C51函数... 19 1. 中断函数声明:... 19 2. 通用存储工作区... 19 3. 选通用存储工作区由using x声明,见上例。... 19 4. 指定存储模式... 19 5. #pragma disable. 19 6. 递归或可重入函数指定... 19 7. 指定PL/M-51函数... 20 第四章 Keil C51高级编程... 20 第一节 绝对地址访问... 20 1. 绝对宏:... 20 2. _at_关键字... 21 3. 连接定位控制... 21 第二节 Keil C51与汇编的接口... 21 1. 模块内接口... 21 2. 模块间接口... 21 第三节 Keil C51软件包中的通用文件... 22 1. 动态内存分配... 22 2. C51启动文件STARTUP.A51. 22 3. 标准输入输出文件... 25 4. 其它文件... 25 第四节 段名协定与程序优化... 25 1. 段名协定(Segment Naming Conventions) 25 2. 程序优化... 25 第五章 Keil C51库函数参考... 26 第一节 本征库函数(intrinsic routines)和非本征证库函数... 26 第二节 几类重要库函数... 26 1. 专用寄存器include文件... 26 2. 绝对地址include文件absacc.h. 26 3. 动态内存分配函数,位于stdlib.h中... 27 4. 缓冲区处理函数位于“string.h”中... 27 5. 输入输出流函数,位于“stdio.h”中... 27 第三节 Keil C51库函数原型列表... 27 1. CTYPE.H.. 27 2. INTRINS.H.. 27 3. STDIO.H.. 28 4. STDLIB.H.. 28 5. STRING.H.. 28 第六章 Keil C51例子:Hello.c.. 29 第一节 uVision for Windows的使用步骤... 29 第二节 Ishell for Dos使用步骤... 30 第七章 Keil C51代码效率... 30 第一节 存储模式的影响... 30 第二节 程序结构的影响... 31 第八章 dScope for Windows使用详解... 32 第一节 概述... 32 1. 主窗口(Mainframe Window)... 32 2. 调试窗口(DEBUG Window)... 32 3. 命令窗口(Command Window)... 32 4. 观察窗口(Watch Window)... 32 5. 寄存器窗口(Registe Window)... 32 6. 串口窗口(Serical Windows)... 32 7. 性能分析窗口... 32 8. 内存窗口(Memory Window)... 32 9. 符号浏览窗口(Symbol Browser Window)... 33 10. 调用线窗口(Call-Stack Window)... 33 11. 代码覆盖窗口... 33 12. 外围设备窗口(peripherals) 33 第二节 dScope for Windows基本操作... 33 1. 指定初始化文件... 33 2. 观察变量... 33 3. 显示RAM的值... 34 4. 观察堆栈... 34 5. 中断处理程序调试... 34 6. 性能分析(Performance Analyzer:PA)... 34 第三节 dScope for Windows命令文件的编制... 34 1. 地址空间及地址空间类型... 34 2. 常量... 35 3. 变量... 36 4. 运算符... 38 5. 表达式... 38 6. 数组... 38 7. 结构和联合... 38 8. 指针:... 38 9. dScope命令语句... 38 10. 函数... 43
Small RTOS(51) 1.20.3v 说明文件 编写动机: 就像在嵌入系统中使用C语言替代汇编一样,在嵌入系统中使用RTOS是大势所趋。原因主要是现在在大多数情况下编程效率比执行效率重要(单片机便宜嘛)。但纵观51的RTOS,keil c51 所带的RTX Full 太大(6k多),且需要外部ram,又无源代码,很多时候不实用。RTX Tiny虽然小(900多字节),但是任务没有优先级和中断管理,也无源代码,也不太实用。而ucosII虽有源代码,但是它太大,又需要外部ram,所有函数又必须是重入函数,用在51这类小片内RAM的单片机上有点勉强。于是,我借鉴ucosII和RTX Tiny编写了Small RTOS 51,虽然它为51系列编写,但是它还是比较容易移植到其它CPU上。 与作者联系方法: 可以给chenmingji@tom.com(原chenmingji@163.net)写信,或是在www.zlgmcu.com.cn上的论坛ARM与ucosII区提问(目前本人是版主)或是在www.c51bbs.com的论坛上提问(不推荐。c51bbs和21ic网名均为cmj)。 版本号定义方式: a.bc.d a:主版本号,一般重大改变时改变它。 bc:次便本号,一般功能增加时改变它。 d:同一版本的修订序号。 版本升级: 1.20.3版 2004年6月8日 修正Os_q.c的一个BUG,造成FIFO发送数据时,在队列中有大量数据且队列较大时,可能会出错。 1.20.2版 2004年2月4日 修正for Keil c51的Os_cpu_c.c的StkDelB函数的BUG,它会影响任务删除的正确执行。 1.20.1版 2004年2月4日 修改OSWait(K_SIG | K_TMO, x) 只能通过信号唤醒的bug。 1.20.0版 2003年8月3日 支持任务动态建立与删除。函数功能向一般的RTOS靠拢。支持C51的重入函数(用关键字reentrant定义的函数)。支持动态内存分配(使用动态内存分配的任务必须使用重入栈)。 1.12.1版 2003年2月5日 修正OS_MAX_TASKS为8、16时的bug。同时修正一些小bug。 1.12.0版 2003年1月24日 OS_MAX_TASKS就是用户任务数量。同时修正一些小bug。 1.11.0版 2002年12月2日 各个任务具有自己的关中断计数器,不在互相影响(这意味着如果一个任务在任务放弃CPU前关了中断,当它再次进入运行态时中断还是关的)。优先级最低的任务作为系统保留任务不再需要用户编写,同时节约一些内存。增加一些注释。更正在Keil C51下Memory Model为非Small 模式的Bug。 1.10.5版 2002年10月26日 更正许多小Bug。 1.10.4版 2002年10月6日 合并Os_cpu_a.asm和OS_CPU_A_task16.ASM。统一了一下代码风格 1.10.3版 2002年9月16日 修改了Os_cpu_a.asm和OS_CPU_A_task16.ASM的LoadCtx代码使之执行更快,代码更小 1.10.2版 2002年9月9日 更正OSWait()的Bug,在极端情况下,这个Bug可能造成可能锁死任务。 修改OSQIntPost()的Keil C51特殊代码,它会造成阅读障碍。 1.10.1版 2002年9月4日 更正OSTimeTick的Bug,它在keil c51中不会有问题,但移植的其它系统可能出错。 1.10版 2002年9月1日 增加Small RTOS 对消息队列(简化的)和信号量的支持;改变了开关中断的方式;增加可移植的变量定义;修正一些Bug。 1.00版 2002年6月20日 使用户可以进行更多的配置,可以禁止中断管理,51系列支持软的非屏蔽中断,并调整目录结构等. 0.60版 2002年5月10日 修改OS_CORE.c使之在keil c51可以重入。不再需要禁止覆盖分析。 0.52版

27,375

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧