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

[复制链接]
 楼主| 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中却认为是不同的操作,不信,你编译看看,用我上面的代码,反编译一下就能发现区别了
 楼主| singleywy 发表于 2010-11-5 20:41 | 显示全部楼层
我通常写C的时候,就是用习惯后一种的,代码简洁,不过现在才发现还要看编译器如何解释的
223178825 发表于 2010-11-5 21:31 | 显示全部楼层
学习了
流行音乐 发表于 2010-11-5 21:45 | 显示全部楼层
在C语言中修改 ACC 或 R0~R7 是一种冒险。
流行音乐 发表于 2010-11-5 21:47 | 显示全部楼层
你不知道什么时候就踩到地雷上了,例如楼主遇到的“ACC+=...”。
 楼主| singleywy 发表于 2010-11-5 22:12 | 显示全部楼层
8# 流行音乐 恩,一般情况下,我不会这么轻易去做的,因为可能造成数据的破坏,但是由于程序的需要,关键部分确实要精简一些,我通常都是通过反编译方式来查看,是否存在错误或其他东西
 楼主| 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);
ayb_ice 发表于 2010-11-6 08:35 | 显示全部楼层
差之毫厘,失之千里
5880527 发表于 2010-11-6 11:57 | 显示全部楼层
不用暂时关闭定时器的,因为它一进来TH0,TL0本来就是0附近的数,根本不会发生进位,书本上的例子都是先关闭一下,搞不懂
 楼主| singleywy 发表于 2010-11-6 12:25 | 显示全部楼层
12# 5880527
请您仔细看一下代码,关闭定时器的时候可能TL0的值较小(如果系统进入critical section 即临界区,中断会发生无法预料的延迟,TL0,TH0还会是较小的值么),加上修正值后,很可能产生进位,所以是TH0加上进位是需要的,因为你不知道TL0的值是多少
5880527 发表于 2010-11-6 12:57 | 显示全部楼层
要修正就只能T0定时器中断是唯一的一个最高级中断,延迟的不确定性都是很小的几个机器周期,否则不如用T2的自动重装算了。其实这种修正跟步进电机的步距角不均匀有类似之处,修正无多大用处
upc_arm 发表于 2012-11-15 23:09 | 显示全部楼层
很好 顶! MARK一下
anazel 发表于 2012-11-16 09:03 | 显示全部楼层
编译器不同,同样的程序编译出来的代码也会不同吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

295

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部

0

主题

295

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部