刚才看到一位很牛的师兄写的一篇日志中提到了Keil C51中using这个关键字的用法,粗心的我本来一直都没有留意它是用来干嘛的(因为我一般看见它都是在中断服务函数的定义开头处,好像没有了它也可以中断呀,所以才没怎么管),然而在日志中有看到这个关键字,所以也考究了一下,突然发现,原来这个东东和我最近在帮一个同学调的一个程序的时候突然遇到一个很怪的问题是有关系的,而且就是因为它才搞得程序莫明奇妙的出错(因为编译通过了,看起来也没什么错误,按C语言的逻辑分析也分析不出个什么所以然来,所以才怪)。
后来调试了好久,甚至到http://www.51hei.com/keil%CF%C2%D4%D8.html 这里下载了好几个版本的keil,反汇编代码看了N次,基本各个版本出来的结果都差不多,不知情的情况下,推断出是Keil C51的编译器问题,以为Keil C51的编译器的变量空间分配出问题了,R7本来是用来作参数传递的,却也被编译器分配用来在主函数中被用来作循环变量,结果就是循环变量的汇编判断指令CJNE指令执行前,R7的值(也就是循环变量)被改变了,导致判断R7总是不能达到循环设置的值,就不断地在循环,也就致使按键扫描去抖动这个延时循环无法完成,就导致延时后的第二次判断无法进行,自然按键下来也就没反应了。后来尝试着关了定时器中断,又可以了,那就可以肯定是在执行CJNE前,R7的值被改变了,就是因为跳到了中断,然后中断函数执行的过程中,R7值被改变了(因为中断函数中还调用了其它的函数,而R7后来被分析反汇编代码时发现是被用作参数传递的),中断执行完后R7的值当然不正确啦!
得出推断后我的解决办法就是:让C51编译好之后手动修改汇编的指令,不要直接使用寄存器来作循环变量,而是使用能实现间接寻地址的R1进行间接寻址(指向0x77)的方式,终于把问题解决了,因为0x77在执行中断函数的过程中没被修改,CJNE语句能正常判断了,循环能完成了,按键也能扫下来了,问题也可以解决了。后来我又想到用_at_关键字直接指定循环变量的分配地址,这样的话就不用手动改汇编指令了,编译器直接就是编译成使用间接寻址的,这也算解决了。但还是有个疑问,为什么编译器会不够聪明地把R7的空间分配错了呢?一直在疑问。。。。。。奇怪,怎么编译器会出这种问题?
直到我刚才考究过了using的用法之后,才发现原来自己的推断是错的,结论的总方向还是对的,只是问题并不在编译器身上,真正的问题根源如下:
1.我的同学写的那个程序,用到了定时器0,它的中断服务函数定义是这样写的:
{ ........//一大串大代码,其中包括调用了其他函数,用到了R7作参数传递 }
这里就是加了个using 0,而问题就出在加了这个using 0,为什么?且听我的理解:
using关键字的作用就是指定某个函数在执行时切换寄存器组的:
51中有四个寄存器组,每个组有R0-R7这8个寄存器,用于CPU的数据处理,一般主函数main()默认使用第0组,因为PSW寄存器的初始值的第3、4位是00嘛,即默认指定了第0组。using 0就是指定在执行函数时切换为使用第0组,不加using关键字的话,一般都默认使用第0组,但这样的话在调用其他函数(包括中断服务函数)的时候,就会加入一些压栈指令以保护原来的R0-R7寄存器的(这样的话,程序执行会效率会低一点,因为会产生很多个指令是用来压栈出栈的),照这样说,只是加了using 0,使用的也是第0组又不是其它的组,程序就不应该有问题了吧,但是就是因为加了using 0,编译了一次,才发现在定时器中断函数t0()的入口中并没有发现把R0-R7的代码压入栈呀,就是说没有保护好R7呀,那当然就是在执行完之后回来R7不能回复原来的值啦,接下来的事情。。。。我就不说啦,这就是问题的根源,去掉using 0就可以了,编译器就自动帮你将R0-R7压栈,手动加了using 0,就是让编译器以为之前用的并不是第0组,而现在执行这个中断函数时就切换到第0组,而省去了将R0-R7这8个寄存器压入栈的指令了,这样虽然看起来是快了,然而对于这个程序来说却是致命的问题!!!因为根本没有保护好R0-R7,而没有保护R7并不是我预期发生的!!!这不是编译器的问题,是自己没有了解好、用好using的问题啊!还有,其实也可以在编译器选项里有选项来硬性规定编译器统一不直接使用寄存器而是使用间接寻址的办法来改变循环变量分配的地址的,或者使用
#pragma NOAREGS ;定义函数 #pragma AREGS
来规定某个函数的是这样子。
当然,这样的规定和使用using本身并不冲突,只是使用了这个关键字后就可能会间接地产生一系列的问题,让人郁闷了这么久,其实本来如果有详细地看整个程序的反汇编代码,或许当时就会发现发现少了那段压栈指令了,而不是说推断为编译器分配空间的问题了。。。。。。。。希望我的这次教训对各位有所帮助!!!
另外,using的用法,其实就是手动指定函数使用的寄存器组,用得不好,如果在中断里还有调用其它函数,用得不好会出现函数传递出错的,不信可以反汇编看看,建议如果对这个关键字用法和C51的结构及汇编不熟的话,请还是让C51编译器帮你好了,不要胡乱使用,因为会比较容易出错的,要切记哦!!!其实用using关键到底对在编译后会造成什么影响,建议自己亲自去查看汇编程序。
关于Keil C51中using关键字的使用心得的更多相关文章
-
Keil C51中函数指针的使用
函数指针在C语言中应用较为灵活.在单片机系统中,嵌入式操作系统.文件系统和网络协议栈等一些较为复杂的应用都大量地使用了函数指针.Keil公司推出的C51编译器是事实上80C51 C编程的工业标准,它针 ...
-
KEIL C51中const和code的使用
code是KEIL C51 扩展的关键字,用code修饰的变量将会被放到CODE区里.但C语里的const关键字好像也有定义不能改变的变量的功能,这两个关键字有什么区别呢?在帮助手册里查找const, ...
-
KEIL C51 中嵌入汇编以及C51与A51间的相互调用
如何在 KEIL C51(v6.21) 中调用汇编函数的一个示例 有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者通过一个简单例子 ...
-
Keil C51中变量的使用
引言 8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量的使用 ...
-
Keil C51 中指针的使用
指针是C语言中比较难的一个内容,Keil C51在指针方面有和标准C不一样的地方,今天看了一些资料学习了一下Keil C51 中指针的使用. keil51的指针,包含两种指针:普通指针,兼容标准C:内 ...
-
C51中的关键字和ANSIC标准关键字
C51中的关键字和ANSIC标准关键字 作 者:武力戡乱 修改日期:2017-09-05 备 注: 1.总备注信息 2.联系方式 3.其它博文链接:武力戡乱博客目录总表 内 ...
-
[51单片机] Keil C51中变量的使用方法详解
引言 8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量 ...
-
Hash查找法在Keil C51中的实现
摘要:散列(hash)是一种重要的存储方法,也是一种常见的查找方法.它是指在记录的存储位置和它的关键字之间建立一个确定的对应关系.本文以射频卡门禁控制器为例,说明用射频卡卡号作为关键字,用Hash查找 ...
-
Keil C51 中的函数指针和再入函数
函数指针是C语言中几个难点之一.由于8051的C编译器的独特要求,函数指针和再入函数有更多的挑战需要克服.主要由于函数变量的传递.典型的(绝大部分8051芯片)函数变量通过堆栈的入栈和出栈命令来传递. ...
随机推荐
-
平常看到的Alt+xx 快捷键用法
1. 先按Alt, 哪一个菜单对应的字符是有划线的. 2. 输入对应的字符打开相应的菜单, 3 再输入相应的字符打开子菜单
-
Jq_Ajax 操作函数跟JQuery 遍历函数跟JQuery数据操作函数
JQuery文档操作方法 jQuery 库拥有完整的 Ajax 兼容套件.其中的函数和方法允许我们在不刷新浏览器的情况下从服务器加载数据. 函数 ...
-
Windows bat with adb
/********************************************************************* * Windows bat with adb * 说明: ...
-
安卓任意两个或多个Fragment之间的交互与刷新界面
平时项目中遇到一个问题:在子fragment中刷新父fragment的界面,通俗的说也就是在任何一个fragment中来刷新另一个fragment.大家都知道activity和fragment之间的交 ...
-
sim卡中短信简要格式
//SELECT A0 A4 00 00 02 3F 00 9F 17 //A0 A4 00 00 02 是命令头,CLA = A0表示GSM应用,INS = A4 表示SELECT,P1 P2 = ...
-
使用python发送QQ邮件
这里用到了Python的两个包来发送邮件: smtplib 和 email . Python 的 email 模块里包含了许多实用的邮件格式设置函数,可以用来创建邮件“包裹”.使用的 MIMEText ...
-
spring 事务无效解决方法
(原) spring 事务目前有二种,注解式和声明式,以前都是以公司里的框架写好的,没有学习的机会,今天抽空好好试了下,结果遇到好多问题. 1.注解式 最开始是这么玩的,发现数据进数据库了,没有起作用 ...
-
Xcode8出现的一些常见问题
消除无用输出语句问题:Xcode8之后,新创建的项目在手机上运行后,就会在输出窗口,输出一大堆乱七八糟的日志,对我们几乎没有用,如图: 解决办法: [product]-[scheme]-[Edit S ...
-
洛谷P3602 Koishi Loves Segments(贪心,multiset)
洛谷题目传送门 贪心小水题. 把线段按左端点从小到大排序,限制点也是从小到大排序,然后一起扫一遍. 对于每一个限制点实时维护覆盖它的所有线段,如果超过限制,则贪心地把右端点最大的线段永远删去,不计入答 ...
-
mysql中if()函数使用
博主原创,转载请注明出处: 在mysql中if()函数的用法类似于java中的三目表达式,其用处也比较多,具体语法如下: IF(expr1,expr2,expr3),如果expr1的值为true,则返 ...