KEILC使用总结大全.docx
《KEILC使用总结大全.docx》由会员分享,可在线阅读,更多相关《KEILC使用总结大全.docx(16页珍藏版)》请在冰点文库上搜索。
KEILC使用总结大全
KEILC使用总结大全
我们使用KeilC调试某系统时积累的一些经验
1、在Windows2000下面,我们可以把字体设置为Courier,这样就可以显示正常。
2、当使用有片外内存的MCU(如W77E58,它有1K片外内存)的时候,肯定要设置标志位,并且编译方式要选择大模式,否则会出错。
3、当使用KeilC跟踪程序运行状态的时候,要把引起Warning的语句屏蔽,否则有可能跟踪语句的时候会出错。
4、在调用数组的时候,KeilC是首先把数组Load进内存。
如果要在C中使用长数组的时候,我们可以使用code关键字,这样就实现了汇编的DB的功能,KeilC是不会把标志code的数组Load入内存的,它会直接读取Rom。
5、拉高管脚的执行速度远远比检查管脚电平的要快。
当编程涉及到有关通信,时序是很重要的。
6、在等待管脚电平变化的时候,我们需要设置好超时处理,否则程序就会因为一个没有预计的错误而死锁。
7、能用C语言实现的地方,尽量不要用汇编,尤其在算法的实现,用汇编是晦涩难懂。
8、程序的几个参数数组所占篇幅很大,其中液晶背景数组最长,有四千个Byte,因而把那些初始化数组都放在另外一个C文件,在主文件使用使用关键字extern定义,这样就不会对主文件的编写造成干扰。
9、所有函数之间的相关性越低越有利于以后功能的扩展。
10、6.20版在编译带code关键字的数组时,编译通过但是单片机运行结果是错误的,改用6.14版后正常。
------------------------------------------------------------------------------------------------------------------------------------------------------
问:
C51怎样将1个子程序段定位在1个固定的地址位置?
以下2问题均要用C51解决
1。
怎样将1个子程序段定位在1个固定的地址位置?
例如将INTBCD2HEX(INTXX)定位在1000H
2。
HOW在EEPROM中固定的位置存放1字符串?
如在200H处放“COPYRIGHT2001-11”
答:
函数定位与变量定位...
1、函数定位:
假如要把C源文件tools.c中的函数
intBIN2HEX(intxx)
{
...
}
放在CODEMEMORY的0x1000处,先编译该工程,然后打开该工程的M51文件,在
***CODEMEMORY***
行下找出要定位的函数的名称,应该形如:
CODExxxxHxxxxHUNIT?
PR?
_BCD2HEX?
TOOLS
然后在:
Project->OptionsforTarget...->BL51Locate:
Code
中填写如下内容:
?
PR?
_BCD2HEX?
TOOLS(0x1000)
再次Build,在M51中会发现该函数已放在CODEMEMORY的0x1000处了
2、赋初值的变量定位:
要将某变量定位在一绝对位置且要赋初值,此时用_at_不能完成,则如下操作:
在工程中建立一个新的文件,如InitVars.c,在其中对要处理的变量赋初值(假设是code变
量):
charcodemyVer={"COPYRIGHT2001-11"};
然后将该文件加入工程,编译,打开M51文件,若定义的是code型,则在
***CODEMEMORY***
下可找到:
CODExxxxHxxxxHUNIT?
CO?
INITVARS
然后在:
Project->OptionsforTarget...->BL51Locate:
Code
中填入:
?
CO?
INITVARS(0x200)
再次编译即可。
相应地,如为xdata变量,则InitVars.c中写:
charxdatamyVer={"COPYRIGHT2001-11"};
然后将该文件加入工程,编译,打开M51文件,在
***XDATAMEMORY***
下可找到:
XDATAxxxxHxxxxHUNIT?
XD?
INITVARS
然后在:
Project->OptionsforTarget...->BL51Locate:
Xdata
中填入:
?
XD?
INITVARS(0x200)
再次编译即可。
相应地,若定义的是data/idata等变量,则相应处理即可。
3、若有多个变量或函数要进行绝对地址定位,则应按地址从低到高的顺序排列。
------------------------------------------------------------------------------------------------------------------------------------------------------
C51的一些误区和注意事项
2005-11-249:
03:
43
1)C忌讳绝对定位。
常看见初学者要求使用_at_,这是一种谬误,把C当作ASM看待了。
在C中变量的定位是编译器的事情,初学者只要定义变量和变量的作用域,编译器就把一个固定地址给这个变量。
怎么取得这个变量的地址?
要用指针。
比如unsignedchardatax;后,x的地址就是&x,你只要查看这个参数,就可以在程序中知道具体的地址了。
所以俺一看见要使用绝对定位的人,第一印象就是:
这大概是个初学者。
2)设置SP的问题。
原因和1差不对,编译器在把所有变量和缓冲区赋予地址后,自动把最后一个字节开始的地方,作为SP的开始位置,所以初学者是不必要去理会的。
这体现C的优越性,很多事情C编译时候做了。
3)用C的主程序结构:
#includevoidmain(void){while
(1);}这是个最小的成功的C程序,包括头部文件和程序主体。
头部文件的名词解释:
引用的外部资源文件,这个文件包括了硬件信息和外部模块提供的可使用的函数和变量的说明。
可以用文本方式打开reg52.h,仔细研究下,会有一些写程序的体会。
4)这样构成一个C项目在C中,常用项目来管理。
项目一般分为两大块:
C文件块和头部文件块。
我们常把不同功能写在不同的C文件中,依靠项目的管理,最后把所有文件连接起来,这样就可以得到可以烧录的HEX文件或BIN文件。
这些C文件中,有且只有唯一一个包括main()函数,和3)中一样的C文件。
用头部文件把各个不同的C互相连接起来。
一个C文件基本上要对应有一个H头部文件,这个H文件就包含本C文件中可以提供给外面使用的变量和函数,没有在H文件中列出的文件,可以算是该C文件的内部函数和变量,外部C不能使用。
例子:
a.C:
unsignedchari;unsignedcharmWork;voidTest1(void){mWork;}voidTest2(void){i;}a.h文件中:
externunsignedchari;externvoidTest1(void);这样主程序M.c中:
#include/*C编译器内部自带的H文件,使用<>*/#include"a.h"/*自定义的H文件,一般用""*/voidmain(void){Test1();/*使用a.c模块文件中的函数*/while
(1){i;/*使用a.c模块文件中的变量*/}}
5)51家族核心都是基于8031的,有很多在此核心上进行扩展,有的把程序存储器放在内部:
89c(S)51..,有的增加了RAM:
89c(S)52..,有的增加了一些专用硬件80C552...,有的改变时钟时序W77E58...。
市面上现在常用的主要有ATMEL公司的AT89X系列,PHILIPS的P87(89)x,台湾WINBOND的w77(78)x系列,Cygnal的C8051Fx系列。
6)51单片机结构的C描述这里不讲51的具体结构,只是引导初学者快速理解51单片机的物理结构。
寄存器和IO及其它硬件设备的地址名称,在相应的C头部文件中可以找到。
51为reg51.h,52为reg52.h,以次类推,比如winbond的78E58就为w78e58.h这些H文件中的描述:
srf,定义一个8位的设备。
srf16,定义一个16位的设备。
sbit,定义一个位的设备。
用这些语句定义后,就可以在C中象汇编一样使用这些硬件设备,这是单片机应用比标准C特殊的地方,其它差别很少。
7)在51系列中data,idata,xdata,pdata的区别data:
固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。
idata:
固定指前面0x00-0xff的256个RAM,其中前128和data的128完全相同,只是因为访问的方式不同。
idata是用类似C中的指针方式访问的。
汇编中的语句为:
moxACC,@Rx.(不重要的补充:
c中idata做指针式的访问效果很好)xdata:
外部扩展RAM,一般指外部0x0000-0xffff空间,用DPTR访问。
pdata:
外部扩展RAM的低256个字节,地址出现在A0-A7的上时读写,用movxACC,@Rx读写。
这个比较特殊,而且C51好象有对此BUG,建议少用。
但也有他的优点,具体用法属于中级问题,这里不提。
8)startup.a51的作用和汇编一样,在C中定义的那些变量和数组的初始化就在startup.a51中进行,如果你在定义全局变量时带有数值,如unsignedchardataxxx=100;,那startup.a51中就会有相关的赋值。
如果没有=100,startup.a51就会把他清0。
(startup.a51==变量的初始化)。
这些初始化完毕后,还会设置SP指针。
对非变量区域,如堆栈区,将不会有赋值或清零动作。
有人喜欢改startup.a51,为了满足自己一些想当然的爱好,这是不必要的,有可能错误的。
比如掉电保护的时候想保存一些变量,但改startup.a51来实现是很笨的方法,实际只要利用非变量区域的特性,定义一个指针变量指向堆栈低部:
0xff处就可实现。
,为什么还要去改?
可以这么说:
任何时候都可以不需要改startup.a51,如果你明白它的特性。
关于在KEILC51中嵌入汇编以及C51与A51间的相互调用
如何在KEILC51(v6.21)中调用汇编函数的一个示例[ycong_kuang]
有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者
通过一个简单例子对这个过程进行描述,希望能对初学者有所帮助。
几年来,在这个论坛里笔者得到很多热心人指导,因此也希望
藉此尽一点绵薄之力。
在这个例子里,阐述了编写c51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是
一个整型变量。
例中,先用c51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所
要的汇编函数。
该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。
step1.按写普通c51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。
相关文件如下:
//main.c文件
#include
#defineucharunsignedchar
#defineuintunsignedint
externuintAFUNC(ucharv_achr,bitv_bflag);
voidmain()
{
bitBFLAG;
ucharmav_chr;
uintmvintrslt;
mav_chr=0xd4;BFLAG=1;
mvintrslt=AFUNC(mav_chr,BFLAG);
}
//CFUNC.c文件
#defineucharunsignedchar
#defineuintunsignedint
uintAFUNC(ucharv_achr,bitv_bflag)
{
uchartmp_vchr;
uinttp_vint;
tmp_vchr=v_achr;
tp_vint=(uint)v_bflag;
returntmp_vchr+(tp_vint<<8);
}
step2.在Project窗口中包含汇编代码的C文件上右键,选择“Optionsfor...”,点击右边的“GenerateAssemblerSRC
File”和“AssembleSRCFile”,使检查框由灰色变成黑色(有效)状态;
step3.根据选择的编译模式,把相应的库文件(如Small模式时,是Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工
程的最后文件;
step4.build这个工程后将会产生一个CFUNC.SRC的文件,将这个文件改名为CFUNC.A51(也可以通过编译选项直接产生CFUNC.A51文
件),然后在工程里去掉库文件(如C51S.Lib)和CFUNC.c,而将CFUNC.A51添加到工程里。
//CFUNC.SRC文件如下
.\CFUNC.SRCgeneratedfrom:
CFUNC.c
NAMECFUNC
?
PR?
_AFUNC?
CFUNCSEGMENTCODE
?
BI?
_AFUNC?
CFUNCSEGMENTBITOVERLAYABLE
PUBLIC?
_AFUNC?
BIT
PUBLIC_AFUNC
RSEG?
BI?
_AFUNC?
CFUNC
?
_AFUNC?
BIT:
v_bflag?
041:
DBIT1
;#defineucharunsignedchar
;#defineuintunsignedint
;
;uintAFUNC(ucharv_achr,bitv_bflag)
RSEG?
PR?
_AFUNC?
CFUNC
_AFUNC:
USING0
;SOURCELINE#5
;----Variable'v_achr?
040'assignedtoRegister'R7'----
;{
;SOURCELINE#6
;uchartmp_vchr;
;uinttp_vint;
;
;tmp_vchr=v_achr;
;SOURCELINE#10
;----Variable'tmp_vchr?
042'assignedtoRegister'R5'----
MOVR5,AR7
;tp_vint=(uint)v_bflag;
;SOURCELINE#11
MOVC,v_bflag?
041
CLRA
RLCA
;----Variable'tp_vint?
043'assignedtoRegister'R6/R7'----
;returntmp_vchr+(tp_vint<<8);
;SOURCELINE#12
MOVR6,A
MOVR4,#00H
CLRA
ADDA,R5
MOVR7,A
MOVA,R4
ADDCA,R6
MOVR6,A
;}
;SOURCELINE#13
?
C0001:
RET
;ENDOF_AFUNC
END
step5.检查main.c的“GenerateAssemblerSRCFile”和“AssembleSRCFile”是否有效,若是有效则点击使检查框变成无效状
态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。
参考文献:
1.徐爱钧,彭秀华。
单片机高级语言C51windows环境编程与应用,电子工业出版社
C51编程:
关于在KEILC51中直接嵌入汇编。
。
。
帖子编号:
83838发表用户:
Youth
------------------------------------------------------------------------------------------------------------------------------------------------------
keil中汇编函数调用c51函数[ycong_kuang]
在keil的写法可参考89852帖子,具体如下:
与89852帖子相比,第一步在工程里多了一个被汇编调用的c51的函数文件(c51func.c),至于汇编函数还是先用c51编写出主体
(a51func.c),这样汇编程序接口和段都交给编译器处理,你只管在编译成汇编代码后按你的要求改写汇编代码就行了。
例程如下:
//main.c
#include
#defineucharunsignedchar
#defineuintunsignedint
externuintAFUNC(ucharv_achr,bitv_bflag);
voidmain()
{
bitBFLAG;
ucharmav_chr;
uintmvintrslt;
mav_chr=0xd4;BFLAG=1;
mvintrslt=AFUNC(mav_chr,BFLAG);
}
//a51FUNC.c
#defineucharunsignedchar
#defineuintunsignedint
externuintCFUNC(uint);
uintAFUNC(ucharv_achr,bitv_bflag)//c51写的汇编函数,最终要变成汇编代码
{
uchartmp_vchr;
uinttp_vint;
tmp_vchr=v_achr;
tp_vint=(uint)v_bflag;
returnCFUNC(tp_vint);//这里调用一个c51函数
}
//c51FUNC.c
#defineucharunsignedchar
#defineuintunsignedint
uintCFUNC(uintv_int)//被汇编函数调用c51函数
{
returnv_int<<2;
}
第二步是按89852帖子的step2,3,4把用c51写的(汇编)函数变成a51文件(今天我试了一下step3可以不要)例程编译结果如
下:
;.\a51func.SRCgeneratedfrom:
a51func.c
NAMEA51FUNC
?
PR?
_AFUNC?
A51FUNCSEGMENTCODE
?
DT?
_AFUNC?
A51FUNCSEGMENTDATAOVERLAYABLE
?
BI?
_AFUNC?
A51FUNCSEGMENTBITOVERLAYABLE
EXTRNCODE(_CFUNC)
PUBLIC?
_AFUNC?
BIT
PUBLIC_AFUNC
RSEG?
DT?
_AFUNC?
A51FUNC
?
_AFUNC?
BYTE:
tmp_vchr?
042:
DS1
RSEG?
BI?
_AFUNC?
A51FUNC
?
_AFUNC?
BIT:
v_bflag?
041:
DBIT1
;//a51FUNC.c
;
;#defineucharunsignedchar
;#defineuintunsignedint
;
;externuintCFUNC(uint);
;
;uintAFUNC(ucharv_achr,bitv_bflag)
RSEG?
PR?
_AFUNC?
A51FUNC
_AFUNC:
;c51所写的函数产生的汇编代码从这里开始
USING0
;SOURCELINE#8
;----Variable'v_achr?
040'assignedtoRegister'R7'----
;{
;SOURCELINE#9
;uchartmp_vchr;
;uinttp_vint;
;
;tmp_vchr=v_achr;
;SOURCELINE#13
MOVtmp_vchr?
042,R7
;tp_vint=(uint)v_bflag;
;SOURCELINE#14
MOVC,v_bflag?
041
CLRA
MOVR6,A
RLCA
MOVR7,A
;----Variable'tp_vint?
043'assignedtoRegister'R6/R7'----
;这里说明R6,R7内容就是tp_vint
;returnCFUNC(tp_vint);
;SOURCELINE#16
LCALL_CFUNC;这里调用了用c51写的函数
;}
;SOURCELINE#17
?
C0001:
RET
;ENDOF_AFUNC
END
这个文件就是你的汇编函数所在文件,把函数里面的汇编代码修改成你所需的汇编函数就ok了。
建议参考徐爱钧,彭秀华所写的《单片机高级语言C51windows环境编程与应用》或马忠梅所写的
《单片机的c语言应用程序设计》有关混合语言编程有关章节
------------------------------------------------------------------------------------------------------------------------------------------------------
关于在KEILC51中直接嵌入汇编。
。
。
[Youth]
有时在C51程序中需要嵌入一些汇编代码,这时当然可以用通常的作法:
按照C51与汇编的接口写一个汇编函数,然后在C51程序中调用该函数。
(此种方法可在论坛里搜索,以前有很多帖子讲到,不再
重复)
下面介绍直接嵌入汇编代码的方法:
1、在C文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragmaASM
;AssemblerCodeHere
#pragmaENDASM
2、在Project窗口中包含汇编代码的C文件上右键,选择“Optionsfor...”,点击右边的“GenerateAssemblerSRCFile”
和“AssembleSRCFile”,使检查框由灰色变成黑色(有效)状态;
3、根据选择的编译模式,把相应的库文件(如Small模式时,是Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工程的最
后文