用Keil做51的开发也4年多了,代码量基本上维持在5~10K左右,说大不大,说小也不小,也就是个中等货色。这段期间工作上难得有稍许的空间,潜心研究了一下keil中如何在 CODE中定位C程序的方法。

在汇编中数据段和程序段都比较容易定位,例如程序1:

    cseg    at 0x0000
    ljmp    main
    dseg    at 0x20 

    iseg    at 0xC0 

    xseg    at 0x0010 

    cseg    at 0x1000
main: 

    sjmp    main
    END 

  这段代码就把main定位到0x1000的位置。aa 定位在data(0x20)中,bb定位在idata(0xc0)中,CC定位到xdata(0x0010)当然,cc在不超过256字节的时候还可以用 page方式访问。

  在C语言程序里面定位比较复杂。

  常见的数组定位有如下几个方式:

  1、使用 _at_ ,例如程序2:

#include <reg51.h>
unsigned ] _at_ 0x20;    //在data段中0x20开始的地方定义一个20字节的数组
unsigned ] _at_ 0x80;    //在idata段中0x80开始的地方定义一个20字节的数组
unsigned ] _at_ 0x0000;  //在pdata段中0x00开始的地方定义一个20字节的数组
unsigned ] _at_ 0x0100;  //在xdata段中0x0100开始的地方定义一个20字节的数组

void main()
{
    sysTemp_aa[] = 0x55;
    sysTemp_bb[] = 0x55;
    sysTemp_cc[] = 0x55;
    sysTemp_dd[] = 0x55;

    )
    {
        ;
    }
}

编译后生成的汇编代码如下:

C:0x0000    020015   LJMP     C:0015 
    11: void main() 
12: { 
    13:         sysTemp_aa[0] = 0x55; 
C:0x0003    752055   MOV      sysTemp_aa(0x20),#0x55 
    14:         sysTemp_bb[0] = 0x55; 
C:0x0006    7880     MOV      R0,#sysTemp_bb(0x80) 
C:0x0008    7655     MOV      @R0,#0x55 
    15:         sysTemp_cc[0] = 0x55; 
C:0x000A    7800     MOV      R0,#sysTemp_cc(0x00) 
C:0x000C    7455     MOV      A,#0x55 
C:0x000E    F2         MOVX    @R0,A 
    16:         sysTemp_dd[0] = 0x55; 
17:  
C:0x000F    900100  MOV      DPTR,#sysTemp_dd(0x0100) 
C:0x0012    F0         MOVX    @DPTR,A 
    18:         while(1) 
C:0x0013    80FE     SJMP     C:0013 
C:0x0015    787F     MOV      R0,#0x7F 
C:0x0017    E4        CLR       A 
C:0x0018    F6        MOV      @R0,A 
C:0x0019    D8FD     DJNZ     R0,C:0018 
C:0x001B    758193   MOV      SP(0x81),#0x93 
C:0x001E    020003   LJMP     main(C:0003)

请注意加横线的是汇编代码对应的C程序。

  函数定位

  更深入一 点,如果我想把main函数定位呢?上面的汇编代码是由keil自动定位的一个地址,添加或者删除程序后,main的地址是不确定的,能否在也使用 _at_呢?答案是否定的。要想把程序段绝对定位需要在keil里面采用一定的设置。例如程序3:

#include <reg51.h>
unsigned ] _at_ 0x20;
unsigned ] _at_ 0x80;
unsigned ] _at_ 0x0000;
unsigned ] _at_ 0x0100;

extern void test1();

void main()
{
    sysTemp_aa[] = 0x55;
    sysTemp_bb[] = 0x55;
    sysTemp_cc[] = 0x55;
    sysTemp_dd[] = 0x55;

    )
    {
        test1();
    }
}

void test1()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
}

  我想把main函数定位到0x1000开始的地放,test1定位到0x2000开始的地方,怎么设置呢?点击“project”->”option for target ..."弹出如下窗口:

选择BL51 MISC,在Misc controls的框中填入code (?PR?MAIN?TEST (0x1000),?PR?TEST1?TEST (0x2000))。这里我解释一下,

code 表示程序段

?PR?各位可参考一下keil的帮助文件

?PR? 表示program 意思是 Executable program code(可执行程序段)

MAIN 和 TEST1 就是你要定位的程序名称

?TEST是main和test1所在的文件名,我这里只是示例一下,命名不是很明确,在实际应用中需要看情况而定。

好,我们编译一下,看看实际的效果。

再看看test1汇编程序

o(∩_∩)o...,正如自己所期望的那样,main和test1均定位到了所需的地址。下班了,明天再来更深入的介绍。

  如何定位整个文件,和keil创建工程文件中的group。

  继续昨天讲解的如何定位子程序的话题。当程序变大,子程序很多,我想把整个文件定位到一个固定地址怎么办呢?难不成每一个文件都在BL51 MISC中设置吗?那手脖子都累掉了,有那功夫还不如仔细研究研究keil的帮助文件,看看它里面是如何说明的。我仔细研究了一下keil的帮助文件,发现文件定位的方式有如下3种,且听我一一道来:

  方法1:这是最基本的方法,和昨天定位子程序的方法差不多,示例代码如下:

