原创 C51

2009-2-11 16:50 3238 4 4 分类: MCU/ 嵌入式
1.第一种错误信息

***WARNING L15:  MULTIPLE CALL TO SEGMENT
SEGMENT:   ?PR?_WRITE_GMVLX1_REG?D_GMVLX1
CALLER1:   ?PR?VSYNC_INTERRUPT?MAIN
CALLER2:   ?C_C51STARTUP

***WARNING L15:  MULTIPLE CALL TO SEGMENT
SEGMENT:   ?PR?_SPI_SEND_WORD?D_SPI
CALLER1:   ?PR?VSYNC_INTERRUPT?MAIN
CALLER2:   ?C_C51STARTUP

***WARNING L15:  MULTIPLE CALL TO SEGMENT
SEGMENT:   ?PR?SPI_RECEIVE_WORD?D_SPI
CALLER1:   ?PR?VSYNC_INTERRUPT?MAIN
CALLER2:   ?C_C51STARTUP


    该警告表示连接器发现有一个函数可能会被主函数和一个中断服务程序(或者调用中断服务程序的函数)同时调用,
或者同时被多个中断服务程序调用。
    出现这种问题的原因之一是这个函数是不可重入性函数,当该函数运行时它可能会被一个中断打断,从而使得结果发生变化
并可能会引起一些变量形式的冲突(即引起函数内一些数据的丢失,可重入性函数在任何时候都可以被ISR打断,一段时间后又可以
运行,但是相应数据不会丢失)。
    原因之二是用于局部变量和变量(暂且这样翻译,arguments,[自变量,变元一数值,用于确定程序或子程序的值])的内存区被其他函数的内存区所覆盖,如果该函数被中断,则它的内存区就会
被使用,这将导致其他函数的内存冲突。
    例如,第一个警告中函数WRITE_GMVLX1_REG 在D_GMVLX1.C 或者D_GMVLX1.A51被定义,它被一个中断服务程序或者一个调用了中断
服务程序的函数调用了,调用它的函数是VSYNC_INTERRUPT,在MAIN.C中。
解决方法:
    如果你确定两个函数决不会在同一时间执行(该函数被主程序调用并且中断被禁止),并且该函数不占用内存(假设只使用寄存器),
则你可以完全忽略这种警告。
    如果该函数占用了内存,则应该使用连接器(linker)OVERLAY指令将函数从覆盖分析(overlay analysis)中除去,例如:
OVERLAY (?PR?_WRITE_GMVLX1_REG?D_GMVLX1 ! *)
   上面的指令防止了该函数使用的内存区被其他函数覆盖。如果该函数中调用了其他函数,而这些被调用在程序中其他地方也被调用,
你可能会需要也将这些函数排除在覆盖分析(overlay analysis)之外。这种OVERLAY指令能使编译器除去上述警告信息。
   如果函数可以在其执行时被调用,则情况会变得更复杂一些。这时可以采用以下几种方法:
1.主程序调用该函数时禁止中断,可以在该函数被调用时用#pragma disable语句来实现禁止中断的目的。必须使用OVERLAY指令将该函数
从覆盖分析中除去。
2.复制两份该函数的代码,一份到主程序中,另一份复制到中断服务程序中。
3.将该函数设为重入型。例如:
void myfunc(void) reentrant {
 ...
}

      这种设置将会产生一个可重入堆栈,该堆栈被被用于存储函数值和局部变量,用这种方法时重入堆栈必须在STARTUP.A51文件中配置。
这种方法消耗更多的RAM并会降低重入函数的执行速度。

2.第二种错误信息

*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
   
SEGMENT: ?PR?_COMPARE?TESTLCD

       说明:程序中有些函数(或片段)以前(调试过程中)从未被调用过,或者根本没有调用它的语句。
       这条警告信息前应该还有一条信息指示出是哪个函数导致了这一问题。只要做点简单的调整就可以。不理它也没什么大不了的。
       解决方法:去掉COMPARE()函数或利用条件编译#if …..#endif,可保留该函数并不编译。

 




 



keil 使用笔记(转帖)

 


在Memory窗口上输入address_type:address才能看到正确地址的变量
debug~perfermance analyzer加入要察看的模块名称,然后view~perfermance analyzer
window 可以察看各个模块运行时间
①Display address_type:address
B:Bit address
C:Code Memory
Bx:Code Bank
D D:80H 命令可以查看特殊寄存器 data
D I:0 命令可以查看内部RAM数据iData;
D X:0 命令可以查看外部RAM数据xData;


②R1<enter> //显示R1 register
~R1<enter> //显示变量R1
R1 = R7<enter> //对寄存器Rx操作
R1 = --R7<enter>
R1 = 0x20<enter>


③main<enter> //显示main()的开始地址
d main<enter> //显示main()的代码


④向RAM.ROM中写数据
Enter data_type address_type:address expr,expr....
data_type:int char double float long


E char data:0x20 1,2,3,4 //向data区0x20开始的地址写1,2,3,4



变量放在RAM的30H,要把定义放在main前面!另外特别注意,内部RAM通常供C程序存放中
间变量等,所以一定要看看编译后的程序中是否存在存储单元冲突的情况,比如如果程序中
使用了别的寄存器组的话,08-1FH单元就不能用了
unsigned long data i _at_ 0x30



如何用Keil的uVision2仿真外部中断?
方法一:调试状态下,打开PeriPherals->I/O PORTS->P3 用鼠标将相应的端口变高或低即
可产生中断


方法二:在命令窗口中输入DEFINE BUTTON "INTERUPT","P3=0XFE"
然后打开TOOLBOX,即可以看见按钮INTERUPT,按下按钮即可
Define Button "button_label","command"<enter>
注意:Define Button "show R5 Register","printf(\"R5=%04xh\\n\")"
kill button x<enter> //x为按钮在toolbox上位置


方法三:用调试函数,可参考uv2\hlp\gs51.pdf第五和第六章
信号函数写在一个ini文件中,调试主程序时用debug-Function Editor调入,
会有一个框出现,可在里面修改,然后complie。也可以在debug状态下include
<file.ini><enter>调入。file.ini里面的内容是debug command和function definitions,
可以用kill命令结束。


functiong definition可以是以下几种:
㈠系统预定功能 printf getin等
㈡用户定义功能 即用户自己写的函数,如FUNC void MyStatus(void)
㈢信号函数。用户程序运行时后台运行,模拟外部的信号输入,可同时有64个。


dir bfunc<enter> //察看所有预定功能predefined
dir ufunc //察看所有用户功能user
dir singal //察看所有信号函数singal
dir func //看所有的



㈠系统预定功能 printf getin等
void exec (“command_string”) //在用户和信号函数里面调用keil的调试命令
如:exec (“BS timer0”)



double getdbl(“prompt_string”) //跳出一窗口提示输入数,返回,如无则返回0
int getint(“prompt_string”)
long getlong(“prompt_string”)
如:age = getint(“Enter your age”)


void memset(start_address,ulong length,uchar value) //用指定的数填充一段内存
如memset(0x2000,0x1000,’a’)


void printf(“format_string”,value) //从serial窗口输

如:printf(“%s for %d”,uvision2,51) //输出uvision2 for 51



int rand(int seed) //产
生随机数,seed为0时还原



void twatch(long states) //等待n个clock,只能被
singal函数调用
void swatch(float seconds) //如swatch(0.5)
void rwatch(address) //rwatch(X:0x1234) 一直等待直到X:0x1234被读
void wwatch(address) //一直等待直到X:0x1234被写


如 twatch (200000); // 200000 Cycles Time-Break
twatch(CLOCK); //wait for 1 seconds



_wbyte(address,uchar value) //向指定的内存写数据 _wbyte
(0x2000,0x55)
_wword(address,uint value)
_wdword(address,ulong value)
_wfloat(address,float value)
_wdouble(address,double value)
㈡用户定义功能 即用户自己写的函数,不能调用singal函数和twatch(),可用KILL
FUNC function_name杀之
FUNC return_type function_name(parameter_list)
{
statments
}


/*-------------------------------------------*/
/* Function MyRegs() shows Registers R0...R3 */
/*-------------------------------------------*/
FUNC void MyRegs (void)
{
printf ("---------- MyRegs() ----------\n");
printf (" R0 R1 R2 R3\n");
printf (" %02X %02X %02X %02X\n",R0,R1,R2,R3);
printf ("------------------------------\n");
}



