打印

【原创】51定时器修正C语言代码(非汇编)

[复制链接]
2529|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
singleywy|  楼主 | 2010-11-5 18:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
为了得到与汇编一样高效的定时器修正代码,经过多次反编译修改后得到如下的代码
即:
“ACC=((65536+8-SYS_CLK)%256);
TR0=0;
TL0+=ACC;
ACC=0;
CY=ACC & 0x80;
ACC =((65536+8-SYS_CLK)/256)+ACC;
TH0+=ACC;
TR0=1;”
其中SYS_CLK为所定时的时间,这里默认的时钟为12MHZ,
本人在keil中,(我当时默认设置了5000)反编译之后得到的汇编的代码为:
MOV   A,#080H
CLR   TR0
ADD   A,TL0
MOV   TL0,A;TL0修正
CLR   A;清空ACC
RLC   A;保存CY到ACC中,即为TLO修正时的进位
ADD   A,#0ECH
ADD   A,TH0
MOV   TH0,A;TH0修正
SETB  TR0
看一下与Intel蓝本中汇编比较一下:
; // MOV A,#((65536-SYS_CLK+7) MOD 256)
; // CLR TR0
; // ADD A,TL0
; // MOV TL0,A
; // MOV A,TH0
; // ADDC A,#((65536-SYS_CLK+7 )/256)
; // MOV TH0,A
; //  SETB TR0
大家可以看到结果了吧,相比之下只有1条指令的差距
相对来说效率是很高,您可能会发觉这条语句:“ACC =((65536+8-SYS_CLK)/256)+ACC;”
为什么不用“ACC+ =((65536+8-SYS_CLK)/256)”
我原本以为这两句是一样的,可是编译器可不这样想,认为是两种不同的操作,这条指令编译后会将
ACC中的值清零,再与修正值相加,这样就得不到前面TL0修正时的进位CY了
呵呵,如果大家觉得不错就拿去用吧,省着用汇编修正了
欢迎大家到singleywy的个人博客:<a href="http://blog.21ic.com/user1/7823/archives/2010/77521.html">Singleywy</a>

相关帖子

沙发
singleywy|  楼主 | 2010-11-5 18:08 | 只看该作者
自己先顶一下,呵呵

使用特权

评论回复
板凳
dong_abc| | 2010-11-5 19:36 | 只看该作者
相对来说效率是很高,您可能会发觉这条语句:“ACC =((65536+8-SYS_CLK)/256)+ACC;”
为什么不用“ACC+ =((65536+8-SYS_CLK)/256)”

以上不一样?习惯用后一种!

使用特权

评论回复
地板
singleywy|  楼主 | 2010-11-5 20:39 | 只看该作者
3# dong_abc
恩,C语言里应该一样的,不过Keil中却认为是不同的操作,不信,你编译看看,用我上面的代码,反编译一下就能发现区别了

使用特权

评论回复
5
singleywy|  楼主 | 2010-11-5 20:41 | 只看该作者
我通常写C的时候,就是用习惯后一种的,代码简洁,不过现在才发现还要看编译器如何解释的

使用特权

评论回复
6
223178825| | 2010-11-5 21:31 | 只看该作者
学习了

使用特权

评论回复
7
流行音乐| | 2010-11-5 21:45 | 只看该作者
在C语言中修改 ACC 或 R0~R7 是一种冒险。

使用特权

评论回复
8
流行音乐| | 2010-11-5 21:47 | 只看该作者
你不知道什么时候就踩到地雷上了,例如楼主遇到的“ACC+=...”。

使用特权

评论回复
9
singleywy|  楼主 | 2010-11-5 22:12 | 只看该作者
8# 流行音乐 恩,一般情况下,我不会这么轻易去做的,因为可能造成数据的破坏,但是由于程序的需要,关键部分确实要精简一些,我通常都是通过反编译方式来查看,是否存在错误或其他东西

使用特权

评论回复
10
singleywy|  楼主 | 2010-11-5 22:16 | 只看该作者
我忘了加了部分代码,因为这段代码在中断中,自动保护了ACC,PSW,如果没有在中断中的话,
头文件需加上intrins.h
之后再这段前面加上如下代码:
_push_(PSW);
_push_(ACC);
ACC=((65536+8-SYS_CLK)%256);
TR0=0;
TL0+=ACC;
ACC=0;
CY=ACC & 0x80;
ACC =((65536+8-SYS_CLK)/256)+ACC;
TH0+=ACC;
TR0=1;
_pop_(ACC);
_pop_(PSW);

使用特权

评论回复
11
ayb_ice| | 2010-11-6 08:35 | 只看该作者
差之毫厘,失之千里

使用特权

评论回复
12
5880527| | 2010-11-6 11:57 | 只看该作者
不用暂时关闭定时器的,因为它一进来TH0,TL0本来就是0附近的数,根本不会发生进位,书本上的例子都是先关闭一下,搞不懂

使用特权

评论回复
13
singleywy|  楼主 | 2010-11-6 12:25 | 只看该作者
12# 5880527
请您仔细看一下代码,关闭定时器的时候可能TL0的值较小(如果系统进入critical section 即临界区,中断会发生无法预料的延迟,TL0,TH0还会是较小的值么),加上修正值后,很可能产生进位,所以是TH0加上进位是需要的,因为你不知道TL0的值是多少

使用特权

评论回复
14
5880527| | 2010-11-6 12:57 | 只看该作者
要修正就只能T0定时器中断是唯一的一个最高级中断,延迟的不确定性都是很小的几个机器周期,否则不如用T2的自动重装算了。其实这种修正跟步进电机的步距角不均匀有类似之处,修正无多大用处

使用特权

评论回复
15
upc_arm| | 2012-11-15 23:09 | 只看该作者
很好 顶! MARK一下

使用特权

评论回复
16
anazel| | 2012-11-16 09:03 | 只看该作者
编译器不同,同样的程序编译出来的代码也会不同吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

295

帖子

3

粉丝