//test.c
#include <reg51.h>
unsigned ] _at_ 0x20;
unsigned ] _at_ 0x80;
unsigned ] _at_ 0x0000;
unsigned ] _at_ 0x0100;

extern void test1();
extern void test2();

void main()
{
    sysTemp_aa[] = 0x55;
    sysTemp_bb[] = 0x55;
    sysTemp_cc[] = 0x55;
    sysTemp_dd[] = 0x55;

    )
    {
        test1();
        test2();
    }
}

void test1()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

void test2()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

  现在我想把整个test.c的程序定位到0x1200开始的地方,还使用昨天的那个方法,点击“project”->”option for target ..."弹出如下窗口:

  在Misc controls中填入code(?PR?*?TEST (0x1200)),什么意思呢,就是test文件中所有的程序就定位到0x1200,呵呵,和昨天子程序定位相似吧,用一个*字符代替了所有的子程序名称。好看一下实际的结果。

  MAIN函数已经定位到了0x1200了,再看下面两个调用的函数test1和test2分别定位到了0x1218和0x121f,完全符合要求。如果想定位其他文件怎么办?假设现在有一个test2.c文件我想把test2定位到0x2200开始的地方,只要稍微修改一下 code(?PR?*?TEST (0x1200),?PR?*?TEST2(0x2200)), 各位看官是否注意到那个逗号',',用‘,’把各个文件隔开。实际效果请自行实践,我就不再 一一列举。

  方法2:使用USERCLASS。USERCLASS官方解释是The USERCLASS directive assigns a user defined class name to a compiler generated segment. By default, the C51 Compiler uses the basic class name for segment definitions.呵呵我的E文不是很好,只能看懂个大概,各位自己理解吧,想了解更多请参考keil的帮助文件。

  不在废话了,进入正题。首先定义USRCLASS,不过第一步要设置一下编译器,点击“project”->”option for target ..."弹出如下窗口:勾选LX51和AX51,其实AX51不是必须的,本帖只是讲C的定位,汇编程序不谈。

  选择好了以后选择“LX51 Locate",如图:

  在"User classes"中填写" CODE_TEST (C:0x1500 - C:0x2000)",如果你对程序的大小不确定那么只要写一个" CODE_TEST (C:0x1500 )"就可以,其他的交给KEIL自动分配。点击”确定“回到程序编辑区,在程序添加如下代码:

#pragma userclass (code = test)  //code的含义应该不用我说吧

  使用#pragma参数,在文件头部定位整个文件,刚刚填写的(CODE_TEST ...)到了程序中就需要写 code = test,为什么这么写,我也不知道keil的规定。总结了一下,比如说我再定一个userClass,名称为 CODE_TEST1(C:0x2000),那么到了程序中我就要这么写:

#pragma userclass (code = test1) 

  引申一下,同理可以使用userclass来限制一个文件使用的RAM区域,稍许修改一下那个CODE,怎么改各位参照KEIL帮助文档自己思考。实际修改后的源码:

//test.c
#include <reg51.h>
#pragma userclass (code = test)
unsigned ] _at_ 0x20;
unsigned ] _at_ 0x80;
unsigned ] _at_ 0x0000;
unsigned ] _at_ 0x0100;

extern void test1();
extern void test2();

void main()
{
    sysTemp_aa[] = 0x55;
    sysTemp_bb[] = 0x55;
    sysTemp_cc[] = 0x55;
    sysTemp_dd[] = 0x55;

    )
    {
        test1();
        test2();
    }
}

void test1()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

void test2()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

看看实际的效果:

main、test1和test2都已经定位到了1500开始的地方。

方法3:和方法2差不多,也是使用userclass不过方法稍许有点差别,同样定义一个userclass

回到程序编辑区,右键test.c选择”Option for file test.c",弹出如下窗口:

  在Misc Controls中填写:userclass (code = test),确定后回到程序编辑区。此时test.c文件的图标会有一个变化,如图:

编译源程序:

//test.c
#include <reg51.h>
unsigned ] _at_ 0x20;
unsigned ] _at_ 0x80;
unsigned ] _at_ 0x0000;
unsigned ] _at_ 0x0100;

extern void test1();
extern void test2();

void main()
{
    sysTemp_aa[] = 0x55;
    sysTemp_bb[] = 0x55;
    sysTemp_cc[] = 0x55;
    sysTemp_dd[] = 0x55;

    )
    {
        test1();
        test2();
    }
}

void test1()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

void test2()
{
    unsigned char i;

    ;i<;i++)
    {
        ;
    }
} 

调试一下,看看结果是否和方法二相同?结果我就不展示了。

篇幅太长,GROUP定位的下一篇再介绍吧!

GROUP定位的方法和文件定位的方法3类似,详情各位请等我整理上来。