㈢信号函数。用户程序运行时后台运行,模拟外部的信号输入,可同时有64个。
当调用twatch()时进入idle状态,一个signal函数返回值必须是void,最多8个参数,能够
调用predefine和user函数,但不能调用其它信号函数,能被uesr函数调用,至少调用
twatch一次,用ctrl+c终止它。
Signal state<cr> //察看当前活动的信号函数
Signal kill signal_name<cr> //杀掉活动的


Singal void func_name(para_list)
{
statements
}
例子1:singal void stuffsin(void)
{
while(1)
{
sin = ‘A’;
twatch(100000);//每隔100000个cpu states就输出
个’A’
}


}


例子2:
signal void check_p20(void) //一个没有调用twatch()的信
号函数用法
{
if(PORT2 & 1)
{
printf("Led is on\n");
}
else
{
printf("led is off\n");
}


}


然后设置断点:
bs write PORT2,1,"check_p20()"<enter>如果有写p2的动作则会执行这个
signal函数。



这里注意write和read
例如:unsinged int data value;
value = P1;
P2 = value;


此时bs read PORT1,1,"PORT1 = getint(\"input value\")"
bs write PORT3,1,"printf(\"port3 value=%x\\n\",port3)"
执行后会跳出窗口让你输入p1的值,然后输出p3的值。



如何仿真串口输入:ASSIGN WIN2 <S1IN>S1OUT(如果你在DeviceDatabase选的单片机类型
有第二个串口,否则WIN2也都是NUL,如果选择的单片机类型没有第二串口,是没有S1IN和
S1OUT这两个虚拟寄存器的,你可以通过dir vtreg命令查看当前的定义了的虚拟寄存器值)


peripherals->serial channel中令SBUF = 0x55是指发送即时数给发送寄存
器,若要从串行口读入数据,在命令行中输入sin=你的数据即可向串行口送入数据.窗口中
SBUF中的数据是发送寄存器中的数据,不是接收寄存器中的数据!


单片机串口指向到了PC机的串口上,这样就可以在pc机的环境下模拟单片机对外部设备的操
作了,此时把pc串口和外设连接,此时pc的串口 = 你单片机的串口。注意:模拟单片机运行
时,单片机串口速率是由MODE命令来指定的,和C程序中对SMOD,TH1的值无关(但是在烧写到
单片机上时,smod,th1要设定好)。Serial#1上面的是单片机发出的数据。
Command_line上输入sin=value,value是模拟外设传过来的数据。s


printf是从串口输出的(当然也可以改写putchar函数),可以用根串口线链接计算机的
COM1,COM2,这是针对有两个串口接口的计算机,然后在DEBUG模式的命令行加下两句:
MODE COM1 19200,0,8,1
ASSIGN COM1 <SIN>SOUT
然后打开一个串口调试的软件,对应串口COM2,19200,0.就可以看到结果了


mode com2 9600,0,8,1<enter> //无校验位,8位数据位,1个停止位
assign com2 <sin> sout<enter>
stime = 0<enter>


Assign win<sin>sout //意思就是uVision 把模拟的单片机串口对应到Serial window
和#2上(在serial window里输入字符,就是模拟对单片机串口输入数据)







第八章 dScope for Windows使用详解(转帖)


第一节 概述


1. 主窗口(Mainframe Window)


可设置其它各种调试窗口,设置断点、观察点,修改地址空间,加载文件等等;


2. 调试窗口(DEBUG  Window)


支持用户程序的各种显示方式,可连续运行,单步运行用户程序,并可在线 汇编;


3. 命令窗口(Command Window)


支持命令行的输入;


4. 观察窗口(Watch Window)


可设置所要观察的变量、表达式等;


5. 寄存器窗口(Registe Window)


显示内部寄存器的内容,程序运行次数等;


6. 串口窗口(Serical Windows)


显示串口接收和发送的数据;


7. 性能分析窗口


显示所要观察的各程序段占用CPU的空间;


8. 内存窗口(Memory Window)


显示所选择的内存中的数据;


9. 符号浏览窗口(Symbol Browser Window)


显示各种符号名称,包括专有符号,用户自定义符号(函数名、变量、标号)等;


10. 调用线窗口(Call-Stack Window)


动态显示当前执行的程序段的函数调用关系;


11. 代码覆盖窗口


提供当前模块内各程序段中被执行代码的比率;。


12. 外围设备窗口(peripherals)


可显示I/O口,定时器,中断,串口等外围设备状态;


第二节 dScope for Windows基本操作


1. 指定初始化文件


uVision的Option菜单dScope Debugger中指定dScope的初始化文件,用uVision的RUN启动dScope将自动加载此初始化文件,自动执行其中命令;


下面是一个例子,可以看出调入一个调试代码的过程。Ds51.ini:


load 8051.dll


load test


slog>>test.log


xtal=11.0592


define button "go to main","g,main"


ws RevCounter


ws rm.r


g,main


PA RESET


PA serial


PA timer0


2. 观察变量


方法1:命令行


WS expression [, numberbase ] [ LINE ]


其中numberbase为显示数制,10对应10进制,16对应16进制,缺省为16进制。LINE为单行显示,缺省为多行显示。


方法2:setup->Watchpoints,在对话框中输入变量


3. 显示RAM的值<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


d i(x,d):起始地址,终止地址


d 变量名


4. 观察堆栈


View->Call-stack->Show invocation,可以跟踪调用过程;


5. 中断处理程序调试


在装入8051.dll后,在dScope的主菜单中将增加Peripherial,其有4个字菜单:


I/0 port:Pi端口状态


Interrupt:中断设置


Timer:定时器中断状态


Serial:串口中断状态


设置相应的中断请求标志位即可产生中断。


6. 性能分析(Performance Analyzer:PA)


PA用来分析一段代码执行占用CPU的百分比。定义:


命令行  PA func_name


第三节 dScope for Windows命令文件的编制


dScope除了用命令行的方式进行调试以外,还可将各种调试命令汇集于一个调试文件中,然后调用该文件,就可达到自动测试用户源代码的目的。dScope的命令文件支持C/PL/M的格式,因而编制调试命令文件与编制C语言程序有些类似。


1. 地址空间及地址空间类型


(1) 地址空间分段


dScope提供的最大可用空间为16M,实际上我们只用以下三段:


内部数据空间段(0X00段或D段)


0X00:0X0000~0X00:0XFFFF(MSC51而言为0X00:0X00FF)


外部数据空间段(0X01段式或X段)


0X010X00000X010XFFFF


程序空间段(0XFF段或C段)


0XFF0X00000XFF0XFFFF


(2) 地址空间类型


C:代码空间


D:内部直接寻址空间


I 内部间接寻址空间


X:外部数据空间


B:位寻址空间


PI/O


EB:扩展的位寻址空间(MCS251专有)


ED:扩展的数据空间(MCS251专有)


CO:常数空间(MCS251专有)


HC:正常数空间(MCS251专有)


2. 常量


dScope支持十六进制、八进制、十进制、二进制常数,其后缀分别为HQ(O)T(或无)、Y


dScope不区分常量的大、小写。


(1) 整型常量


分为整型(int),无符号整型(uint,00rd),长整型(long),无符号长整型(WlongWord)。


(2) 浮点型常量


  ANSI  C相同。


(3) 字符串常量


      ANSI  C相同


(4) 字符常量


分为字符型(Char)和无符号字符型(Uchar)一种。


(5) 行号常数


指用户程序中的行号,实际上是个地址


(6) 位常量(Bit):


0和1


(7) 地址常数


地址常数的种类很多,地址常数不同于行号常数,行号常数就是一个地址,而地址数被引用时,实际上是取该地址中的数据。


C:代码地址常数,如C:0X0012或0XFF:0X0012


D:内部直接寻址地址常数,如D:0X0068或0X00:0X0068


I:内部间按寻址地址常数,如I:0X0010或0X00:0X0010


X:外部数据空间地址常数,如X:0X0028或0X01:0X0028


B:位地址常数,如B:0X20或B:0X24.0


EB:扩展的位地址常数(MCS251专有), 


ED:扩展的数据空间地址常数(MCS251专有)


CO:常数空间地址常数(MCS251专有)


HC:正常数空间地址常数(MCS251专有)


(8) 标识符常量


即用户源程序中的标号、函数名等,实际上代表某一地址。


(9) 用户源程序中定义的常数


3. 变量


dScope所支持的变量名或标识符最多可由31个字符组成,第一个字母为A~Z,a~z,下划线或问号,后续字符可为字母、数字、下划线和问号。除CPU变量和系统变量外,dScope不支持全局变量,但可视“define”命令定义的变量为全局变量。


