Rss & SiteMap

曙海教育集团论坛 http://www.bjzhda.cn

曙海教育集团论坛
共1 条记录, 每页显示 10 条, 页签: [1]
[浏览完整版]

标题:单片机代码优化深入讨论

1楼
wangxinxin 发表于:2010-12-7 13:56:33
本人在优化定时器和计数器的中断处理函数中总结了一下经验,才有自言自语格式:图片点击可在新窗口打开查看
1、优化代码采用汇编就是啦,何必在用C语言呢?
答:代码的优化是建立在于程序结构最优化之上的,好的程序结构,代码优化才有价值,是优中优;反之糟糕的程序结构,代码优化只能在最差的程序结构中得到最好代码,是差中优。所以优中优>差中优。C语言是一种高级语言(有的叫中级语言)在描述程序结构的与汇编没有区别,更直观。
2、现在单片机速度很快,为什么要优化的程序结构呢?
答:比如我在编写定时器和计数器的程序的时候,由于这个函数使用频繁,这个中断以后还要加入类似PLC的IO数据刷新程序(把PLC程序的结果送入单片机的IO端口,或从IO端口中读入数据)和系统变量数据函数(如秒脉冲,100ms秒脉冲,等),所以这个中断函数负担很重。所以每个算法必须最优化。现在单片机速度很快,但是具体某一个固定功能的函数优化一下,可以把单片机资源更多的用于用户程序。比如PLC的单片机必须解释用户程序。必须在定期完成。比如PLC周期是100ms,比如12M的8051,1/10的振荡周期内完成。1.2M/12=100kHZ,平均下来,10万指令条不到,还是比较紧张的。稍微好一点的PLC,周期数可以达到10ms。即使采用AVR这种RISC的,在10ms完成一个PLC扫描周期,也是很吃紧的。
3、怎么才能得到最优的程序结构?
答:这个问题很广,算法=程序+数据结构。数据结构优化,可以学习数据结构的书籍,里面全是最优的结构,依赖于计算机。程序的优化,一般独立于计算机,要自己有一个好的思路。
比如我在处理定时器和计数器函数是,画了状态图,根据状态图,编程序一目了然,基本是最优结构了。除非开发专用硬件或查表法。请参看我的另一个帖子:http://www.stmfans.com/bbs/viewt ... &extra=page%3D1
4、你的那个帖子,首先发的效率不是还可以吗?
C语言精简不等于编译出来的东西会精简。
5、为什么呀?
我首先贴出来的的C程序,没有跟我画出来的状态图一一对应。没有充分利用各bit量的信息。
比如,定时器从S1转到S2,只需判断T_EN=1;维持状态:T_EN=0
S2转到S1,只需判断T_EN=0。S2维持,须判断T_ACC<T_SET=1。S2转到S3,须判断T_ACC<T_SET=0;
S3转到S1,T_EN=0;S3维持,T_EN=1;这个时候T_ACC<T_SET是个无关量,不需要重复运算了。

我还设置tmp中间量,其实T_OUT的状态已经表明T_ACC<T_SET=0,tmp是画蛇添足的,浪费空间。
6、条件表达式不是比if else要好吗?
在大多情况下,进行简单的运算,要好一点(微弱),语句复杂的话,编译出来的东西不一定高效。况且条件表达式中,
无法加入break等语句。
7、我看了关于编程优化的书籍,要减少跳转的,你后面的程序跳转很多呀?尤其是那个计数器,嵌套了好几层呀?
由于很多编程优化的书籍是针对PC机的:减少跳转,可以提高CPU缓存的命中率。由于缓存速度很快,与CPU同步的。如intel的扣肉
分一级缓存,二级缓存。当跳转的时候如果跳出了二级缓存的范围,会到内存中读取数据,由于内存的速度比CPU慢一个数量级。
所以效率不高。

而我们的单片机编程的时候,flash与RAM都是与CPU同步的。单片机的RAM全部是SRAM(缓存也是SRAM),跳转只能在单片机的资源以内,相当于PC的CPU中只能在缓存空间内跳。所以单片机的命中率是100%,除非出错。图片点击可在新窗口打开查看OL所以跳转语句只是单片机的一个普通指令,处理周期数不是最高的,比如51的跳转都是2个机器周期。比如ADD,SUB,MOV等指令都要2个周期。
8、你后面发的程序,为什么是最优呢?
我把后面的程序由编译器编译出来的指令贴出来:
;        d:\MYDOCU~1\51_proj\timer.c:28: if(T0_EN)
        jnb        _T0_EN,00105$   ;对应状态图S2   t2
;        d:\MYDOCU~1\51_proj\timer.c:30: if(T0_OUT);
        jb        _T0_OUT,00106$        ;对应状态图S2   t2
;        d:\MYDOCU~1\51_proj\timer.c:32: {T0_OUT=++T0_ACC>=T0_SET;}
        inc        _T0_ACC           ;对应状态图S2 t1
        clr        c                                t1
        mov        a,_T0_ACC                        t2
        subb        a,#0x14                                t2
        mov  b0,c                                t2
        cpl        c                                t1
        mov        _T0_OUT,c        ;对应状态图S3  t2
        sjmp        00106$                                t2
00105$:
;        d:\MYDOCU~1\51_proj\timer.c:36: T0_OUT=0;T0_ACC=0;
        clr        _T0_OUT                ;对应状态图S1  t1
        mov        _T0_ACC,#0x00                   t2
00106$:

即使没采用汇编语言,C编译器已经为我们产生出来很精简的语句,当然32至36之间的代码还可以采用汇编优化。
所以首先程序优化,然后在进行汇编,难度降低了很多。因为程序优化后,C编译出来的汇编,在进行优化工作量很小了。
其中计数器的代码变化最大,优化了10行之多。给我可以自己用编译器试验一下。

9、这个是最快的吗?
不是,最快的应该是查表法。对这个定时器来说:
方案一:
输入:T_EN,T_ACC,T_SET
输出:T_OUT,T_ACC
建立一个数据表格,然后在中断函数中用查表法,大概两条指令搞定。不过占用的空间也是吓人。图片点击可在新窗口打开查看OL

10、在使用if else语句注意什么?
采用if else语句避免()中进行多目运算。也不要进行取反运算,因为这样代码会增加好几行。
如果直接用bit量,这样编译器会用 jnb或jb,

由于本人水平有限,举例采用的是8051(因为我的电脑是P3 800,运行proteus正好)。希望对大家有参考作用
共1 条记录, 每页显示 10 条, 页签: [1]

Copyright © 2000 - 2009 曙海教育集团
Powered By 曙海教育集团 Version 2.2
Processed in .02930 s, 2 queries.