keil中的变量和常量定位问题.doc_第1页
keil中的变量和常量定位问题.doc_第2页
keil中的变量和常量定位问题.doc_第3页
keil中的变量和常量定位问题.doc_第4页
keil中的变量和常量定位问题.doc_第5页
已阅读5页,还剩120页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

/*keil中的变量和常量定位问题变量定位:char tab110 _at_ 0x200; 赋值:在函数中赋值,如tab10=0x01; 常量定位及初始化: 新建一个TABLE.C, 写入 char code table= 初始值; KEIL定位:选择 option-BL51 Locate, 在CODE:栏中写入如: ?CO?TABLE(0x7000) 这样,table表就定位到了0x7000开始的程序段。 /*如何在 KEIL C51(v6.21) 中调用汇编函数的一个示例 ycong_kuang有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者通过一个简单例子对这个过程进行描述,希望能对初学者有所帮助。几年来,在这个论坛里笔者得到很多热心人指导,因此也希望藉此尽一点绵薄之力。在这个例子里,阐述了编写c51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是一个整型变量。例中,先用c51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所要的汇编函数。该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。step1. 按写普通c51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。相关文件如下:/main.c文件#include #define uchar unsigned char#define uint unsigned intextern uint AFUNC(uchar v_achr,bit v_bflag);void main()bit BFLAG;uchar mav_chr;uint mvintrslt;mav_chr=0xd4; BFLAG=1;mvintrslt=AFUNC(mav_chr,BFLAG);/CFUNC.c文件#define uchar unsigned char#define uint unsigned intuint AFUNC(uchar v_achr,bit v_bflag)uchar tmp_vchr;uint tp_vint;tmp_vchr=v_achr;tp_vint=(uint)v_bflag;return tmp_vchr+(tp_vint8);step2. 在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for .”,点击右边的“Generate Assembler SRCFile”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;step3. 根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中,该文件必须作为工程的最后文件;step4. build这个工程后将会产生一个CFUNC.SRC的文件,将这个文件改名为CFUNC.A51(也可以通过编译选项直接产生CFUNC.A51文件),然后在工程里去掉库文件(如C51S.Lib)和CFUNC.c,而将CFUNC.A51添加到工程里。/CFUNC.SRC文件如下.CFUNC.SRC generated from: CFUNC.cNAME CFUNC?PR?_AFUNC?CFUNC SEGMENT CODE?BI?_AFUNC?CFUNC SEGMENT BIT OVERLAYABLEPUBLIC ?_AFUNC?BITPUBLIC _AFUNCRSEG ?BI?_AFUNC?CFUNC?_AFUNC?BIT:v_bflag?041: DBIT 1; #define uchar unsigned char; #define uint unsigned int; uint AFUNC(uchar v_achr,bit v_bflag)RSEG ?PR?_AFUNC?CFUNC_AFUNC:USING 0; SOURCE LINE # 5;- Variable v_achr?040 assigned to Register R7 -; ; SOURCE LINE # 6; uchar tmp_vchr; uint tp_vint; tmp_vchr=v_achr; SOURCE LINE # 10;- Variable tmp_vchr?042 assigned to Register R5 -MOV R5,AR7; tp_vint=(uint)v_bflag; SOURCE LINE # 11MOV C,v_bflag?041CLR ARLC A;- Variable tp_vint?043 assigned to Register R6/R7 -; return tmp_vchr+(tp_vint8); SOURCE LINE # 12MOV R6,AMOV R4,#00HCLR AADD A,R5MOV R7,AMOV A,R4ADDC A,R6MOV R6,A; ; SOURCE LINE # 13?C0001:RET; END OF _AFUNCENDstep5. 检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。参考文献:1.徐爱钧,彭秀华。单片机高级语言C51windows环境编程与应用,电子工业出版社.keil中汇编函数调用c51函数 ycong_kuang第一步在工程里多了一个被汇编调用的c51的函数文件(c51func.c),至于汇编函数还是先用c51编写出主体(a51func.c),这样汇编程序接口和段都交给编译器处理,你只管在编译成汇编代码后按你的要求改写汇编代码就行了。例程如下:/main.c#include #define uchar unsigned char#define uint unsigned intextern uint AFUNC(uchar v_achr,bit v_bflag);void main()bit BFLAG;uchar mav_chr;uint mvintrslt;mav_chr=0xd4; BFLAG=1;mvintrslt=AFUNC(mav_chr,BFLAG);/a51FUNC.c#define uchar unsigned char#define uint unsigned intextern uint CFUNC(uint);uint AFUNC(uchar v_achr,bit v_bflag) /c51写的汇编函数,最终要变成汇编代码uchar tmp_vchr;uint tp_vint;tmp_vchr=v_achr;tp_vint=(uint)v_bflag;return CFUNC(tp_vint); /这里调用一个c51函数/c51FUNC.c#define uchar unsigned char#define uint unsigned intuint CFUNC(uint v_int) /被汇编函数调用c51函数return v_int2;第二步是按89852帖子的step2,3,4把用c51写的(汇编)函数变成a51文件(今天我试了一下step3可以不要)例程编译结果如下:; .a51func.SRC generated from: a51func.cNAME A51FUNC?PR?_AFUNC?A51FUNC SEGMENT CODE?DT?_AFUNC?A51FUNC SEGMENT DATA OVERLAYABLE?BI?_AFUNC?A51FUNC SEGMENT BIT OVERLAYABLEEXTRN CODE (_CFUNC)PUBLIC ?_AFUNC?BITPUBLIC _AFUNCRSEG ?DT?_AFUNC?A51FUNC?_AFUNC?BYTE:tmp_vchr?042: DS 1RSEG ?BI?_AFUNC?A51FUNC?_AFUNC?BIT:v_bflag?041: DBIT 1; /a51FUNC.c; #define uchar unsigned char; #define uint unsigned int; extern uint CFUNC(uint); uint AFUNC(uchar v_achr,bit v_bflag)RSEG ?PR?_AFUNC?A51FUNC_AFUNC: ;c51所写的函数产生的汇编代码从这里开始USING 0; SOURCE LINE # 8;- Variable v_achr?040 assigned to Register R7 -; ; SOURCE LINE # 9; uchar tmp_vchr; uint tp_vint; tmp_vchr=v_achr; SOURCE LINE # 13MOV tmp_vchr?042,R7; tp_vint=(uint)v_bflag; SOURCE LINE # 14MOV C,v_bflag?041CLR AMOV R6,ARLC AMOV R7,A;- Variable tp_vint?043 assigned to Register R6/R7 -; 这里说明R6,R7内容就是tp_vint; return CFUNC(tp_vint); SOURCE LINE # 16LCALL _CFUNC ;这里调用了用c51写的函数; ; SOURCE LINE # 17?C0001:RET; END OF _AFUNCEND这个文件就是你的汇编函数所在文件,把函数里面的汇编代码修改成你所需的汇编函数就ok了。建议参考 徐爱钧,彭秀华所写的单片机高级语言C51windows环境编程与应用或马忠梅所写的单片机的c语言应用程序设计有关混合语言编程有关章节./* 关于在 KEIL C51 中直接嵌入汇编。 Youth*有时在C51程序中需要嵌入一些汇编代码,这时当然可以用通常的作法:按照 C51 与汇编的接口写一个汇编函数,然后在 C51 程序中调用该函数。(此种方法可在论坛里搜索,以前有很多帖子讲到,不再重复)下面介绍直接嵌入汇编代码的方法:1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:#pragma ASM; Assembler Code Here#pragma ENDASM2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for .”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中, 该文件必须作为工程的最后文件;4、编译,即可生成目标代码。 在单片机的开发应用中,已逐渐开始引入高级语言,C语言就是其中的一种。对用惯了汇编的人来说,总觉得高级语言可控性不好,不如汇编那样随心所欲。但是只要我们掌握了一定的C语言知识,有些东西还是容易做出来的,以下是笔者实际工作中遇到的几个问题,希望对初学C51者有所帮助。一、C51热启动代码的编制对于工业控制计算机,往往设有有看门狗电路,当看门狗动作,使计算机复位,这就是热启动。热启动时,一般不允许从头开始,这将导致现有的已测量到或计算到的值复位,导致系统工作异常。因而在程序必须判断是热启动还是冷启动,常用的方法是:确定某内存单位为标志位(如0x7f位和0x7e位),启动时首先读该内存单元的内容,如果它等于一个特定的值(例如两个内存单元的都是0xaa),就认为是热启动,否则就是冷启动,程序执行初始化部份,并将0xaa赋与这两个内存单元。根据以上的设计思路,编程时,设置一个指针,让其指向特定的内存单元如0x7f,然后在程序中判断,程序如下:void main() char data *HotPoint=(char *)0x7f;if(*HotPoint=0xaa)&(*(-HotPoint)=0xaa) /*热启动的处理 */ else HotPoint=0x7e; /*冷启动的处进*HotPoint=0xaa;*(+HotPoint)=0xaa; /*正常工作代码*/然而实际调试中发现,无论是热启动还是冷启动,开机后所有内存单元的值都被复位为0,当然也实现不了热启动的要求。这是为什么呢?原来,用C语言编程时,开机时执行的代码并非是从main()函数的第一句语句开始的,在main()函数的第一句语句执行前要先执行一段起始代码。正是这段代码执行了清零的工作。C编译程序提供了这段起始代码的源程序,名为CSTARTUP.A51,打开这个文件,可以看到如下代码:.IDATALEN EQU 80H ; the length of IDATA memory in bytes. .STARTUP1:IF IDATALEN 0MOV R0,#IDATALEN - 1CLR AIDATALOOP: MOV R0,ADJNZ R0,IDATALOOPENDIF.可见,在执行到判断是否热启动的代码之前,起始代码已将所有内存单元清零。如何解决这个问题呢?好在启动代码是可以更改的,方法是:修改startup.a51源文件,然后用编译程序所附带的a51.exe程序对 startup.a51编译,得到startup.obj文件,然后用这段代码代替原来的起始代码。具体步骤是(设C源程序名为HOTSTART.C):修改startup.a51源文件(这个文件在C51LIB目录下)。 执行如下命令: A51 startup.a51 得到startup.obj文件。将此文件拷入HOTSTART.C所在目录。将编好的C源程序用C51.EXE编译好,得到目标文件HOTSTART.OBJ。 用 L51 HOTSTART, STARTUP.OBJ 命令连接,得到绝对目标文件HOTSTART。 用 OHS51 HOTSTART 得到HOTSTART.HEX文件,即可。 对于startup.a51的修改,根据自已的需要进行,如将IDATALEN EQU 80H中的80H改为70H,就可以使6F到7F的16字节内存不被清零。二、直接调用EPROM中已固化的程序笔者用的仿真机,由6位数码管显示,在内存DE00H处放显示子程序,只要将要显示的数放入显示缓冲区,然后调用这个子程序就可以使用了,汇编指令为:LCALL 0DEOOH在用C语言编程时,如何实现这一功能呢?C语言中有指向函数的指针这一概念,可以利用这种指针来实现用函数指针调用函数。指向函数的指针变量的定义格式为:类型标识符 (*指针变量名)();在定义好指针后就可以给指针变量赋值,使其指向某个函数的开始存地址,然后用(*指针变量名)()即可调用这个函数。如下例:void main(void)void (*DispBuffer)(); /*定义指向函数指针*/DispBuffer=0xde00; /*赋值*/for(;) Key();DispBuffer();三、将浮点数转化为字符数组笔者在编制应用程序时有这样的要求:将运算的结果(浮点数)存入EEPROM中。我们知道,浮点数在C语言中是以IEEE格式存储的,一个浮点数占用四个字节,例如浮点数34.526存为(160,26,10,66)这四个数。要将一个浮点数存入EEPROM,实际上就是要存这四个数。那么如何在程序中得到一个浮点数的组成数呢?浮点数在存储时,是存储连续的字节中的,只要设法找到存储位置,就可以得到这些数了。可以定义一个void的指针,将此指针指向需要存储的浮点数,然后将此指针强制转化为char型,这样,利用指针就可以得到组成该浮点数的各个字节的值了。具体程序如下:#define uchar unsigned char#define uint unsigned intvoid FtoC(void) float a;uchar i,*pxuchar x4; /*定义字符数组,准备存储浮点数的四个字节*、void *pf;px=x; /*px指针指向数组x*/pf=&a; /*void 型指针指向浮点数首地址*/a=34.526;for(i=0;i4;i+) *(px+i)=*(char *)pf+i); /*强制void 型指针转成char型,因为*/ /*void型指针不能运算*/如果已将数存入EEPROM,要将其取出合并,方法也是一样,可参考下面的程序。#define uchar unsigned char#define uint unsigned intvoid CtoF(void) float a;uchar i,*pxuchar x4=56,180,150,73;void *pf;px=x;pf=&a;for(i=0;i”出现),则当中断申请时,显示中断源信息。比如当中断发生时会显示:“interrupt Timer 0 occured”等A/D converter:显示A/D转换器状态无时,则提示“无”。Serial:串口信息显示,包括串口模式、波特产等Other:其它器件,如为8031则显示“ 无”3. (3) 单步或“Go”执行“F8”单步执行,“F5”全速执行到断点。或选主菜单中Trace单步执行CPU中的Go全速执行。4. (4) 存储器寄存器及变量访问外部存储器管理MAP菜单:设置(set)、取消(reset)、显示(Display)处理可用存储空间。修改Code代码:ASM命令存储器显示命令:D 类别为(X、D、I、B、C)修改存储器命令:E 有以下几种命令EB、EC、EI、EL、EF、EP复杂数据类型显示:Object命令;用以显示结构或数组的内容。欲使此命令有效,C51编译器必须有DB及OBJECTEXTEND两条。反汇编命令:U5. (5) “Watch”表达式之值在View菜单的“Watch”一栏中有四项:其中包括定义Watch Point(Define)、删除Watch Point(remove,kill all),及自动更新选项。也可用WS、WK等命令代替,下面具体看“表达式”类型:dScope51一次最多可设16个WtchPoint表达式,显示于Watch Window之中,表达式可以是简单变量,也可是复杂数据类型如结构、数组和指向结构的指针等,例如:WS *ptimeWS ptimehourWS some_recordo,analog等等6. (6) 关于.IOF文件启动DS51后必须装入.IOF文件才能使CPU及Peripheral各项起作用,这个函数的使用是依据8051系列CPU的不同特点,装入8051各CPU硬件设备模拟驱动文件,比如8031CPU就必须load DS51目录下的8051.IOF。2. 2. dScope for WindowsdScope for windows具有dScope for dos的全部功能,此外,它还具有以下明显的优点:(1) 标准的Windows界面,操作更容易更简单; (2) 常用操作多用对话框,而非Dos的行命令方式;(3) 窗口资源更加丰富:存储器窗口、覆盖率分析、运行状态分析窗口,加强了调试功能;因为dScope for Windows功能强大,具体操作在第八章详细介绍。3. 第三节 Monitor51及其使用1. 1. Monitor51对硬件的要求(1) 硬件系统为51系列CPU;(2) 带5K外部程序存储器(从O地址开始),存放Monitor51程序;(3) 256Bytes的外部数据存储器以及5K的跟踪缓冲区,此外,外部数据存储器必须足够容纳所有应用程序代码及数据,且所有外部数据存储器必须为冯诺伊曼存储器,即能一致访问XDATA与Code空间。(4) 一个定时器作为波特率发生器供串口使用;(5) 6 Bytes的空余堆栈。2. 2. Mon51的使用Mon51的使用途径有三种方式:(1) Dos行命令方式即先用install对MON51进行配置,然后用MON51进入Monitor状态,启用各种命令对Monitor51进行调试。(2) tScope51方式启动tScope51装入TS51目录下的MON51.IOT驱动文件,与目标板通信。(3) dScope51 for Windows方式在选CPU驱动文件时,选“MON51.dll”,则检查目标板并进入MON51状态。3. 3. MON51的配置(1) MON51 for Dos的配置运行install文件(在MON51目录下),不同的参数可以配置不同的硬件环境。INSTALL Serialtype xdstastartcodestartbankPROMCHECK,具体说明见MON51帮助文件或使用手册。(2) MON51 for Windows的配置在启用MON51.dll时,会使得系统自动检查目标板连接,如配置不对,则弹出“Configuration”对话框,设置PC串口,波特率等,完毕单击“apply”有效。4. 4. 串口连接图:收发交叉互连,RTS、CTS直连,DSR、DTR直连,具体引脚排列参考串口资料。5. 5. MON51命令及使用详细的MON51命令可参阅帮助。4. 第四节 集成开发环境(IDE)的使用1. 1. Ishell for Dos的使用进入Ishell之后看到两个窗口:一个是文件窗口,一个是Dos命令行窗口,窗口上方是下拉式的命令菜单,其中的Files控制文件窗口的显隐。使用Ishell,第一步就是配置系统,即要学习两个文件的修改与创建:1. (1) Ishell.CFG文件每一个project都有一个Ishell.CFG,其中存放有“Option菜单和Setup菜单下的部分信息;Bell enabled、Monochrome enabled、Editor Selected、CRT Lines、target enviroment、name of user edit、Automatic load for configuration enabled、file window enabled、file specification for file window、translate command line controls、project name等。对每个project都必须设置以上信息,然后存盘“setup”的的“save”,这样才可正式开始下面工作。2. (2) IShell.col文件对IDE颜色设置,如不改动,可以缺省为主。3. (3) CDF文件该文件位于BIN目录下,每一文件定义一组外部函数工具包,即定义外部环境如8051.CDF,USER.CDF等,开发者可修改CDF文件,供自己使用,至于CDF文件内容可查看一下8051.CDF即可知道。注意.CDF文件是Ishell系统的核心所在,不同的CDF文件可使本IDE适用于不同的编译、连接系统,即本IDE并不仅适于C51。下面谈一谈Automake工具:C51的Automake是一个project管理器,在8051工具包中以OBJECT文件形式保留了一个project的信息,AutoMake用这些信息来进行project管理,一旦手工建立一个project,Automake可生成一个新的OBJECT,AutoMake利用此文件来编译那些修改过的文件。Automake支持C51、A51、L51/BL51、C166、A166、L166等编译连接器。点中主菜单中的Automake即运行本工具。Ishell for Dos使用比较繁琐,推荐使用uVision for windows。2. 2. uVision for windows的使用uVision是一个标准的windows应用程序,其编译功能、文件处理功能、project处理功能、窗口功能以及工具引用功能(如A51、C51、PL/M41、BL51 dScope等)等都较Ishell for Dos要强得多。uVision采用BL51作连接器,因为BL51兼容L51,所以一切能在Dos下工作的project都可以到uVision中进行连接调试。uVision采用dScope for windows作调试器,该调试器支持MON51及系统模拟两种方式,功能较for DOS要强大好用,调试功能强大。注意:(1) Option菜单下的各项要会使用,其中A51、C51、PL/M51、BL51定义各文件所使用的编译、连接控制指令,dScope定义一个dScope初始化文件。Make则是定义一个make文件。(2) 进入调试是在RUN菜单下运行dScope。(3) project中包括新建、打开、修改、更新、编译、连接等poject处理,具体使用可参考后面的例子。3. 第三章 Keil C51 vs 标准C深入理解并应用C51对标准ANSIC的扩展是学习C51的关键之一。因为大多数扩展功能都是直接针对8051系列CPU硬件的。大致有以下8类:l 8051存储类型及存储区域l 存储模式l 存储器类型声明l 变量类型声明l 位变量与位寻址l 特殊功能寄存器(SFR)l C51指针l 函数属性具体说明如下(8031为缺省CPU)。1. 第一节 Keil C51扩展关键字C51 V4.0版本有以下扩展关键字(共19个):_at_idata sfr16 alien interrupt smallbdata large _task_ Code bit pdatausing reentrant xdata compact sbit data sfr2. 第二节 内存区域(Memory Areas):1. 1. Pragram Area:由Code说明可有多达64kBytes的程序存储器2. 2. Internal Data Memory:内部数据存储器可用以下关键字说明:data:直接寻址区,为内部RAM的低128字节 00H7FHidata:间接寻址区,包括整个内部RAM区 00HFFHbdata:可位寻址区, 20H2FH3. 3. External Data Memory外部RAM视使用情况可由以下关键字标识:xdata:可指定多达64KB的外部直接寻址区,地址范围0000H0FFFFHpdata:能访问1页(25bBytes)的外部RAM,主要用于紧凑模式(Compact Model)。4. 4. Speciac Function Register Memory8051提供128Bytes的SFR寻址区,这区域可位寻址、字节寻址或字寻址,用以控制定时器、计数器、串口、I/O及其它部件,可由以下几种关键字说明:sfr:字节寻址 比如 sfr P0=0x80;为PO口地址为80H,“”后HFFH之间的常数。sfr16:字寻址,如sfr16 T2=0xcc;指定Timer2口地址T2L=0xcc T2H=0xCDsbit:位寻址,如sbit EA=0xAF;指定第0xAF位为EA,即中断允许还可以有如下定义方法:sbit 0V=PSW2;(定义0V为PSW的第2位)sbit 0V0XDO2;(同上)或bit 0V-0xD2(同上)。3. 第三节 存储模式存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域,共三种:1. 1. Small模式所有缺省变量参数均装入内部RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。2. 2. Compact模式所有缺省变量均位于外部RAM区的一页(256Bytes),具体哪一页可由P2口指定,在STARTUP.A51文件中说明,也可用pdata指定,优点是空间较Small为宽裕速度较Small慢,较large要快,是一种中间状态。3. 3. large模式所有缺省变量

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论