Dscope所支持的变量分为以下几种(变量名称不区分大、小写),支持类型转换:


(1) 整型变量


分为整型变量(int)、无符号整型变量(uint/word),长整型(Long) 、无符号长整型(Ulong/dword)。


(2) 浮点型变量(float)


ANSI  C相同。


(3) 字符型变量L


分为字符型(char)变量和无符号字符型(Uchar)


(4) 位变量(Bit)


(5) 系统变量  


 dScope自己定义了一系列内部变量,用户可对这些变量进行读或读/写操作,   可被用户自定义数所引用。


a.      Cycles (Read Only)


32位变量(Ulong),指示当前程序执行已花费的指令周期(cycle)。


b.     Ramsize(R/W)


16位变量(Uint),指示内部可直接寻址的数据空间大小。


c.      Radix(R/N)


8位变量(Uchar),决定输出的数制


Radix=0X0A (10进制)Radix=0X10 (16进制)


d.     IIP-(R/W


8位变量(Uchar),指示当前的中断嵌套数目。


e.      R/W


32位变量(Ulong),指出PC值,通过对其进行写操作,可改变程序执行的流程。


f.       Itrace (R/W)


8位变量(Uchar),决定是否对程序运行情况进行记录


    Itrace=1,使能记录操作


    Itrace=0,根本上记录操作


g.      __Break__(R/W)


8位变量(Uchar  __Break__=1,中止程序的运行


h.      __Mode____Frame size__MCS 251专有的变量。


(6) CPU变量


R0R7AC(位变量)、BDPTR及特殊功能寄存器变量,对这些变量均可进行读、写操作。


(7) 用户源程序中定义的变量、数组、结构等


4. 运算符


dScope支持ANSI  C的运算符,包括算术运算符,逻辑运算符,关系运算符。


5. 表达式


以运算符将dScope所支持的常量、变量、函数等连接在一起,就构成了dScope的表达式。


6. 数组


dScope不支持在命令文件中定义数组,但可引用用户程序中的数组,引用方式如同C。


7. 结构和联合


dScope不支持在命令文件中定义结构和联合,但可引用用户程序中的结构和联合,引用方式如同C,但如要输出整个结构或联合的结果,就要用命令“OBJ”。


8. 指针:


不可自定义指针,但支持用户源程序中的指针变量。


9. dScope命令语句


dScope提供了一系列调试命令。在命令文件中,dScope只支持这些语句及前述定义的表达式,C语言的语句均不被支持,但在命令文件所包含的用户自定义函数(非用户源程序中的函数)中支持C语句,但用户自定义函数中同样不支持数组、结构、联合和指针。


(1) ASM


在线汇编命令,格式如下:


ASM   C:0Xnnnn (或标号);设定插入汇编指令的地址


ASM  汇编指令


ASM  汇编指令


插入完毕后,在debug窗口内选择“Assemble->Assemble”完成编译。


(2) Assign


串行口分配指令,格式如下:


Assign channel<unreg>outreg


MCS51为:Assign  Win<SOIN> Soot


但目前的dScope版本并未提供完整串口窗口功能。


(3) Define


用户自定义变量指令,格式如下:


Define <类型> <变量名>


类型一为如前所述的变量类型,Define指令定义的变量可能为全局变量,可为用户自定义函数所引用。


(4) Display


内存显示命令,格式如下二:


D   起始地址,结束地址


地址如前所述的地址常数,标识符常量。


(5) Enter


内存修改指令,格式如下:


E  类型地址=表达式 [表达式2][……]


类型如前所述,地址如前所述的地址常数。表达式如前所述,但如果是函数名称(含标号、指针变量),则关键字E→EP


(6) Map/Reset map


Map为内存段修改指令,Reset map将内存段复位或缺省值。


(7) Object


用以引用用户源程序中的结构(联合)、数组、格式如下:


Obj表达式 [n][Line]


表达式为用户源程序中的数组,结构(联合)名称。当Line缺省时,数目、结构(联合)的内容按n行输出;如有Line,则单行输出。


(8) U


反汇编命令,格式如下:


    U  [地址]


地址包括地址常 数及标识符常量,指明反汇编的起始地址。


(9) WK


观察点删除命令,格式如下:


    WK   n1[n2 ][……]  ;删除指定的观察点,n为字符型,整型


   常数


    WK   *              ;删除所有的观察点


(10) WS


观察点设置命令,格式如下:


WS  表达式[,n][LINE]


关键字LINE存在时,观察点表达式单行输出


LINE缺省时,观察点表达式n行输出。


(11) G


连续运行命令,格式如下:


   G  [起始地址][终止地址]


地址为标识符常量或地址常数,地址缺省时,为连续运行。


(12) T/P


单步运行指令,格式如下:


    T/P    n    n指至单行运行的步数,P指给用户当调用某函数时,把它作为一步处理,并不进入该函数运行。


(13) PA


性能分析操作指令,其分以下几种:


PA


显示当前所设置的性能分析程度段


PA Kill  *


删除当前所设置的所有性能分析程序段


PA  Kill  n1 [,n2],[……]


删除指定的性能分析程序段


PA  地址范围


设置性能分析程序段,地址范围可以起始地址和结束地址的方式给出,也可给出函数名,行号范围。


PA  Reset


复位性能分析窗口(PA  Windows),清除所有的记录。


(14) BD


断点失效命令,格式如下:


BD    n1 [,n2],[,……]    ;disable指定的断点


DB    *                 ;disable所有的断点


(15) BE


断点使能命令,格式如下:


BE   M  [,n2],[,……]    ;使能指定的断点


BE   *                  ;使能所有的断点


(16) BK


断点删除指令,格式如下:


BK    M[,n2],[,……]    ;删除指定的断点


BK    *                ;删除所有的断点


(17) BL


断点显示指令,显示所有被定义的断点。


(18) BS


断点定义指令,dScope支持多达40个断点,具体格式如下:


a.BS  表达式[,count] [,“cmd”]


count:经过该断点的次数 [选项]


cmd”:断点到达后附带执行的dScope命令(连项)


表达式一个条件表达式,此时该断点称为条件断点(运算符为&.&&,<<=>,>=,= =,!=)


BS  READ  表达式 [,count] [,“cmd”]


BS  WRITE  表达式 [,count] [“cmd”]


BS  READWRITE  表达式 [,count] [,“cmd”]


以上三种断点称访问式(Access断点),当某一址或变量被访问(R/W)或某些值被读写时,程序被中断。


(19) Define button


图标定义指令,用于当窗口(Toolbox)


(20) !


DOS窗口Open命令,以“EXIT”命令退出DOS窗口。


(21) Include


文件包含命令,格式如下:


Include  [路径] 文件名


dScope支持以文件包含的方式调入并执行调试命令文件,用户自定义函数文件,调试命令文件可以有后缀,也可无后缀。


(22) Load


加载命令,格式如下:


Load  [路径] 文件名


 Load指令能够加载的文件必须具有以下格式之一。


Intel Hex/Hex 386格式


Intel Object (OMF_51) 格式


Intel Object (OMF-251) 格式


dScope的CPU驱动文件(.DLL)


(23) LOG


Command Window存盘指令,用于将Command Windows中的内容输出到指定的文件中,格式如下:


LOG > [路径]文件名   ;创建一个新文件


LOG >> [路径]文件名  ;将Command  Windows的内容输出到某个已


   存在的文件中。


LOG  OFF   完成输出操作并开闭该文件


LOG指令只将LOG>或LOG>>与LOG  OFF指令之间的操作命令存入该指定文件。


(24) Reset


复位指令,具体格式如下:


Reset        ;执行dScope的复位


Reset  Map  ;复位外部数据空间


Reset  Var   ;复位SET指令定义的变量


(25) Save


该指令将一段内存映象以19EX386/HEX的格式存盘,具体格式如下:


Save  路径  文件名:地址1、地址2


地址1、地址2指所要保存的空间范围,既可是标识符,也可是址常数。


(26) SET


该指令回来定义dScope目标代码预定义变量的含义,这些预定义变量包括以下二种:


SRC   ;指出所在的路径


F1~F12;对应于键盘上的12个功能键,定义这些功能键的


              含义。


SET指令的格式为:


SET  变量=“字符串”


SET  变量


10. 函数


dScope支持三种函数,即dScope预定义函数,用户自定义函数和信号函数,分别详述如下:


(1) dScope预定义函数


dScope号提供8个预定义函数(可视为dScope的库函数)


Void Printf(“String”,输出表列)


屏幕打印函数,与ANSI C的Printf ( ) 函数相同


Void exec(“Command__String”)


Command__String为一有效的命令字符串,此函数用于在运行用户自定义函数的过程中执行dScope命令,这个函数提供了一个很重要的编制测试命令文件的方法。


int getint(“Prompt__String”);从键盘输入一个整数


int  getlong (“Prompt__String”);从键盘输入一个长整数


float getfloat (“Prompt__String”);从键盘输入一个浮点数


以上这三个函数被执行时,dScope会弹出一个dialog box等待用户输入数据,其标题栏上是“Prompt__String”,利用这个函数,不仅可以为变量赋值,也可使用户得以看清前一阶段的测试结果。


int  rand (int seed)


   该函数会输出一个随机数(-32768~32768)


Void memeset (ulorg start , ulong end ,uchar val)


   该函数用于给地址范围(Start__end)内的内存赋值(Val)


Void twatch (Long cycles)


定时函数,时间由(Long cycles)决定,它是以指令周期计数的,它也  用于产生一个信号波形,该函数必须用于信号函数中。


(2) 用户自定义函数


这类函数不同于用户源程序中的数函,其定义格式为


Func  返回类型  函数名(参数序列)


{


    语句


}


返回类型如前所述的变量类型


用户自定义函数中的语句与ANSI  C相似,只是不支持数组结构、联合、指针,可引用dScope系统变量,define语句定义的变量和用户源程序变量,不支持dScope命令,如想在函数中执行dScope命令,要借助于exec(“Command__String”)函数,可引用dScope预定义的函数(除了twatch ( )函数),不支持ANSI  C的库函数。


(3) 信号函数


用于产生具有某一波形的信号,定义格式为:


Signal返回类型函数名(参数长列){


                              语句


       }


信号函数主要是利用twatch (  )函数,目前dScope版本在提供这一功能上面还有一定问题。


(4) dScope函数与ANSI函数的区别


不支持条件汇编


不支持头文件


无变量的初始化


不支持数组、结构、指针


调用方式不同,自定义函数和信号函数首先要包含一个函数文件之中,然而在测试命令文件中以Inclule指令调用该函数文件,最后才能以函数名调用之。


函数调用只支持传值方式。







第七章 Keil C51的代码效率(转帖)

发表于 2009/2/9 8:32:35

C51程序编译生成汇编代码的效率,是由许多因素共同决定的,对于Keil C51,主要受以下两种因素影响:

第一节 存储模式的影响


    存储模式决定了缺省变量的存储空间,而访问各空间变量的汇编代码的繁简程度决定了代码率的高低。


例如:一个整形变量i,如放于内存18H、19H空间,则++i的操作编译成四条语句:


INC  0x19


MOV  A,0x19


JNZ  0x272D


INC  0x18


0x272D:


而如果放于外存空间0000H、0001H则++i的操作编译成九条语句:


MOV DPTR,0001


MOVX A,@ DPTR


INC A


MOVX @ DPTR,A


JNz  #5


MOV OPTR,#0000


MOVX A,@DPTR


INC A


MOVX @ DPTR,A


就汇编之后的语句而言,对外部存储器的操作较内部存储器操作代码率要低得多,生成的语句为内存的两倍以上,而程序中有大量的这种操作,可见存储模式对代码率的响了。


因此程序设计的原则是


1、存储模式从small-Compact-large依次选择,实在是变量太多,才选large模式。


2、即使选择了large模式,对一些常用的局部的或者可放于内存中的变量,最好放于内存中,以尽量提高程序的代码率。


第二节 程序结构的影响


程序的结构单元包括模块、函数等等。同样的功能,如果结构越复杂,其所涉及的操作、变量、功能模块函数等就越多,较之结构性好,代码简单的程序其代码率自然就低得多。


此外程序的运行控制语句,也是影响代码率的关键因素,例如:switch -case语句,许多编译器都把它们译得非常复杂,Keil C51也不例外,相对较为简易的Switch-case语句,编译成跳转指令形式,代码率较高,但对较为复杂的Switch-Case,则要调用一个系统库函数?C?ICASE进行处理,非常复杂。


再如if( ),while( ),等语句也是代码相对较低的语句,但编译以后比switch-case要高得多。


因此建议设计者尽量少用switch-case之类语句来控制程序结构,以提高代码率。


除以上两点外,其它因素也会对代码率产生影响,例如:


是否用寄存器传递参数  即NOAREGS选项是否有


是否包括调试信息:即DEBUG选项


是否包括扩展的调试信息:即BJECTEXTEND



 


 


第六章 Keil C51例子:Hello.c(转帖)

发表于 2009/2/9 8:31:35


Hello位于\C51\excmples\Hello\目录,其功能是向串口输出“Hello,world”整个程序如下:


pragma DB OE CD


#indule <reg51.h>


#include<stdio.h>


void main(void)


    {


          SCOn=0x50;


          TMOD=0x20


          TH1=0xf3;


          Tri=1;


          TI=1;


          printf(“Hello,world \n”);


          while(1) {  }


    }


第一节 uVision for Windows的使用步骤


(1) file_new新建一个hello.c文件,输入如上内容或直接用目录下源文件。


(2) file_save或工具栏将文件存盘。


(3) project_new project创建一个project名为hello,并在其中加入hello.c。


这时该project已是打开状态,或用open project打开已存在的project。


(4) option_C51 compiler中选出至少包括两项DB OE。


(5) option_dscope Debugger选中hello\DS51.INI


查看DS51.INI看其是否为:


    load…\\BIN\8051.DLL


    map 0, 0xffff”


否则修改。


(6) 在option_make选make文件顺序。


(7) project选Build  project,看是否有语法错误,若无则生成HEX文件,若有则修改源文件后重复以上部分步骤。


(8) run_dScope debugger进入dScope51后装入hello则可用go直接运行看serial窗口有无输出,正常每系统运行一次,serial窗口均出现一个“Hello,world”表明运行无误。


第二节 Ishell for Dos使用步骤


(1) 进入Ishell 用Setup editer选择编辑器。


然后单击Edit或用Edit命令编辑hello.c源文件,存盘,也可以在files窗口中直接选中hello.c。


(2) 用cd改换project目录至hello目录。


(3) 在setup_target一项目选8051。


(4) 在setup_C51中输出DB OE。


(5) 在setup_project输入project名hello。


(6) 在setup_save保存Ishell.CFG文件。


(7) 编辑一个Link文件hello.lin中有“hell.obj”一行。


(8) 由光标落在files菜单中的Hello.c上,单击“translate”,如无语法错,再击“link”,则Hex文件生成。


(9) 单击Simulate如在8051.CDF中选Simulate为dScope则进入dScope调试直接“Go”,看serial窗口输出为“Hello.world”。


(10) 如程序有误修改源代码后不必再translate或link了,只要一步Amake即可。


project中包括不止一个文件,在DOS的Ishell中不能用Translate编译,而应建立bat文件,直接在命令窗编译,然后link连接。


如还需用Translate则只能多个文件分别编译,然后连接







第五章 Keil C51库函数参考(转帖)

 


C51强大功能及其高效率的重要体现之一在于其丰富的可直接调用的库函数,多使用库函数使程序代码简单,结构清晰,易于调试和维护,下面介绍C51的库函数系统。


第一节 本征库函数(intrinsic routines)和非本征证库函数


C51提供的本征函数是指编译时直接将固定的代码插入当前行,而不是用ACALL和LCALL语句来实现,这样就大大提供了函数访问的效率,而非本征函数则必须由ACALL及LCALL调用。


C51的本征库函数只有9个,数目虽少,但都非常有用,列如下:


_crol_,_cror_:将char型变量循环向左(右)移动指定位数后返回


_iror_,_irol_:将int型变量循环向左(右)移动指定位数后返回


_lrol_,_lror_:将long型变量循环向左(右)移动指定位数后返回


_nop_:      相当于插入NOP


_testbit_:  相当于JBC bitvar测试该位变量并跳转同时清除。


_chkfloat_: 测试并返回源点数状态。


使用时,必须包含#inclucle  <intrins.h>一行。


如不说明,下面谈到的库函数均指非本征库函数。


第二节 几类重要库函数


1. 专用寄存器include文件


例如8031、8051均为REG51.h其中包括了所有8051的SFR及其位定义,一般系统都必须包括本文件。


2. 绝对地址include文件absacc.h


该文件中实际只定义了几个宏,以确定各存储空间的绝对地址。


3. 动态内存分配函数,位于stdlib.h中


 


4. 缓冲区处理函数位于“string.h”中


其中包括拷贝比较移动等函数如:


memccpy memchr memcmp memcpy memmove memset


这样很方便地对缓冲区进行处理。


5. 输入输出流函数,位于“stdio.h”中


流函数通8051的串口或用户定义的I/O口读写数据,缺省为8051串口,如要修改,比如改为LCD显示,可修改lib目录中的getkey.c及putchar.c源文件,然后在库中替换它们即可。


第三节 Keil C51库函数原型列表


1. CTYPE.H


    bit  isalnum(char c);


    bit  isalpha(char c);


    bit  iscntrl(char c);


    bit  isdigit(char c);


    bit  isgraph(char c);


    bit  islower(char c);


    bit  isprint(char c);


    bit  ispunct(char c);


    bit  isspace(char c);


    bit  isupper(char c);


    bit  isxdigit(char c);


    bit  toascii(char c);


    bit  toint(char c);


        char  tolower(char c);


        char  __tolower(char c);


        char  toupper(char c);


        char  __toupper(char c);


2. INTRINS.H


    unsigned char _crol_(unsigned char c,unsigned char b);


    unsigned char _cror_(unsigned char c,unsigned char b);


    unsigned char _chkfloat_(float ual);


    unsigned int _irol_(unsigned int i,unsigned char b);


    unsigned int _iror_(unsigned int i,unsigned char b);


    unsigned long _irol_(unsigned long l,unsigned char b);


    unsigned long _iror_(unsigned long L,unsigned char b);


    void _nop_(void);


    bit _testbit_(bit b);


3. STDIO.H


   char getchar(void);


   char _getkey(void);


    char *gets(char * string,int len);


    int printf(const char * fmtstr[,argument]…);


    char putchar(char c);


    int puts (const char * string);


    int scanf(const char * fmtstr.[,argument]…);


    int sprintf(char * buffer,const char *fmtstr[;argument]);


    int sscanf(char *buffer,const char * fmtstr[,argument]);


    char ungetchar(char c);


    void vprintf (const char *fmtstr,char * argptr);


    void vsprintf(char *buffer,const char * fmtstr,char * argptr);


4. STDLIB.H


    float atof(void * string);


    int atoi(void * string);


    long atol(void * string);


    void * calloc(unsigned int num,unsigned int len);


    void free(void xdata *p);


    void init_mempool(void *data *p,unsigned int size);


    void *malloc (unsigned int size);


    int rand(void);


    void *realloc (void xdata *p,unsigned int size);


    void srand (int seed);


5. STRING.H


    void *memccpy (void *dest,void *src,char c,int len);


    void *memchr (void *buf,char c,int len);


    char memcmp(void *buf1,void *buf2,int len);


    void *memcopy (void *dest,void *SRC,int len);


    void *memmove (void *dest,void *src,int len);


    void *memset (void *buf,char c,int len);


    char *strcat (char *dest,char *src);


    char *strchr (const char *string,char c);


    char strcmp (char *string1,char *string2);


    char *strcpy (char *dest,char *src);


    int strcspn(char *src,char * set);


    int strlen (char *src);


    char *strncat (char 8dest,char *src,int len);


    char strncmp(char *string1,char *string2,int len);


    char strncpy (char *dest,char *src,int len);


    char *strpbrk (char *string,char *set);


    int strpos (const char *string,char c);


    char *strrchr (const char *string,char c);


    char *strrpbrk (char *string,char *set);


    int strrpos (const char *string,char c);


    int strspn(char *string,char *set);



 



第四章 Keil C51高级编程(转帖)

发表于 2009/2/9 8:29:37


本章讨论以下内容:


l        绝对地址访问


l        C与汇编的接口


l        C51软件包中的通用文件


l        段名转换与程序优化


第一节 绝对地址访问


C51提供了三种访问绝对地址的方法:


1. 绝对宏:


在程序中,用“#include<absacc.h>”即可使用其中定义的宏来访问绝对地址,包括:


CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD


具体使用可看一看absacc.h便知


例如:


rval=CBYTE[0x0002];指向程序存贮器的0002h地址


rval=XWORD   [0x0002];指向外RAM的0004h地址


2. _at_关键字


直接在数据定义后加上_at_ const即可,但是注意:


(1)绝对变量不能被初使化;


(2)bit型函数及变量不能用_at_指定。


例如:


idata struct link list _at_ 0x40;指定list结构从40h开始。


xdata char text[25b] _at_0xE000;指定text数组从0E000H开始


提示:如果外部绝对变量是I/O端口等可自行变化数据,需要使用volatile关键字进行描述,请参考absacc.h。


3. 连接定位控制


此法是利用连接控制指令code xdata pdata \data bdata对“段”地址进行,如要指定某具体变量地址,则很有局限性,不作详细讨论。


第二节 Keil C51与汇编的接口


1. 模块内接口


方法是用#pragma语句具体结构是:


#pragma asm


汇编行


#pragma endasm


这种方法实质是通过asm与ndasm告诉C51编译器中间行不用编译为汇编行,因而在编译控制指令中有SRC以控制将这些不用编译的行存入其中。


2. 模块间接口


C模块与汇编模块的接口较简单,分别用C51与A51对源文件进行编译,然后用L51将obj文件连接即可,关键问题在于C函数与汇编函数之间的参数传递问题,C51中有两种参数传递方法。


(1) 通过寄存器传递函数参数


最多只能有3个参数通过寄存器传递,规律如下表:


 



参数数目


char


int


long,float


一般指针


1


2


3


R7


R5


R3


R6 & R7


R4 & R5


R2 & R3


R4~R7


R4~R7


R1~R3


R1~R3


R1~R3


 


(2) 通过固定存储区传递(fixed memory)


这种方法将bit型参数传给一个存储段中:


          function_name?BIT


将其它类型参数均传给下面的段:?function_name?BYTE,且按照预选顺序存放。


至于这个固定存储区本身在何处,则由存储模式默认。


(3) 函数的返回值


函数返回值一律放于寄存器中,有如下规律:


 



return type


Registev


说明


bit


标志位


由具体标志位返回


char/unsigned char 1_byte指针


R7


单字节由R7返回


int/unsigned int 2_byte指针


R6 & R7


双字节由R6和R7返回,MSB在R6


long&unsigned long


R4~R7


MSB在R4,  LSB在R7


float


R4~R7


32Bit IEEE格式


一般指针


R1~R3


存储类型在R3 高位R2 低R1


(4) SRC控制


该控制指令将C文件编译生成汇编文件(.SRC),该汇编文件可改名后,生成汇编.ASM文件,再用A51进行编译。


第三节 Keil C51软件包中的通用文件


C51\LiB目录下有几个C源文件,这几个C源文件有非常重要的作用,对它们稍事修改,就可以用在自己的专用系统中。


1. 动态内存分配


init_mem.C:此文件是初始化动态内存区的程序源代码。它可以指定动态内存的位置及大小,只有使用了init_mem( )才可以调回其它函数,诸如malloc calloc,realloc等。


calloc.c:此文件是给数组分配内存的源代码,它可以指定单位数据类型及该单元数目。


malloc.c:此文件是malloc的源代码,分配一段固定大小的内存。


realloc.c:此文件是realloc.c源代码,其功能是调整当前分配动态内存的大小。


2. C51启动文件STARTUP.A51


启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:


l        定义内部RAM大小、外部RAM大小、可重入堆栈位置


l        清除内部、外部或者以此页为单元的外部存储器


l        按存储模式初使化重入堆栈及堆栈指针


l        初始化8051硬件堆栈指针


l        main( )函数交权


开发人员可修改以下数据从而对系统初始化


 常数名            意义


IDATALEN        待清内部RAM长度


XDATA START     指定待清外部RAM起始地址


XDATALEN        待清外部RAM长度


IBPSTACK        是否小模式重入堆栈指针需初始化标志,1为需要。缺省为0


IBPSTACKTOP     指定小模式重入堆栈顶部地址


XBPSTACK        是否大模式重入堆栈指针需初始化标志,缺省为0


XBPSTACKTOP     指定大模式重入堆栈顶部地址


PBPSTACK        是否Compact重入堆栈指针,需初始化标志,缺省为0


PBPSTACKTOP     指定Compact模式重入堆栈顶部地址


PPAGEENABLE     P2初始化允许开关


PPAGE           指定P2值


PDATASTART      待清外部RAM页首址


PDATALEN        待清外部RAM页长度


提示:如果要初始化P2作为紧凑模式高端地址,必须:PPAGEENAGLE=1,PPAGE为P2值,例如指定某页1000H-10FFH,则PPAGE=10H,而且连接时必须如下:


L51<input modules> PDATA(1080H),其中1080H是1000H-10FFH中的任一个值。


以下是STARTUP.A51代码片断,红色是经常可能需要修改的地方:


;------------------------------------------------------------------------------


;  This file is part of the C51 Compiler package


;  Copyright KEIL ELEKTRONIK GmbH 1990


;------------------------------------------------------------------------------


;  STARTUP.A51:  This code is executed after processor reset.


;


;  To translate this file use A51 with the following invocation:


;


;     A51 STARTUP.A51


;


;  To link the modified STARTUP.OBJ file to your application use the following


;  L51 invocation:


;


;     L51 <your object file list>, STARTUP.OBJ <controls>


;


;------------------------------------------------------------------------------


;


;  User-defined Power-On Initialization of Memory


;


;  With the following EQU statements the initialization of memory


;  at processor reset can be defined:


;


;                    ; the absolute start-address of IDATA memory is always 0


IDATALEN EQU         80H    ; the length of IDATA memory in bytes.


;


XDATASTART           EQU    0H   ; the absolute start-address of XDATA memory


XDATALEN EQU         0H     ; the length of XDATA memory in bytes.


;


PDATASTART           EQU    0H   ; the absolute start-address of PDATA memory


PDATALEN EQU         0H     ; the length of PDATA memory in bytes.


;


;  Notes:  The IDATA space overlaps physically the DATA and BIT areas of the


;          8051 CPU. At minimum the memory space occupied from the C51


;          run-time routines must be set to zero.


;------------------------------------------------------------------------------


;


;  Reentrant Stack Initilization


;


;  The following EQU statements define the stack pointer for reentrant


;  functions and initialized it:


;


;  Stack Space for reentrant functions in the SMALL model.


IBPSTACK EQU         0 ; set to 1 if small reentrant is used.


IBPSTACKTOP          EQU    0FFH+1   ; set top of stack to highest location+1.


;


;  Stack Space for reentrant functions in the LARGE model. 


XBPSTACK EQU         0 ; set to 1 if large reentrant is used.


XBPSTACKTOP          EQU    0FFFFH+1; set top of stack to highest location+1.


;


;  Stack Space for reentrant functions in the COMPACT model.    


PBPSTACK EQU         0 ; set to 1 if compact reentrant is used.


PBPSTACKTOP          EQU    0FFFFH+1; set top of stack to highest location+1.


;


;------------------------------------------------------------------------------


;


;  Page Definition for Using the Compact Model with 64 KByte xdata RAM


;


;  The following EQU statements define the xdata page used for pdata


;  variables. The EQU PPAGE must conform with the PPAGE control used


;  in the linker invocation.


;


PPAGEENABLE          EQU    0    ; set to 1 if pdata object are used.


PPAGE                EQU    0    ; define PPAGE number.


;


;------------------------------------------------------------------------------


3. 标准输入输出文件


putchar.c


putchar.c是一个低级字符输出子程,开发人员可修改后应用到自己的硬件系统上,例如向CLD或LEN输出字符。


缺省:putchar.c是向串口输出一个字符XON|XOFF是流控标志,换行符“\*n”自动转化为回车/换行“\r\n”。


getkey.c


getkey函数是一个低级字符输入子程,该程序可用到自己硬件系统,如矩阵键盘输入中,缺省时通过串口输入字符。


4. 其它文件


还包括对Watch-Dog有独特功能的INIT.A51函数以及对8×C751适用的函数,可参考源代码。


第四节 段名协定与程序优化


1. 段名协定(Segment Naming Conventions)


C51编译器生成的目标文件存放于许多段中,这些段是代码空间或数据空间的一些单元,一个段可以是可重定位的,也可以是绝对段,每一个可重定位的段都有一个类型和名字,C51段名有以下规定:


每个段名包括前缀与模块名两部分,前缀表示存储类型,模块名则是被编译的模块的名字,例如:


CO?main1  :表示main1模块中的代码段中的常数部分


PR?function1?module 表module模块中函数function1的可执行段,具体规定参阅手册。


2. 程序优化


C51编译器是一个具有优化功能的编译器,它共提供六级优化功能。确保生成目标代码的最高效率(代码最少,运行速度最快)。具体六级优化的内容可参考帮助。


C51中提供以下编译控制指令控制代码优化:


OPTIMIZE(SJXE):尽量采用子程序,使程序代码减少。


NOAREGS:不使用绝对寄存器访问,程序代码与寄存器段独立。


NOREGPARMS:参数传递总是在局部数据段实现,程序代码与低版本C51兼容。


OPTIMIZE(SIZE)AK OPTIMIZE(speed)提供6级优化功能,缺省为:   OPTIMIZE(6,SPEED)。



第三章 Keil C51 vs 标准C(转帖)



发表于 2009/2/9 8:28:28


深入理解并应用C51对标准ANSIC的扩展是学习C51的关键之一。因为大多数扩展功能都是直接针对8051系列CPU硬件的。大致有以下8类:


l        8051存储类型及存储区域


l        存储模式


l        存储器类型声明


l        变量类型声明


l        位变量与位寻址


l        特殊功能寄存器(SFR)


l        C51指针


l        函数属性


具体说明如下(8031为缺省CPU)。


第一节 Keil C51扩展关键字


C51 V4.0版本有以下扩展关键字(共19个):


_at_         idata      sfr16      alien    interrupt     small


bdata        large      _task_     Code     bit           pdata


using        reentrant xdata      compact  sbit          data   sfr


第二节 内存区域(Memory Areas):


1. Pragram Area:


Code说明可有多达64kBytes的程序存储器


2. Internal Data Memory:


内部数据存储器可用以下关键字说明:


data:直接寻址区,为内部RAM的低128字节    00H~7FH


idata:间接寻址区,包括整个内部RAM区       00H~FFH


bdata:可位寻址区,                       20H~2FH


3. External Data Memory


外部RAM视使用情况可由以下关键字标识:


xdata:可指定多达64KB的外部直接寻址区,地址范围0000H~0FFFFH


pdata:能访问1页(25bBytes)的外部RAM,主要用于紧凑模式(Compact Model)。


4. Speciac Function Register Memory


8051提供128Bytes的SFR寻址区,这区域可位寻址、字节寻址或字寻址,用以控制定时器、计数器、串口、I/O及其它部件,可由以下几种关键字说明:


sfr:字节寻址  比如 sfr P0=0x80;为PO口地址为80H,“=”后H~FFH之间的常数。


sfr16:字寻址,如sfr16  T2=0xcc;指定Timer2口地址T2L=0xcc T2H=0xCD


sbit:位寻址,如sbit EA="0xAF";指定第0xAF位为EA,即中断允许


还可以有如下定义方法:


sbit   0V=PSW^2;(定义0V为PSW的第2位)


sbit   0V=0XDO^2;(同上)


bit  0V-=0xD2(同上)。


第三节 存储模式


存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域,共三种:


1. Small模式


所有缺省变量参数均装入内部RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。


2. Compact模式


所有缺省变量均位于外部RAM区的一页(256Bytes),具体哪一页可由P2口指定,在STARTUP.A51文件中说明,也可用pdata指定,优点是空间较Small为宽裕速度较Small慢,较large要快,是一种中间状态。


3. large模式


所有缺省变量可放在多达64KB的外部RAM区,优点是空间大,可存变量多,缺点是速度较慢。


提示:存储模式在C51编译器选项中选择。


第四节 存储类型声明


变量或参数的存储类型可由存储模式指定缺省类型,也可由关键字直接声明指定。各类型分别用:code,data,idata,xdata,pdata说明,例:


data uar1


char code array[ ]=“hello!”;


unsigned char xdata arr[10][4][4];


第五节 变量或数据类型


C51提供以下几种扩展数据类型:


bit 位变量值为0或1


sbit 从字节中定义的位变量  0或1


sfr  sfr字节地址  0~255


sfr16  sfr字地址  0~65535


其余数据类型如:char,enum,short,int,long,float等与ANSI C相同。


第六节 位变量与声明


1. bit型变量


bit型变量可用变量类型,函数声明、函数返回值等,存贮于内部RAM20H~2FH。


注意:


(1) 用#pragma disable说明函数和用“usign”指定的函数,不能返回bit值。


(2) 一个bit变量不能声明为指针,如bit *ptr;是错误的


(3) 不能有bit数组如:bit arr[5];错误。


2. 可位寻址区说明20H-2FH


可作如下定义:


int bdata i;


char bdata arr[3],


然后:


sbit  bito=in0;sbit bit15=I^15;


sbit arr07=arr[0]^7;sbit arr15=arr^7;


第七节 Keil C51指针


C51支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer).


1. 一般指针


一般指针的声明和使用均与标准C相同,不过同时还可以说明指针的存储类型,例如:


long * state;为一个指向long型整数的指针,而state本身则依存储模式存放。


char * xdata ptr;ptr为一个指向char数据的指针,而ptr本身放于外部RAM区,以上的long,char等指针指向的数据可存放于任何存储器中。


一般指针本身用3个字节存放,分别为存储器类型,高位偏移,低位偏移量。


2. 存储器指针


基于存储器的指针说明时即指定了存贮类型,例如:


char data * str;str指向data区中char型数据


int xdata * pow; pow指向外部RAM的int型整数。


这种指针存放时,只需一个字节或2个字节就够了,因为只需存放偏移量。


3. 指针转换


即指针在上两种类型之间转化:


l        当基于存储器的指针作为一个实参传递给需要一般指针的函数时,指针自动转化。


l        如果不说明外部函数原形,基于存储器的指针自动转化为一般指针,导致错误,因而请用“#include”说明所有函数原形。


l        可以强行改变指针类型。


第八节 Keil C51函数


C51函数声明对ANSI C作了扩展,具体包括:


1. 中断函数声明:


中断声明方法如下:


void serial_ISR () interrupt 4 [using 1]


{


/* ISR */


}


为提高代码的容错能力,在没用到的中断入口处生成iret语句,定义没用到的中断。


/* define not used interrupt, so generate "IRET" in their entrance */


void extern0_ISR() interrupt 0{}    /* not used */


void timer0_ISR () interrupt 1{}    /* not used */


void extern1_ISR() interrupt 2{}    /* not used */


void timer1_ISR () interrupt 3{}    /* not used */


void serial_ISR () interrupt 4{}    /* not used */


2. 通用存储工作区


3. 选通用存储工作区由using x声明,见上例。


4. 指定存储模式


small compact 及large说明,例如:


void fun1(void) small {  }


提示:small说明的函数内部变量全部使用内部RAM。关键的经常性的耗时的地方可以这样声明,以提高运行速度。


5. #pragma disable


在函数前声明,只对一个函数有效。该函数调用过程中将不可被中断。


6. 递归或可重入函数指定


在主程序和中断中都可调用的函数,容易产生问题。因为51和PC不同,PC使用堆栈传递参数,且静态变量以外的内部变量都在堆栈中;而51一般使用寄存器传递参数,内部变量一般在RAM中,函数重入时会破坏上次调用的数据。可以用以下两种方法解决函数重入:


a、在相应的函数前使用前述“#pragma disable”声明,即只允许主程序或中断之一调用该函数;


b、将该函数说明为可重入的。如下:


void func(param...) reentrant;


KeilC51编译后将生成一个可重入变量堆栈,然后就可以模拟通过堆栈传递变量的方法。


由于一般可重入函数由主程序和中断调用,所以通常中断使用与主程序不同的R寄存器组。


另外,对可重入函数,在相应的函数前面加上开关“#pragma noaregs”,以禁止编译器使用绝对寄存器寻址,可生成不依赖于寄存器组的代码。


7. 指定PL/M-51函数


alien指定。



 



第二章 Keil C51软件使用详解(转帖)

发表于 2009/2/9 8:27:07


第一节 Keil C51编译器的控制指令


C51编译器的控制指令分为三类:源文件控制类,目标文件控制类及列表控制类。


1. 源文件控制类


NOEXTEND:C51源文件不允许使用ANSI C扩展功能。


DEFINE(DF):定义预处理(在C51命令行)。


2. 目标文件(Object)控制类:


 COMPACT LARGE SMALL 选编译模式


 DEBUG(DB) 包含调试信息,以供仿真器或dSCope51使用。


 NOAMAKE(NOAM)  禁止AutoMake信息记录


 NOREGPARMS  禁止用寄存器传递参数


 OBJECTEXTEND(OE)  Object文件包含附加变量类型信息


 OPTIMIZE(OT)  指定优化级别


 REGFILE(RF)  指定一个寄存器使用的文件以供整体优化用


 REGISTERBANK(RB)  指定一个供绝对寄存器访问的寄存器区名


 SRC  不生成目标文件只生成汇编源文件


       其它控件不常用。


3. 列表文件(listing)控制类:


 CODE(CD):向列表文件加入汇编列表


 LISTINCLUDE(LC):显示indude文件


 SYMBOLS(SB):列表文件包括模块内所有符号的列表


 WARNINGLEVEL(WL):选择“警告”级别


第二节 dScope51的使用


1. dScope51 for Dos


    总的来说dScope51具有以下特性:


l        高级语言显示模式


l        集成硬件环境模拟


l        单步或“GO”执行模式


l        存储器、寄存器及变量访问


l        Watch表达式之值


l        函数与信号功能


下面,具体说明在进入dScope51 for Dos之后,如何实现上述功能,dScope51采用下拉菜单格式和窗口显示控制,共有language、serial、exe、register四个窗口,其中exe为命令行窗口,language为程序窗口,serial为串口窗,register为寄存器窗。


(1) 高级语言显示模式


单击主菜单中的“View”,第一栏中的三条命令“Highlevel”、“Mixed”、“Assembly”分别对所装入的程序按照“高级”、“混合级”及“汇编级”三种方式显示,以方便调试使用。


(2) 集成硬件环境模拟显示


主菜单中“Peripheral”各条能显示模拟硬件环境的状态,其中:


i/o Port:显示各I/O口之值,对8031而言SFR中的P1、P2、P3、P0与引脚之值分别列出:


Interrupt:显示5个中断源的入口模式是否允许,优先级等中断状态。


Timer:显示各定时/计数器的模式,初始值状态等。


int Message:中断信息允许,如为允许(“>>”出现),则当中断申请时,显示中断源信息。比如当中断发生时会显示:


    interrupt Timer 0 occured”等


    A/D converter:


       显示A/D转换器状态无时,则提示“无”。


    Serial:串口信息显示,包括串口模式、波特产等


    Other:其它器件,如为8031则显示“ 无”


(3) 单步或“Go”执行


F8”单步执行,“F5”全速执行到断点。或选主菜单中Trace单步执行CPU中的Go全速执行。


(4) 存储器寄存器及变量访问


外部存储器管理MAP菜单:设置(set)、取消(reset)、显示(Display)处理可用存储空间。


修改Code代码:ASM命令


存储器显示命令:D  类别为(X、D、I、B、C)


修改存储器命令:E  有以下几种命令EB、EC、EI、EL、EF、EP


复杂数据类型显示:Object命令;用以显示结构或数组的内容。欲使此命令有效,C51编译器必须有DB及OBJECTEXTEND两条。


反汇编命令:U


(5) Watch”表达式之值


View菜单的“Watch”一栏中有四项:其中包括定义Watch Point(Define)、删除Watch Point(remove,kill all),及自动更新选项。


也可用WS、WK等命令代替,下面具体看“表达式”类型:


dScope51一次最多可设16个WtchPoint表达式,显示于Watch Window之中,表达式可以是简单变量,也可是复杂数据类型如结构、数组和指向结构的指针等,例如:


>WS  *ptime


>WS  ptime→hour


>WS  some_record[o],analog等等


(6) 关于.IOF文件


启动DS51后必须装入.IOF文件才能使CPU及Peripheral各项起作用,这个函数的使用是依据8051系列CPU的不同特点,装入8051各CPU硬件设备模拟驱动文件,比如8031CPU就必须load DS51目录下的8051.IOF。


2. dScope for Windows


dScope for windows具有dScope for dos的全部功能,此外,它还具有以下明显的优点:


 (1) 标准的Windows界面,操作更容易更简单;  


 (2) 常用操作多用对话框,而非Dos的行命令方式;


 (3) 窗口资源更加丰富:存储器窗口、覆盖率分析、运行状态分析窗口,加强了调试功能;


因为dScope for Windows功能强大,具体操作在第八章详细介绍。


第三节 Monitor51及其使用


1. Monitor51对硬件的要求


    (1) 硬件系统为51系列CPU;


    (2) 带5K外部程序存储器(从O地址开始),存放Monitor51程序;


    (3) 256Bytes的外部数据存储器以及5K的跟踪缓冲区,此外,外部数据存储器必须足够容纳所有应用程序代码及数据,且所有外部数据存储器必须为冯·诺伊曼存储器,即能一致访问XDATA与Code空间。


    (4) 一个定时器作为波特率发生器供串口使用;


    (5) 6 Bytes的空余堆栈。


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. MON51的配置


    (1) MON51 for Dos的配置


    运行install文件(在MON51目录下),不同的参数可以配置不同的硬件环境。INSTALL Serialtype [xdstastart[codestart[bank][PROMCHECK]]],具体说明见MON51帮助文件或使用手册。


    (2) MON51 for Windows的配置


    在启用MON51.dll时,会使得系统自动检查目标板连接,如配置不对,则弹出“Configuration”对话框,设置PC串口,波特率等,完毕单击“apply”有效。


4. 串口连接图:


收发交叉互连,RTS、CTS直连,DSR、DTR直连,具体引脚排列参考串口资料。


5. MON51命令及使用


详细的MON51命令可参阅帮助。


第四节 集成开发环境(IDE)的使用


1. Ishell for Dos的使用


进入Ishell之后看到两个窗口:一个是文件窗口,一个是Dos命令行窗口,窗口上方是下拉式的命令菜单,其中的Files控制文件窗口的显隐。


使用Ishell,第一步就是配置系统,即要学习两个文件的修改与创建:


(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) IShell.col文件


IDE颜色设置,如不改动,可以缺省为主。


(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. 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处理,具体使用可参考后面的例子。



 



第一章 Keil C51开发系统基本知识(转帖)

 


第一节 系统概述


Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。


Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。


下面详细介绍Keil C51开发系统各部分功能和使用。


第二节 Keil C51单片机软件开发系统的整体结构




(1)  C51工具包整体结构图


C51工具包的整体结构,如图(1)所示,其中uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。开发人员可用IDE本身或其它编辑器编辑C或汇编源文件。然后分别由C51及A51编译器编译生成目标文件(.OBJ)。目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中。







第三节 Keil C51工具包的安装


1. C51 for Dos


Windows下直接运行软件包中DOS\C51DOS.exe然后选择安装目录即可。完毕后欲使系统正常工作须进行以下操作(设C:\C51为安装目录):


修改Autoexec.bat,加入


path=C:\C51\Bin


Set  C51LIB=C:\C51\LIB


Set  C51INC=C:\C51\INC


然后运行Autoexec.bat


2. C51 for Windows的安装及注意事项:


Windows下运行软件包中WIN\Setup.exe,最好选择安装目录与C51 for Dos相同,这样设置最简单(设安装于C:\C51目录下)。然后将软件包中crack目录中的文件拷入C:\C51\Bin目录下。


第四节 Keil C51工具包各部分功能及使用简介


1. C51与A51


(1) C51


C51是C语言编译器,其使用方法为:


C51  sourcefile[编译控制指令]


或者


C51 @ commandfile


其中sourcefile为C源文件(.C)。大量的编译控制指令完成C51编译器的全部功能。包控C51输出文件C.LST,.OBJ,.I和.SRC文件的控制。源文件(.C)的控制等,详见第五部分的具体介绍。


Commandfile为一个连接控制文件其内容包括:.C源文件及各编译控制指令,它没有固定的名字,开发人员可根据自己的习惯指定,它适于用控制指令较多的场合。


(2) A51


A51是汇编语言编译器,使用方法为:


A51 sourcefile[编译控制指令]


A51  @ commandfile


其中sourcefile为汇编源文件(.asm或.a51),而编译控制指令的使用与其它汇编如ASM语言类似,可参考其他汇编语言材料。


Commandfile同C51中的Commandfile类似,它使A51使用和修改方便。


2. L51和BL51


(1) L51


L51是Keil C51软件包提供的连接/定位器,其功能是将编译生成的OBJ文件与库文件连接定位生成绝对目标文件(.ABS),其使用方法为:


        L51   目标文件列表[库文件列表] [to outputfile] [连接控制指令]


  L51   @Commandfile


源程序的多个模块分别经C51与A51编译后生成多个OBJ文件,连接时,这些文件全列于目标文件列表中,作为输入文件,如果还需与库文件(.LiB)相连接,则库文件也必须列在其后。outputfile为输文件名,缺少时为第一模块名,后缀为.ABS。连接控制指令提供了连接定位时的所有控制功能。Commandfile为连接控制文件,其具体内容是包括了目标文件列表,库文件列表及输出文件、连接控制命令,以取代第一种繁琐的格式,由于目标模块库文件大多不止1个,因而第2种方法较多见,这个文件名字也可由使用者随意指定。


(2) Bl51


BL51也是C51软件包的连接/定位器,其具有L51的所有功能,此外它还具有以下3点特别之处:


    a. 可以连接定位大于64kBytes的程序。


    b. 具有代码域及域切换功能(CodeBanking & Bank Switching)


    c. 可用于RTX51操作系统


RTX51是一个实时多任务操作系统,它改变了传统的编程模式,甚至不必用main( )函数,单片机系统软件向RTOS发展是一种趋势,这种趋势对于186和386及68K系列CPU更为明显和必须,对8051因CPU较为简单,程序结构等都不太复杂,RTX51作用显得不太突出,其专业版软件PK51软件包甚至不包括RTX51Full,而只有一个RTX51TINY版本的RTOS。RTX51 TINY适用于无外部RAM的单片机系统,因而可用面很窄,在本文中不作介绍。Bank switching技术因使用很少也不作介绍。


3. DScope51,Tscope51及Monitor51


(1) dScope51


dScope51是一个源级调试器和模拟器,它可以调试由C51编译器、A51汇编器、PL/M-51编译器及ASM-51汇编器产生的程序。它不需目标板(for windows也可通过mon51接目标板),只能进行软件模拟,但其功能强大,可模拟CPU及其外围器件,如内部串口,外部I/O及定时器等,能对嵌入式软件功能进行有效测试。


其使用方法为:


        DS51[debugfile][INIT(initfile)]


其中debugfile是一个Hex格式的8051文件,即待调试的文件其为可选的,可在进入dScope51后用load命令装入。


Initfile为一个初使化文件,它在启动dScope51后,在debugfile装入前装入,装有一些dScope的初使化参数及常用调试函数等。下面是一个dScope.ini文件(for dos)的内容:


  Load ..\..\ds51\8051.iof


  Map 0,0xffff


dScope51 for Windows则直接用鼠标进入,然后用load装入待调文件。


(2) tScope51


dScope51不同的是Scope51必须带目标板,目前它可以通过两种方式访问目标板。(1) 通过EMul51在线仿真器,tScope51为该仿真器准备了一个动态连接文件EMUL51.IOT,但该方法必须配合该仿真器。(2) 通过Monitov51监控程序,这种方法是可行的,tScope51为访问Monitor51专门带有MON51.IOT连接程序,使用时可通过串口及监控程序来调试目标板。


其使用方法为:


    TS51[INIT(file_name.ini)]


其中file_name.ini为一个初使化文件。


进入TS51后,必须装入IOT文件,可用的有MON51.IOT及EMUL51.IOT两种,如装入MON51.IOT:


Load.C:\C51\TS51\MON51.IOT  CPUTYPE(80517)


可惜的是tScope51只有for Dos的版本。


(3) Monitor 51


Monitor51是一个监控程序通过PC机的串口与目标板进行通信,Monitor操作需要MON51或dScope51 for Windows,后面部分将对Monitor51做较为详细的介绍。


4. Ishell及uVision


(1) Ishell for Dos


这是一个for Dos的IDE,直接在命令行键入Ishell,则进入该环境,它使用简单方便。其命令行与DOS命令行具有同样的功能,对单模块的Project直接由菜单进行编译连接,对多模块的project。则通过批处理,BAT文件进行编译连接,然后通过菜单控制由dScope51或tScope51对程序进行调试,因为是for dos的,不做太详细介绍。


(2) uVision for Windows


uVision for Windows是一个标准的Windows应用程序,它是C51的一个集成软件开发平台,具有源代码编辑、project管理、集成的make等功能,它的人机界面友好,操作方便,是开发者的首选,具体配置及使用见第五部分。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条