对于不同的设计方案需求,扩展可能基于以下任何一种设计:
A,只扩展RAM
B,只扩展ROM
C,扩展ROM,RAM
总线扩展时,P2口是否可用做普通IO口
这种扩展是基于总线扩展的,所以,P0P2口就已经不可以再做它用了(有网友提供信息,总线扩展P2还可以做普通IO口用,有两种可能:1,P2口复用,如同P1利用373锁存器。2,在总线扩展时,只用到了低地址总线,P2口未用到。就作为普通IO口应用。由于技术还不到位,不做评论。)
*扩展RAM程序
扩展RAM,在程序中定义的xdata类型 XBYTE类型等地址范围在外部RAM的变量,对其读写的过程。用C51语言编写程序,且使用总线扩展的RAM,则时序电路不用考虑,WR RD等信号由编译器/硬件自动完成。
编译器设置*
内部RAM:0x00~~0xFF
外部RAM:0x0000~~0xFFFF
RAM的地址虽重复,但是两个RAM是没有关系的,所以不会造成干扰
使用了外部RAM,就在工程选项---off-chip xdata memory中设置 start:0x0000 size:0xFFFF(根据具体的RAM大小设置size)。
*扩展RAM时的变量定位及连续读取问题*
ROM,RAM的扩展时,需要用到变量的绝对地址定位,函数定位等。
变量的绝对地址定位,是由于在程序中可能需要即时读取某个变量,但变量的类型可能是XDATA,存储在外部RAM中。这里有两个方法:
1,用 _at_ 定位 关键字定位
unsigned char xdata xxx _at_ 0x1100 //定义变量XXX数据类型xdata,位置0x1100
[memory_space]tepe variable_name _at_ constant;
*绝对地址的变量不可以被初始化;函数或BIT类型的变量是不可以被定义为绝对地址;
2,用 XBYTE 定位 宏定义 绝对地址访问
#define CBYTE((unsigned char volatile code*)0)
#define DBYTE((unsigned char volatile idata*)0)
#define PBYTE((unsigned char volatile pdata*)0)
#define XBYTE((unsigned char volatile xdata*)0)
////////////////////////////////////////////////////////////////////////////
#define CWORD((unsigned int volatile code*)0)
#define DWORD((unsigned int volatile idata*)0)
#define PWORD((unsigned int volatile pdata*)0)
#define XWORD((unsigned int volatile xdata*)0)
以上是宏定义的原型函数,定义在 #include
#defme xxx XBYTE[0x8000] //变量类型为unsigned char 类型的数据xxx,位置xdata 0x8000
yyy=XBYTE[0x8000]; //变量类型为unsigned char 类型的数据yyy,位置xdata 0x8000
(在这里,有网友提到,当编译器优化时,用绝对地址定位的变量,可能导致变量在连续读取时出
错,采用解决方法:
a,将编译器优化调整为0,即不优化,程序不用修改,做以下操作
>>选择project窗口的Target,然后打开"OptionsforTarget” 设置对话框,选择“C5l”选项卡,
将“Code Optimiztaion”中的“Level”选择为“0:Costant folding”。再次编译<<
b,修改变量定义,增加“volatile”关键字说明其特征:就是说明该变量具有‘挥发’性,每次的读取都一
有意义的,这样编译器即使在优化时,编译后的代码也不会省略掉重复读取的过程。如:
unsigned char volatile xdata xxx_at_0x8000;
由上文XBYTE等的宏定义函数原型可以看出,该宏定义已经说明了变量具有volatile特性,因此,
也可以直接用XBYTE定义所需要的变量
c,硬件解决办法
以上解决方法为参考网络文章)
*扩展ROM时的函数定位函数一部分在内部ROM,一部分在外部ROM中
函数定位,个人理解:当一个完整功能的程序存储在外部内部ROM中时,即利用了内部ROM,可能由于内部ROM空间不够,部分函数在外部中,这时,如果要执行整个功能,就需要告诉编译器,其他功能函数的地址(函数在外部ROM中的地址),此时就要用到函数定位功能。解决方法如下:
....待续.....
51内部ROM地址范围0x0000~0x0FFF,所以外部ROM的地址为0x1000~~最大0xFFFF。
c51bbs有详细介绍
编写完整的程序(如果建立两个工程,堆栈等可能分配位置不同,导致地址重复或多个地址出错),
编译后查看.M51文件,找到需要定位的函数名称信息(如?PR?_BCD2HEX?TOOLS),在KEIL51工程选项---BL51 lacate中code项中加入:?PR?_BCD2HEX?TOOLS(0x1000)再次编译工程,打开.M51文件会发现?PR?_BCD2HEX?TOOLS已经定位在了0x1000位置了。
如果有多个程序需要定位,方法同上,找出函数的名称信息,添加到BL51 locate的CODE项中,每个函数之间用逗号隔开。而且要注意,所要定位的多个函数根据定位设置之前的地址高低安排,仍旧是低地址函数在前,高地址函数在后。
程序分为两部分存储,需要做的设置等如下:
....待续.....
完成函数定位设置后,由于函数是要烧录在两个ROM中,需要将HEX文件分割成两个,内部ROM空间范围与外部ROM空间范围是不一样的,自然就应该将内部ROM的地址范围的HEX代码存储为一个文件,将剩余部分的代码存储为另一个文件,就完成了分割。
例如HEX文件的0x0000~~0x0FFF地址划分为一个文件,0x1000~~0xFFFF划分为另一个文件。
这一点,如果所用的MCU的内部ROM大小不一致,就需要根据具体的大小划分分割HEX文件。
*编译器设置
由于是内部ROM和外部扩展ROM同时使用,在工程选项off-chip memory中需要设置外部ROM地址范围,如eprom start:0x1000 size:0xFFFF(根据具体ROM大小设置size,同时use on-chip memory选项不选,电路中EA接高电平)
*扩展ROM,所有程序都在外部ROM中
51内部ROM不够用,但外部扩展的ROM应该足够了,所以,在扩展了ROM之后,尽量避免编程麻烦,所有功能均放在外部ROM中,此时需要的设置操作等如下:
....待续.....
由于程序代码只用到了外部ROM,程序编译等不需要特殊的设置,按正常编译。然后将整个代码烧录到外部ROM就可以了。也就不存在HEX文件分割的问题了。
*编译器设置
由于只用到了外部ROM,在工程选项off-chip memory中需要设置外部ROM地址范围,如eprom start:0x0000 size:0xFFFF(根据具体ROM大小设置size,同时use on-chip memory选项不选,电路中EA接低电平),这里的设置不同与内外部ROM都用的情况,没有使用内部ROM的情况下需要地址从0x0000开始,程序的开始地址中断向量等都在这里(具体参考内部ROM地址的使用)。EA接低电平表示程序是从外部ROM开始读起的,即不用内部ROM。
扩展ROM,RAM时,总线地址如何安排*
在扩展了ROM,RAM时,总线地址要如何安排,具体怎样设置呢?操作如下:
......待续.......
在程序设计时,要考虑硬件连接。例如,在外部ROM,RAM的地址设置时(keil工程选项中),假设P15初始化置1了或在程序中,P15为1时WR RD信号才时序正常(使用了74门电路),则keil工程选项中的地址设置就要考虑工作状态P15是0或1的情况了。页选信号就是从这里这样而来的,P15页选或地址线高字节页选。
*硬件连接,需要考虑的问题
扩展ROM,RAM时,硬件需要则样连接?总线上的时续,总线设备的速度匹配问题?
.......待续........
使用总线方式连接扩展设备时,51总线有固定的时序,时序也就决定了速度。比如每个读写的过程,相应的信号持续时间长短,扩展设备能否在这个周期内完成工作,是需要51的总线时序和扩展设备的时序匹配才可以的。
上一篇:51单片机ROM与RAM
下一篇:与51单片机扩展有关的知识点
推荐阅读最新更新时间:2024-03-16 14:55