用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. Keil 3光标问题 以及汉字问题

    初次使用keil3,光标总是定位不准,修改十分麻烦,google后解决问题,修改tools.ini如下(蓝色为加入项): NAME="YGLenovo User", "a ...

  2. NSIS脚本调用C语言写的插件

    其实NSIS的官网已经提供了很多别人开发的插件了,今天需要用到GetVersion这个插件,这是不维护的插件了,不推荐用,但是由于现实中的问题,导致我不得不用这个插件. 所以就下载下来了. 下载下来之 ...

  3. NOI2012 骑行川藏

    http://www.lydsy.com/JudgeOnline/problem.php?id=2876 表示完全不会...... 还是跪拜大神吧 http://www.cnblogs.com/Ger ...

  4. linux下,FTP服务相关

    虚拟机上安装完CentOS 6.5后,使用FTP工具(FlashFXP)来上传文件到虚拟机的linux,结果发现连接不上.现在解决了,解决方法总结一下: 1.先检查有没有安装ftp.好像包括两个部分, ...

  5. usaco6.1-Cow XOR:trie树

    Cow XOR Adrian Vladu -- 2005 Farmer John is stuck with another problem while feeding his cows. All o ...

  6. Decorator学习笔记

    初学者,自己的理解,请各位前辈不吝指正! Decorator,装饰模式,设计模式之一,谈谈我的理解,装饰这个词在我概念中就是给某个事物加上一些美丽的外表,把它变得更加完美.但是装饰是可以随时改变的,可 ...

  7. 【转】打包AAC码流到FLV文件

    AAC编码后数据打包到FLV很简单.1. FLV音频Tag格式                              字节位置    意义0x08,                         ...

  8. USB Video Class及其实现

    1 Video Class 基础概念Usb协议中,除了通用的软硬件电气接口规范等,还包含了各种各样的Class协议,用来为不同的功能定义各自的标准接口和具体的总线上的数据交互格式和内容.这些Class ...

  9. java java.uitl.Random产生随机数

    通过使用java.uitl.Random产生一个1-10内的随机数.例: Random random = new Random(); int i = Math.abs(random.nextInt() ...

  10. pyqt例子下拉列表

    #!/usr/bin/env python # -*- coding: utf-8 -*- from PyQt4.QtCore import Qt from PyQt4.QtGui import QC ...