51单片机有趣的小制作 ram 中执行代码的 如何链接

&>&在RAM中执行程序代码
在RAM中执行程序代码
上传大小:116KB
【实验题目】
在RAM中执行程序代码
【实验目的】
掌握片外RAM扩展方法(重点是硬件接法,而程序操作很简单)。
弄清楚什么是“哈佛存储结构”和“冯·诺依曼存储结构”。
【硬件接法】
P1.2接交流蜂鸣器。
请认真参考硬件电路图中RAM的接法。RAM映射到地址“0x8000~0xBFFF”,共16KB。
【实验原理】
8051单片机本来是“哈佛存储结构”,程序ROM和片外数据RAM位于完全分开的存储空间。/WR和/RD信号用于访问片外数据RAM。当使用片外程序ROM时,/PSEN管脚负责读取程序代码或固定数表。通常ROM不可写,所以未安排ROM的写信号。ROM和RAM共用地址和数据总线,但读写选通信号是分开的,所以在逻辑上分属两个不同的64KB空间,总共128KB。另外片内数据RAM和SFR空间又与前两者有别,是独立编址的。在软件上,访问不同的存储空间采用不同的指令,如“MOVX A,@DPTR”、“MOVC A,@A+DPTR”、“MOV
A,@Ri”等。
注意,/PSEN和/RD可以经过“与门”后再接到RAM的/OE。这样,代码和数据都位于相同的地址空间,在RAM中也可以跑程序,用“MOVC”和“MOVX”指令都能访问RAM的存储单
元。如果把程序代码加载到片外RAM中,然后用“LJMP”指令跳转过去就能在RAM中执行程序代码。
【说明:片内Flash中的引导程序】
这是一个比较复杂的程序,其中还牵涉到了C51中嵌入汇编的用法。对大多数初学者来说,只要了解其工作过程即可,不必深究。如果您确实对其感兴趣,请自行仔细研究。
该引导程序位于片内Flash中,其作用是通过串行口加载HEX格式的程序文件,并自动转换成BIN格式,然后保存到片外RAM中,最后跳转过去执行。RAM起始地址为0x8000。引导完毕后,蜂鸣器鸣叫,并等待按下K4键。K4按下后,才开始执行。
【说明:在片外RAM中运行的程序】
编写在片外RAM中运行的程序与编写正常的A51或C51程序基本相同,但是需要做一些小的调整。正常的程序起始地址总是0x0000,但现在片外RAM的起始地址是0x8000,因此要在原有程序的基础上重新设置起始地址。
对于A51编程,找到ORG命令,修改复位地址和全部中断向量入口地址,使它们都偏移0x8000。例如复位地址为0x0000要改成0x8000,定时器T0中断入口地址0x000B要改成0x800B,等等。重新编译,生成HEX程序文件,备用。
而对于C51编程,设置的项目稍多一些,步骤如下:
第一,打开Keil C51安装目录“C:\Keil\C51\LIB”,找到文件“STARTUP.A51”,将其复制到您的工程文件夹下,然后右击项目管理窗口的“Source Group1”添加该文件。另一种方法是:在新建工程选择“CPU”后,当出现是否添加启动文件对话框时选择“是”,则文件“STARTUP.A51”会自动被加入。
第二,双击项目管理窗口里的“STARTUP.A51”,找到“CSEG
0”这一行,将起始地址“0”改成“0x8000”,保存。
第三,设置片外程序ROM的起始地址和大小。打开编译环境中设置(点击工具栏的那个绿色按钮进入该设置),在“Off-chip Code memory”Eprom(在这里,Eprom实际上已被RAM代替)栏第一行填入0x0(共12KB空间)。
第四,程序中有可能用到xdata数据,因此还要设置片外数据RAM的起始地址和大小。可以在“Off-chip Xdata memory”Ram栏第一行填入0xB000和0x1000,留足空间(有4KB呀!)。
第五,设置中断向量。打开“Options fo Target”设置里的“C51”选项页,找到“Interrupt vectors at...”项,修改为“0x8000”。
OK,所有设置都已完成,重新编译,生成HEX程序文件,备用。
【实验步骤】
1、ISP下载开关扳到“01”,用Flash Magic软件下载程序文件“HexLoader.hex”,暂时不要运行。
2、打开串行调试助手软件ZLGCOMView,操作如下:
勾中“HEX发送”(非常重要!);
通信口:选择实际的串行口(通常为COM1);
波特率:4800;
数据位:8;
停止位:1;
点击“打开文件”装入文件夹“在片外RAM中运行的程序”下的一个程序文件(HEX格式),在这些程序中,所有起始地址都已经预先设置好了;
按实验箱上单片机的RST键,会看到显示“Ready”;
点击“发送文件”,程序开始下载到片外RAM;
下载完毕,出现“OK, press K4...”,蜂鸣器同时鸣叫;
按一次实验箱上的K4键,程序开始运行。
【重要注意事项】
程序在片外RAM运行时,需要占用并行总线,因此P0、P2端口都不能再作为普通I/O使用了,否则冲突导致运行失败,切记!
...展开收缩
综合评分:5
{%username%}回复{%com_username%}{%time%}\
/*点击出现回复框*/
$(".respond_btn").on("click", function (e) {
$(this).parents(".rightLi").children(".respond_box").show();
e.stopPropagation();
$(".cancel_res").on("click", function (e) {
$(this).parents(".res_b").siblings(".res_area").val("");
$(this).parents(".respond_box").hide();
e.stopPropagation();
/*删除评论*/
$(".del_comment_c").on("click", function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_invalid/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parents(".conLi").remove();
alert(data.msg);
$(".res_btn").click(function (e) {
var parentWrap = $(this).parents(".respond_box"),
q = parentWrap.find(".form1").serializeArray(),
resStr = $.trim(parentWrap.find(".res_area_r").val());
console.log(q);
//var res_area_r = $.trim($(".res_area_r").val());
if (resStr == '') {
$(".res_text").css({color: "red"});
$.post("/index.php/comment/do_comment_reply/", q,
function (data) {
if (data.succ == 1) {
var $target,
evt = e || window.
$target = $(evt.target || evt.srcElement);
var $dd = $target.parents('dd');
var $wrapReply = $dd.find('.respond_box');
console.log($wrapReply);
//var mess = $(".res_area_r").val();
var mess = resS
var str = str.replace(/{%header%}/g, data.header)
.replace(/{%href%}/g, 'http://' + window.location.host + '/user/' + data.username)
.replace(/{%username%}/g, data.username)
.replace(/{%com_username%}/g, data.com_username)
.replace(/{%time%}/g, data.time)
.replace(/{%id%}/g, data.id)
.replace(/{%mess%}/g, mess);
$dd.after(str);
$(".respond_box").hide();
$(".res_area_r").val("");
$(".res_area").val("");
$wrapReply.hide();
alert(data.msg);
}, "json");
/*删除回复*/
$(".rightLi").on("click", '.del_comment_r', function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_comment_del/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parent().parent().parent().parent().parent().remove();
$(e.target).parents('.res_list').remove()
alert(data.msg);
//填充回复
function KeyP(v) {
var parentWrap = $(v).parents(".respond_box");
parentWrap.find(".res_area_r").val($.trim(parentWrap.find(".res_area").val()));
评论共有7条
可以,谢谢楼主分享。
相当有帮助,谢谢!
好资料,学习了谢谢
VIP会员动态
CSDN下载频道资源及相关规则调整公告V11.10
下载频道用户反馈专区
下载频道积分规则调整V1710.18
spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip
资源所需积分/C币
当前拥有积分
当前拥有C币
输入下载码
为了良好体验,不建议使用迅雷下载
在RAM中执行程序代码
会员到期时间:
剩余下载个数:
剩余积分:0
为了良好体验,不建议使用迅雷下载
积分不足!
资源所需积分/C币
当前拥有积分
您可以选择
程序员的必选
绿色安全资源
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
无法举报自己的资源
你当前的下载分为234。
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可返还被扣除的积分
被举报人:
请选择类型
资源无法下载 ( 404页面、下载失败、资源本身问题)
资源无法使用 (文件损坏、内容缺失、题文不符)
侵犯版权资源 (侵犯公司或个人版权)
虚假资源 (恶意欺诈、刷分资源)
含色情、危害国家安全内容
含广告、木马病毒资源
*投诉人姓名:
*投诉人联系方式:
*版权证明:
*详细原因:
在RAM中执行程序代码查看: 12330|回复: 3
51单片机同时外扩RAM,ROM的具体实现及Keil的具体设置
51MCU内部有RAM,ROM,不同于8031。尽管如今的增强行51MCU的内部RAM,ROM可能已经很大的空间。但就技术而言,扩展RAM,ROM还是需要学会的。
& && &&&对于不同的设计方案需求,扩展可能基于以下任何一种设计:
& && &&&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_
& && && && &&&***绝对地址的变量不可以被初始化;函数或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 &absacc.h&头文件中
& && && && &&&#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地址范围0xFFF,所以外部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文件的0xFFF地址划分为一个文件,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的总线时序和扩展设备的时序匹配才可以的。
楼主好样的,谢谢楼主的分享,太感谢啦
好贴,感谢
Powered by单片机运行的程序是RAM中的还是RoM中的_百度知道
单片机运行的程序是RAM中的还是RoM中的
单片机运行的程序是RAM中的还是RoM中的像电脑是将程序从硬盘中加载到内存即RAM中运行的
单片机是不是也是将程序从R0M中加载到RAM中运行的?
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
常规上ROM是用来存储固化程序的,RAM是用来存放数据的。由于FLASH ROM比普通的ROM读写速度快,擦写方便,一般用来存储用户程序和需要永久保存的数据。譬如说,现在家用的电子式电度表,它的内核是一款单片机,该单片机的程序就是存放在ROM里的。电度表在工作过程中,是要运算数据的,要采集电压和电流,并根据电压和电流计算出电度来。电压和电流时一个适时的数据,用户不关心,它只是用来计算电度用,计算完后该次采集的数据就用完了,然后再采集下一次,因此这些值就没必要永久存储,就把它放在RAM里边。然而计算完的电度,是需要永久保存的,单片机会定时或者在停电的瞬间将电度数存入到FLASH里。
罗素了这么多,不知道楼主看明白了没有。
非常感谢。单片机运行程序 是 像电脑那样把硬盘中的程序加载到内存(即RAM)中运行,也是将程序从R0M中加载到RAM中运行的一样?
还是直接运行ROM中的程序,而不用将ROM中的程序加载到RAM中,也就是直接将ROM中的程序加入单片机的指令寄存器中运行?
采纳率:81%
你还是先弄清RAM和ROM是什么吧,后面是反过来说的。
非常感谢。单片机运行程序 是 像电脑那样把硬盘中的程序加载到内存(即RAM)中运行,也是将程序从R0M中加载到RAM中运行的一样?
还是直接运行ROM中的程序,而不用将ROM中的程序加载到RAM中,也就是直接将ROM中的程序加入单片机的指令寄存器中运行?
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。转自:http://blog.sina.com.cn/s/blog_a575eb9401014tam.html
单片机内程序运行的时候ram空间是如何分配的?我现对一个程序进行减少片内ram的使用的优化,有一些效果,同时也产生了些疑问,在此向各位大虾请教:一、现象:1、&&&&我在通过减少全局变量、函数内变量的使用,减少函数间参数传递等手段来优化,发现某些时候我减少一个变量的使用,keil编译的结果就显示data减少了一字节,有时候这样一直减少几个变量的使用,data值一直都不会变,接着再减少变量的使用,又会一个一个的减少,到后来又不减少了。2、&&&&我屏蔽程序中一些代码之后编译,显示data反而是增加了。二、疑问:1、单片机程序运行的时候,内部ram是如果分配管理的,data值由哪些部分组成?2、之前描述的两个现象如何解释?3、data值是不包括堆栈空间的,那么程序运行的堆栈空间大概需要多少,和哪些因素有关,能不能预估?4、单片机片内ram的使用限度是多少?(指keil编译出来的data值最好不要超过多少)&&
答:单片机内程序运行的时候ram空间是如何分配的1、RAM的分配是与你选择的编译模式有关,你可以看下编译器的手册,再打开最后产生的分配对照表仔细对照源程序,应该可以找到规律。2、仍然与编译模式有关,通常全局变量数量的变化可以立即反映在data段的长度上,但如果局部变量是指定用堆栈,就不一定会反映在data段的长度上了。3、堆栈空间与你的RAM空间的分配有关,这是在连接时确定的,在链接描述文件中指定的。4、RAM的使用限度当然跟你的单片机RAM的大小有关。对不起,我对Keil的环境不熟,我不能帮你解释具体到Keil上如何;上面讲的是基本原理,每个C语言的环境都是这样。
谢谢平常人!若有机会到广佛一带,我请你喝酒!keil编译模式我选择的small:variables in data模式,大家一般也都应该是这个模式吧。变量都是定义到data/idata区的。keil编译结果和编译器本身有关,就算是不同的编译器,在内存分配上是不是有共同遵从的方法呢?或者您能不能介绍其他某个编译器的内存分配方式呢?通常全局变量数量的变化可以立即反映在data段的长度上,但如果局部变量是指定用堆栈,就不一定会反映在data段的长度上了。re:你的意思是局部变量占用的空间的使用还不一定包含到编译结果里了?我编译的结果是200多字节的data,由哪些组成?ram使用限度跟单片机有关,那好比我的单片机片内ram是256的,那我使用的空间(也就是keil编译出来的结果)的限度是多少,或者和哪些有关?也就是通常做法,我要留给堆栈多少空间?另外再问一下:同一个程序生成的bin文件和hex文件在大小上有什么关系?听说bin会是hex的一半?这两个文件在使用中有什么区别?
变量在内存的分配方式通常单片机的RAM区可以分成3类,短地址区、长地址区和外部地址区。短地址区一般指00-FF之间可以用8位地址访问的区域,长地址区一般指0100-FFFF之间必须用多于8位的地址访问的区域,外部地址区指CPU外部总线访问的区域,不同的区域有不同的指令寻址方式,例如:MOV A, 40H ;访问短地址区MOV A, @DPTR ;访问长地址区一般的51中没有外部地址区。根据用途还划分了一个堆栈区。不同的存储分配模式决定了全局变量是放在那个区域,访问短地址区的指令可能比访问长地址区的指令短且快,但长地址区可容纳较多变量,尤其是较大的数组。局部变量有两种分配策略,一种是放在堆栈中,因为局部变量只在他所在的函数中有效,出了这个函数退栈就可以清理掉局部变量所占空间,空间可重复利用。这种策略下,减少局部变量的使用并反映不出内存占用量的减少,因为内存的占用是动态的。另一种策略是分析函数调用关系,把局部变量放在某段特定的内存区,如下例:func1(){&c1, c2;....}func2(){&x1, x2, x3;...}main(){func1();func2();....}编译器发现func1与func2没有调用关系,就把c1与x1分配到同一个地址,c2与x2分配到同一个地址,x3分配到另一个地址;这样处理可以比堆栈的方法得到较高的效率。当你减掉c1时,并没有减少内存的总用量。所以,堆栈的长度要看你程序的调用关系,局部变量的使用策略等因素,根据实际情况决定。至于bin与hex文件的区别,我的理解bin是用二进制的形式存放可执行代码,而hex文件使用ASCII形式存放可执行代码;如&&0x12, 0x34, 0x56&&bin文件&&1 2 3 4 5 6 hex文件你说他们的大小是什么关系?对不起,我只能讲这么多了,再讲就可以写一本书了。
阅读(...) 评论()MCU 如何实现让部分代码运行在 RAM 中
MCU 异于 资源丰富的linux 平台。 MCU(如: 基于Cortex V6M 的Cortex M0+ 等) Code
通常运行在内嵌Flash 中。 在某些特定应用场合,需要将
部分函数运行于RAM 中。 昨天,为解决次问题,实现了一种解法,具体做法如下:
1. 实现要运行在RAM的 routine, 本routine 使用纯汇编实现, 如:
__asm void program_word2addr(uint32_t addr, uint32_t data)
push {r3, r4, r5, lr}save some regsiters
/*your code for this routine*/
pop {r3, r4, r5, pc}
编译时,采用code 与运行位置无关的编译选项 如 (Keil --apcs /ropi/rwpi), 生成 *.axf;
通过fromelf -c 将生成 *.axf 反汇编,找到对应program_word2addr 实现部分, 并将routine 对应的binary code Copy 到所要应用的 Code 中,以只读数组的形式出现:
const staic uint16_t s_flashProg2AddressCode[16] = {...., ....}
定义 一个全局数组, 如 static uint16_t g_code[16], size正好等于 s_flashProg2AddressCode的长度;
5. 定义一个函数指针, 如
static void (*callFlashPrg2Address)(uint32_t addr, uint32_t data)
6. 定义一个函数实现将Code 运行与 RAM如:
void run_prgcode_onram(uint32_t addr, uint32_t data)
memcpy(g_code,s_flashProg2AddressCode,32 );
callFlashPrg2Address = (void (*)(uint32_t addr, uint32_t data))((uin32_t)g_code + 1);
callFlashPrg2Address (address, data);
run_prgcode_onram, 便可以将program_word2addr 运行于RAM中。
callFlashPrg2Address = (void (*)(uint32_t addr, uint32_t data))((uin32_t)g_code + 1); +1 的目的,时由于运行平台为 Cortex V6M , 采用的thumb指令集,根据ARM Spec 要
callFlashPrg2Address (address, data); 则是实现RAM运行program_word2addr 的关键所在。
把DSP TMS320F28XXX的程序段从flash复制到ram中运行
程序在flash中还是ram中运行
RAM之程序运行时数据和代码加载
KEIL中如何程序在 RAM 中运行
MCU编译与运行浅谈
MCU应用程序架构
MCU的启动代码
单片机ram和rom的区别
将程序从Flash搬运到RAM中运行总结(转载)
ARM如何指定函数运行在RAM--KEIL
没有更多推荐了,

我要回帖

更多关于 初学单片机 的文章

 

随机推荐