KEIL 程序定位的更多相关文章

  1. keil程序在外部RAM中调试的问题总结(个人的一点经验总结)

    keil程序在内部RAM调试的基本步骤网上已经有非常多了,我就不再赘述,大家能够在网上搜到非常多. 可是有些时候内部RAM并不够用,这就须要将程序装入外部RAM中调试,而在这个过程中可能会出现各种各样 ...

  2. 微信小程序 - 定位功能

    (1) 查看微信小程序文档 大家可以从我截图中可以看到,API中的返回值有纬度和经度,所以我们接下来就是要用到纬度和经度逆地址解析出地址的一些信息. (2)注册腾讯地图开放平台 注册完之后选择WebS ...

  3. Keil 程序调试窗口

    上一讲中我们学习了几种常用的程序调试方法,这一讲中将介绍Keil提供各种窗口如输出窗口.观察窗口.存储器窗口.反汇编窗口.串行窗口等的用途,以及这些窗口的使用方法,并通过实例介绍这些窗口在调试中的使用 ...

  4. 谈谈在keil下的代码定位

    关于C语言,我们一般都知道对于RAM定位可以用关键字 _at_,但对于程序代码定位往往感到很迷惑, 其实keil中的程序代码定位功能极为强大 Menu: Options for Target 'Tar ...

  5. 如何通过Keil将程序正确的下载进flash中

    前面介绍了一些创建工程和调试的基本步骤,在这里准备介绍一下如何正确的将Keil程序在仿真调试中下载到flash.这里再次涉及到了debug的窗口.   工具/原料   Keil uVision 4/5 ...

  6. tiny4412 裸机程序 八、重定位到DRAM及LCD实验【转】

    本文转载自:http://blog.csdn.net/eshing/article/details/37407423 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   一 ...

  7. dll文件:关于MFC程序不能定位输入点

    问题:无法定位程序输入点到动态链接库上...... 过程:找完整个工程文件夹: APS为资源文件: resource.h为定义文件: 完全复制 除主文件以外的所有文件,程序可用: 在主程序框Cpp文件 ...

  8. keil教程

    KEIL C51标准C编译器为8051微控制器的软件开发提供了C语言环境,但是界面是英文的好多初学者看很多教程都是一头雾水,这个相对简单的教程.KEIL C51编译器的功能不断增强,使你可以更加贴近C ...

  9. 微信小程序的应用及信息整合,都放到这里了

    微信小程序终于开始公测了,这篇文章也终于可以发布了. 这篇文章可以说是微信小程序系列三部曲最后一篇.8 月份,小程序推出前,我写了<别开发 app 了>详细阐述了为什么创业应该放弃原生 a ...

随机推荐

  1. 利用Qt将网页保存为PDF

    灵社区文章链接http://www.ituring.com.cn/article/128717起因是在群里和大家讨论自己做一个图灵社区的客户端,说没有API不好搞,后来fairjm童鞋发了个java版 ...

  2. windows7环境下 硬盘安装ubuntu 12.04 server版

    之前一直用windows7环境下的虚拟机装的操作系统,但有时候在切换系统时老是死机,还是装一个硬盘版的ubuntu 12.04 server吧 先说一下本人的环境吧:windows 7 32位专业版+ ...

  3. hdu3849-By Recognizing These Guys, We Find Social Networks Useful:双连通分量

    By Recognizing These Guys, We Find Social Networks Useful Time Limit: 2000/1000 MS (Java/Others)     ...

  4. 用Scrapy写一个爬虫

    昨天用python谢了一个简单爬虫,抓取页面图片: 但实际用到的爬虫需要处理很多复杂的环境,也需要更加的智能,重复发明轮子的事情不能干, 再说python向来以爬虫作为其擅长的一个领域,想必有许多成熟 ...

  5. Swift字符串常用操作总结

    转自:http://www.jianshu.com/p/52e7580166ff 1.string转换为Int/Long/Float/Double/Bool等 var str1="100&q ...

  6. PyQt实现图片中心旋转

    # -*- coding: cp936 -*- from PyQt4 import QtCore, QtGui, Qt class RotatePage(QtGui.QFrame): def __in ...

  7. tomcat动态映射路径

    写了一个工具类,将上传文件功能保存文件的目录移到webapps目录外面,通过动态生成xml映射文件到tomcat\conf\Catalina\localhost目录下从而实现目录映射.可以被http直 ...

  8. PHP设计模式笔记四:适配器模式 -- Rango韩老师 http://www.imooc.com/learn/236

    适配器模式 1.适配器模式,可以将截然不同的函数接口封装成统一的API 2.实际应用举例,PHP的数据库操作有mysql.mysqli.pdo三种,可以用适配器模式统一成一致,类似的场景还有cache ...

  9. 跟我一起学extjs5(17--Grid金额字段单位MVVM方式的选择)

    跟我一起学extjs5(17--Grid金额字段单位MVVM方式的选择)         这一节来完毕Grid中的金额字段的金额单位的转换.转换旰使用MVVM特性,整体上和控制菜单的几种模式类似.首先 ...

  10. 分享几个社交类网站常用并且也是最好用的jquery类库

    官网都有详细的文档说明,大家自行百度谷歌哈! artZoom:常用于微博,支持图片放大缩小旋转 AutoComplete:自动完成 BackTop:当内容多时出现“返回顶部” CFUpload:批量上 ...