历史上的今天
今天是:2024年11月19日(星期二)
2018年11月19日 | 51单片机内存扩展:从片内ROM跳转到片外ROM
2018-11-19 来源:eefocus
源于一年前想自己动手给51写个OS,编译选Large模式,调试时整个流程都跑的好好的,可是烧写到片上后得不到预期的效果,后来查书才知道51单片机片上只有4KRom,如果没有扩展片外Rom,当访问4K以外的程序空间,程序指针又会回到最开始执行。参考手册扩展片外Rom后,能访问达64K的程序空间。网上能搜索到的扩展方式都是将EA引脚接地,让MCU上电后从外部ROM开始执行。但查看芯片手册,明明说EA为高时,程序从片内ROM执行,当执行到0x1000以上地址时(标准51单片机),会跳转到片外ROM执行。按网上的做法,为了扩展个片外ROM,片内的基本ROM都不用了,有点浪费了,于是开始找资料如何从片内跳转到片外执行。
射人先射马,发帖先上图,仿真图如下:

此处EA脚没有接地。如果想简单粗暴的加电时从片外ROM执行,EA引脚接地,双击U2(27C64)Image File选Hex然后就可以了,这不是本文的重点,略过,后面可能会写到。
跳转,最简单的方式用LJMP,当然也可以用把跳转地址压入栈,然后ret过去,不过这种方式我没尝试成功。
考虑到汇编写代码太苦逼,写规模大一点的代码还得靠C,因此程序的效果是:main函数在片内执行,流水灯代码存放在片外Rom,main函数跳转到流水灯中执行。
因为是一种尝试,所以从写汇编代码开始(加载地址容易控制:ORG指定即可)
1)用汇编代码跳转:
AT89C51中的代码:
ORG 0000H
LJMP 1000H
END
#####################
27C64中代码:
ORG 1000H
STAR:
MOV A,#0AAH
MOV P1,A
MOV A,#55H
MOV P1,A
SJMP STAR
END
程序运行起来后,PC寄存器指向0x0000处的LJMP 0x1000,然后跳到27C64处执行。起初,在27C64 0x0000处搜索编码,没找到,查阅手册后知,当PC超过0FFFH时,会转向片外程序存储空间1000H-FFFFH执行程序。

[27C64处的内容]
2)用C代码跳转:
#include
int main()
{
int i=0;
i++;
/*
执行一些初始化逻辑,或者接受交互内容,按不同的输入,跳转到片外ROM
*/
#pragma asm
LJMP 0x1000
#pragma endasm
while(1);
}
C代码中嵌入汇编,做跳转。
这个连接中有相关的设置 http://bbs.ednchina.com/BLOG_ARTICLE_1721.HTM 如果不做设置,连接时会有警告找不到C_STARTUP,也不会运行到代码中。
调试运行,由于KEIL C加了启动代码,在protues仿真时有一长段麻烦的初始化堆栈的过程,因为没有源码,连设置断点都不行,只能按着F11傻等着。最终当然也是能跳转到片外ROM执行的。
3)片外ROM存放由KEIL C编写的HEX文件
这个摸索了很久才摸索出来!代码如下:
#include
int main()
{
while(1)
{
P1 = 0x33;
P1 = 0xcc;
}
}
首先,由于KEIL C创建的新工程会添加启动代码(startup.a51),这个前面说过用来初始化C语言运行的堆栈。因为我的程序是从片内ROM跳转过来运行的,至少已经被初始化了一次,再初始化一次,原本保留的变量全没了,因此在创建工程的时候,跳过添加startup.a51这个文件。带来的不便是:程序没有C环境,想要在调试是不可能了。
hex文件是生成了,加载,但是从片内ROM跳转过来后,P1口的内容不是0x33/0xCC而是上一次运行时的0x55/0xAA,why?代码写错了?
查看27C64的内存印象:
0x0000H的内容是:

