




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Keil C51的一些有趣特性时间:2005-06-02 15:16:00 来源:侃单片机 作者:yanfengzhu首先得说的是我是菜鸟,在此论坛上学了很多的东东。但是今年以来,论坛上似乎没有了去年一大帮高手讨论问题的场面了,似乎失去了往日的风光了。在此我那出我近日一些不成熟的想法,希望大家斧正。有啥不正确的,请一定告之与我。Keil C51的一些有趣特性作者:yanfengE-mail:Keil c51号称作为51系列单片机最好的开发环境,大家一定都很熟悉。它的一些普通的特性大家也都了解,(书上也都说有)如:因为51内的RAM很小,C51的函数并不通过堆栈传递参数(重入函数除外),局部变量也不存储在堆栈中,而是存在于固定的RAM中及寄存器中。那么看一下下面的程序。void fun1(unsigned char i) 正常情况参数i通过R7传入函数,那么它的实际地址在什么地方呢?就是R7吗?回答这个问题之前我们先来了解keil c51的几个有趣的特性(不考虑重入函数)。一、 函数在调用前定义与在调用后定义产生的代码是有很大差别的(特别是在优化级别大于3级时)。(本人也不太清楚为什么,大概因为在调用前定义则调用函数已经知道被调用函数对寄存器的使用情况,则可对函数本身进行优化;而在调用后进行定义则函数不知被调用函数对寄存器的使用情况,它默认被调用函数对寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)都已经改变,因此不在这些寄存器中存入有效的数据)二、 函数调用函数时除在堆栈中存入返回地址之外,不在堆栈中保存其它任何寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)的内容。(除非被调用函数使用了using特性)三、 中断函数是一个例外,它会计算自身及它所调用的函数对寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)的改变,并保存相应它认为被改变了的寄存器。四、 使用C写程序时,尽量少使用using n (n=0,1,2,3)特性。(这个特性在本人使用的过程中存在一些问题,不知算不算是一个小bug)以下的试验都是在(环境 keil c51 v7.20)中,优化级为default下完成。先看第一个特性问题。例1:void fun2(void)void fun1(unsigned char i) fun2(); while(i-);它的汇编代码如下:; void fun2(void) RSEG ?PR?fun2?TESTfun2: ; SOURCE LINE # 12; ; SOURCE LINE # 13; ; SOURCE LINE # 14 RET ; END OF fun2; ; void fun1(unsigned char i) RSEG ?PR?_fun1?TEST_fun1: USING 0 ; SOURCE LINE # 16;- Variable i?240 assigned to Register R7 -; ; SOURCE LINE # 17; fun2(); ; SOURCE LINE # 18 LCALL fun2?C0003:; while(i-); ; SOURCE LINE # 19 MOV R6,AR7 DEC R7 MOV A,R6 JNZ ?C0003; ; SOURCE LINE # 20?C0005: RET ; END OF _fun1从中可以看到fun2()在fun1()前先定义,fun1()知道fun2()对寄存器的使用情况,知道R7没有改变,而参数i存于R7中,即i既是R7。(;- Variable i?140 assigned to Register R7 -)看另一情况void fun2(void);void fun1(unsigned char i) fun2(); while(i-);void fun2(void)汇编代码如下:; void fun1(unsigned char i) RSEG ?PR?_fun1?TEST_fun1: USING 0 ; SOURCE LINE # 14 MOV i?140,R7; ; SOURCE LINE # 15; fun2(); ; SOURCE LINE # 16 LCALL fun2?C0002:; while(i-); ; SOURCE LINE # 17 MOV R7,i?140 DEC i?140 MOV A,R7 JNZ ?C0002; ; SOURCE LINE # 18?C0004: RET ; END OF _fun1; ; void fun2(void) RSEG ?PR?fun2?TESTfun2: ; SOURCE LINE # 20; ; SOURCE LINE # 21; ; SOURCE LINE # 22 RET ; END OF fun2fun2()在fun1()调用后定义,因fun1()调用fun2()时不知道fun2()对寄存器的使用情况,则认为fun2()改变了所有的寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、, R6、 R7)。因为fun1()认为fun2()改变了寄存器的值(包括R7),因此i虽然通过R7传递,但因已因调用fun2()而改变,所以不能再存在R7了,而上在RAM中额外的用一个Byte来存储。这也就解释了在开始时的那个问题,参数i的存储是看问题而定的。哈哈,是否很有趣呢。在节约RAM方面,这可是一个很有用的特性哦。(大家是否也为自己的节省了1Byte的RAM)这个例子还解释了第二个特性,函数调用函数时除在堆栈中存入返回地址之外,不在堆栈中保存其它任何寄存器(ACC、 B、 DPH、 DPL、 PSW、 R0、 R1、 R2、 R3、R 4、 R5、R6、R7)的内容。函数在调用函数前,尽量不在这些寄存器中保存有效的数据,实在无法避免,则把有效数据存入固定的RAM中。对于中断函数问题,当你看到下面的程序相差55 Byte时,不知你会怎么想的。例2:void OSTimeDly(void); /using 1static void Timer0OVInt(void) interrupt 1 /using 1 TR0 = 0; TH0 = 100; TL0 = 100; TR0 = 1; OSTimeDly();void OSTimeDly(void) /using 1与void OSTimeDly(void) /using 1static void Timer0OVInt(void) interrupt 1 /using 1 TR0 = 0; TH0 = 100; TL0 = 100; TR0 = 1; OSTimeDly();它们的汇编代码分别是,; static void Timer0OVInt(void) interrupt 1 /using 1 RSEG ?PR?Timer0OVInt?TEST USING 0Timer0OVInt: PUSH ACC PUSH B PUSH DPH PUSH DPL PUSH PSW MOV PSW,#00H PUSH AR0 PUSH AR1 PUSH AR2 PUSH AR3 PUSH AR4 PUSH AR5 PUSH AR6 PUSH AR7 USING 0 ; SOURCE LINE # 24; ; TR0 = 0; ; SOURCE LINE # 26 CLR TR0; TH0 = 100; ; SOURCE LINE # 27 MOV TH0,#064H; TL0 = 100; ; SOURCE LINE # 28 MOV TL0,#064H; TR0 = 1; ; SOURCE LINE # 29 SETB TR0; ; OSTimeDly(); ; SOURCE LINE # 31 LCALL OSTimeDly; ; SOURCE LINE # 32 POP AR7 POP AR6 POP AR5 POP AR4 POP AR3 POP AR2 POP AR1 POP AR0 POP PSW POP DPL POP DPH POP B POP ACC RETI ; END OF Timer0OVInt; ; ; void OSTimeDly(void) /using 1 RSEG ?PR?OSTimeDly?TESTOSTimeDly: ; SOURCE LINE # 35; ; SOURCE LINE # 36; ; ; SOURCE LINE # 38 RET ; END OF OSTimeDly及; void OSTimeDly(void) /using 1 RSEG ?PR?OSTimeDly?TESTOSTimeDly: ; SOURCE LINE # 22; ; SOURCE LINE # 23; ; ; SOURCE LINE # 25 RET ; END OF OSTimeDlyCSEG AT 0000BH LJMP Timer0OVInt; ; static void Timer0OVInt(void) interrupt 1 /using 1 RSEG ?PR?Timer0OVInt?TEST USING 0Timer0OVInt: ; SOURCE LINE # 27; ; TR0 = 0; ; SOURCE LINE # 29 CLR TR0; TH0 = 100; ; SOURCE LINE # 30 MOV TH0,#064H; TL0 = 100; ; SOURCE LINE # 31 MOV TL0,#064H; TR0 = 1; ; SOURCE LINE # 32 SETB TR0; ; OSTimeDly(); ; SOURCE LINE # 34 LCALL OSTimeDly; ; SOURCE LINE # 35 RETI ; END OF Timer0OVInt这个例子的汇编代码很好的解释了上面的特性1及3。至于第四个特性,值得特别说明一下。看下例:例3:void OSTimeDly(void);static void Timer0OVInt(void) interrupt 1 using 0 TR0 = 0; TH0 = 100; TL0 = 100; TR0 = 1; OSTimeDly();void OSTimeDly(void) / using 0它的汇编代码是; static void Timer0OVInt(void) interrupt 1 using 0 RSEG ?PR?Timer0OVInt?TEST USING 0Timer0OVInt: PUSH ACC PUSH B PUSH DPH PUSH DPL PUSH PSW USING 0 MOV PSW,#00H ; SOURCE LINE # 24; ; TR0 = 0; ; SOURCE LINE # 26 CLR TR0; TH0 = 100; ; SOURCE LINE # 27 MOV TH0,#064H; TL0 = 100; ; SOURCE LINE # 28 MOV TL0,#064H; TR0 = 1; ; SOURCE LINE # 29 SETB TR0; ; OSTimeDly(); ; SOURCE LINE # 31 LCALL OSTimeDly; ; SOURCE LINE # 32 POP PSW POP DPL POP DPH POP B POP ACC RETI ; END OF Timer0OVInt; ; void OSTimeDly(void) / using 0 RSEG ?PR?OSTimeDly?TESTOSTimeDly: ; SOURCE LINE # 34; ; SOURCE LINE # 35; ; ; SOURCE LINE # 37 RET ; END OF OSTimeDly此例中除了中断函数使用了using 0之外,与上例中的程序并无区别,但是汇编的代码相差却很大。此例中的汇编代码不再保存R0 - R7的值。(默认keil c51中的函数使用的是0寄存器组,当中断函数使用using n时,n = 1,2,3或许是对的,但n=0时,程序就已经存在了bug(只有中断函数及其所调用的函数并没有改变R0 - R7的值时,这个bug不会表现出来)一个结论是,在中断函数中如果使用了using n,则中断不再保存R0-R7的值。由此可以推论出,一个高优先级的中断函数及一个低优先级的中断函数同时使用了using n,(n = 0,1,2,3)当n相同时,这个存在的bug 是多么的隐蔽。(这恰是使人想象不到的)最后再来看一例例4:void OSTimeDly(unsigned char i);static void Timer0OVInt(void) interrupt 1 using 1 TR0 = 0; TH0 = 100; TL0 = 100; TR0 = 1; OSTimeDly(5);void OSTimeDly(unsigned char i) / using 0 while(i-);汇编的结果; static void Timer0OVInt(void) interrupt 1 using 1 RSEG ?PR?Timer0OVInt?TEST USING 1Timer0OVInt: PUSH ACC PUSH B PUSH DPH PUSH DPL PUSH PSW USING 1 MOV PSW,#08H ; SOURCE LINE # 25; ; TR0 = 0; ; SOURCE LINE # 27 CLR TR0; TH0 = 100; ; SOURCE LINE # 28 MOV TH0,#064H; TL0 = 100; ; SOURCE LINE # 29 MOV TL0,#064H; TR0 = 1; ; SOURCE LINE # 30 SETB TR0; ; OSTimeDly(5); ; SOURCE LINE # 32
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 农业种植劳务承包合同示例
- 二手房交易合同违约责任深度分析
- 人教版一年级上册数学 期末综合复习
- 居间服务中介费分成合同
- 涂料施工过程中的质量控制要点考核试卷
- 2024年04月江苏苏州市苏宿工业园区社区卫生服务中心招聘25人笔试历年专业考点(难、易错点)附带答案详解
- 渔业养殖饲料的环保型包装材料开发与应用考核试卷
- 呼吸衰竭的护理-图
- 控制系统的高级过程控制策略考核试卷
- 生物质燃气的农业废弃物利用与处理技术考核试卷
- 驾驶员月度安全会议签到表模板
- 种植甜叶菊的效益分析
- Unit5 A party (1) 课件 牛津译林版六年级下册英语
- 王阳明与心学
- 11楼11月份工程施工月进度计划表
- 高处作业安全监理实施细则
- 2019年度上海市小学生健康体检表
- 运用PDCA血透室导管感染率
- 马克思主义政治经济学概论
- 布地奈德福莫特罗粉吸入剂
- 《雷雨》课件2022-2023学年人教版高中语文必修四
评论
0/150
提交评论