用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下实现对Linux Shell调用的几种方法

    使用QProcess QThread ============================================ #include <QProcess>int main(){ ...

  2. C++11 in Qt5

    本文转载自:http://woboq.com/blog/cpp11-in-qt5.html   C++11 in Qt5 Posted by Olivier Goffart on 11 June 20 ...

  3. (Data structure)Implement Trie && Add and Search Word

    Implement Trie (Prefix Tree) Implement a trie with insert, search, and startsWith methods. Note:You ...

  4. npm 和 bower的区别

    npm和bower在功能上有一定的重合,但不是互斥关系,可以在项目中同时运用.区别在于npm在设计之初就采用了的是嵌套的依赖关系树.一个普通的前端包的依赖树比较长,npm 会将开发环境一起下载下来,  ...

  5. poj 2010 Moo University - Financial Aid(优先队列(最小堆)+ 贪心 + 枚举)

    Description Bessie noted that although humans have many universities they can attend, cows have none ...

  6. mysql插入数据时,中文乱码

    MySQL 插入数据时,中文乱码问题的解决(转) 当向 MySQL 数据库插入一条带有中文的数据形如 insert into employee values(null,'张三','female','1 ...

  7. javascript实现的有缩略图功能的幻灯片切换效果

    不久前写了一个简单的图片效果,没想到那么快就要用到项目中,所以功能方面要丰富一下: 主要改进: 1# 用圆点代替之前简单的页数显示,并且点击圆点可以显示对应图片: 2# 点击圆点,显示对应图片的缩略图 ...

  8. Python一日一练05----怒刷点击量

    功能 自己主动获取CSDN文章列表,并对每篇文章添加点击量. 源代码 import urllib.request import re import time import random from bs ...

  9. Linux下找不到动态链接库

    1.生成静态库 生成静态库使用ar工具,其实ar是archive的意思 $ar cqs libhello.a hello.o 2.生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号: ...

  10. with admin option 与with grant option

    在赋予user 权限或者role 时,常常会用到with admin option 和with grant option,而在使用中,可能会很容易出现混淆的情况,现把他们的相同点和不同点总结如下:相同 ...