75 90 33和75 90 CC是往P1端口写入0x33/0xCC---就是现在的代码
再查看0x1000H的内容:

74 AA对应MOV A,#0AAH,F5 90 对应MOV 90,A,明显是上次仿真时的结果!
好吧,现在得想办法把代码加载到0x1000的位置,ORG是用不上了,得用其他办法。
在我的另一篇文章 中提到,INTEL HEX文件格式中每个规则开始处都有地址,那好先看看这段代码的地址:
:08000F007590337590CC80F868
:03000000020003F8
:0C000300787FE4F6D8FD75810702000F3D
:00000001FF
080000F007 08是这行的长度8字节,后面的0000是这行加载位置,从0x0000开始。shit,难怪加载补上。先手动修改地址,修改玩以后,protues提示HEX校验码不对,仿真失败。无奈,只能想其他办法了。加载地址一般是由连接器在连接阶段确定的(

BL51是KEIL C的连接器,Code这个位置好像是,那就试试填入0x1000,然后再编译连接:
:08100C007590337590CC80F85B
:03000000021000EB
:0C100000787FE4F6D8FD75810702100C23
:00000001FF
这次生成的HEX文件,链接地址部分已经被改为0x100C。再仿真一次,不过这次仿真前要把片内ROM的跳转地址改为LJMP 0x1003,要不然指不准执行了非法指令。

27C64 0x100C处的内容75 90 33对应汇编语句 MOV 90,#33H 75 90 CC对应汇编语句MOV 90,#0CCH这正是c代码的内容,而且P1口的内容也是CC。
至此,从片内ROM跳转到片外ROM结束。另外估计ISP烧写器可能也是类似的工作原理
上一篇:教你给51单片机扩展片外RAM
下一篇:51单片机stack堆栈
史海拾趣
|
请问各位:基于PID算法的有刷直流电机PWM调速系统中对有刷直流电机调速用到的算法是模拟 PID控制原理还是增量式PID控制或者别的PID控制原理?能否将PID算法式子告诉我?谢谢各位了!!QQ:286410824… 查看全部问答> |
|
本人在使用该芯片过程中遇到一些问题,想请有经验的朋友指教一下。 本人用720极的圆感应同步器作为角度传感器,想利用AD2S80来解码。 激磁信号使用的是5Khz的正弦波,AD2S80设置的分辨率为12位,该芯片的外围电路完全按照芯片手册上的针对5KHZ/12 ...… 查看全部问答> |
|
自己写的服务端和客户端,头文件包含是winsock2.h, 库使用的是Ws2.lib。 客户端发送消息是正常的,服务端也能收到消息,但是接收不到客户端发送的具体消息内容(一个字符串)。 同样的代码在windows下可以正常使用(用的库是ws2_32.lib)。 急 ...… 查看全部问答> |
|
我是MSP430小白,正处于入门阶段。 由于要做课题是关于MSP430平台下的存储,存储介质一般都是sd卡吧,所以我想找一本关于sd卡存储的数据组织、分区分簇(我不知道有没有这个概念,类似硬盘下单扇区之类的),主要介绍它的硬件特性和功能,有没有这 ...… 查看全部问答> |
|
TPS2393A集成电路是一款专为-48V系统优化的热插拔控制器。TPS2393A广泛用于许多应用中,它拥有如下强大功能:. 宽泛的输入电源范围. 可编程电流限制. UV/OV保护.&nbs ...… 查看全部问答> |
|
晒WEBENCH设计的过程+利用易电源设计工具进行一款USB充电器的设计 SIMPLE SWITCHER中文名字叫易电源,顾名思义它是一个非常容易控制的电源芯片。过去分离式方案相比,SIMPLE SWITCHER现在新推出的方案是一种更为集成的解决方案,它把MOS管和电感都集成在芯片内部,这样它就具有了明显的优势:把外部的元器件减少, ...… 查看全部问答> |




