英锐恩单片机论坛,Microchip单片机,模拟器件,接口电路,麦肯单片机,单片机应用交流

 找回密码
 立即注册
搜索
电子烟方案单片机单片机开发深圳单片机开发
单片机方案国产单片机8位单片机电子烟方案开发
查看: 5018|回复: 5
打印 上一主题 下一主题

MICROCHIP_PICC常用优化技巧

[复制链接]
跳转到指定楼层
1#
发表于 2009-4-18 18:12:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
常用优化技巧:
·要减少bank切换,把在不同bank里的变量放到一起。
· 在初始化代码里,在程序的开头,注意初始化的顺序-一开始所有的变量放在bank0,然后放bank1,接着bank2,bank3。
·在初始化代码里-可能有些变量不需要初始化。
·在可能的地方,掉换操作数的顺序来使编译器避免多余使用W寄存器或临时位置。
·对于数学运算,表达式里的变量尽量要在同一个bank里,以避免过多的bank切换。
·如果可能,尽可能地采用字节byte运算代替字word运算。
·如果可能,对于数组元素的访问尽量采用指针而不是用下标索引。注意在一个小的循环里使用指针时,管理循环多出的代码抵销了使
用指针节省下来的代码,所以使用两种方法差不多。
·一系列的:
If
else if
else if ... 通常会比case语句产生更小的代码。
·在switch – case里,改变常量为有顺序的数据,不要有间隔。
·依靠bank切换必需的:Depending on the bank switching required:
var = value1;
if (!flag)
var = value2;
产生更理想的代码:
if (flag)
var = value1;
else
var = value2;
只是要确认在该代码执行时不要在中断里使用这个var。
·清零,递增,以及递减一个字节byte是单指令的操作。给一个字节赋值需要两条指令(value -> W, and W -> byte).
· 只要可能,尽量使用bits代替unsigned chars。置位Bit sets,清零clears,以及位测试跳转等都是单条指令。 因为不能在函数里申明位变量,你可以全局声明位变量。
· 调用函数会产生一些管理代码。尝试着用一些宏marcro代替你的一些小一点的函数。
· 如果堆栈空间允许,大块的重复代码应该由函数及函数调用来替代。
· 当前逻辑的优化。我还只是刚接到一个固定要求的项目,于是我尝试着把代码写得非常灵活。当我快接近项目结束时,我发现一些弹性代码不再需要了,这样可以删除它来节省代码。
优化提示1:Signed vs. Unsigned变量
比较使用signed和unsigned变量的汇编代码,你会发现在比较有符号signed变量时会多出一些指令。
结论1:
尽可能地使用unsigned的int或char。
2#
发表于 2009-4-19 01:25:07 | 只看该作者
优化提示2: 基于字节Byte的循环Loops

这里有两块代码,它们做的完全是同样的事情。但是其中一个要完成得快25%,并且使用更小的RAM空间,你能挑出是哪一个吗?

unsigned char i;

for(i=0;i<250;i++) do_func(); //executes do_func() 250 times, in 3.25ms

for(i=250;i!=0;i--) do_func(); //executes do_func() 250 times, in 2.5ms

要找出这个,我们来看一下产生的汇编代码

for(i=0;i<250;i++) do_func();

//executes 250 times in 3251 cy

1617 01B8 clrf 0x38

1618 260F call 0x60F

1619 0AB8 incf 0x38

161A 3008 movlw 0xFA

161B 0238 subwf 0x38,W

161C 1C03 btfss 0x3,0x0

161D 2E18 goto 0x618  

for(i=250;i!=0;i--) do_func();

//executes 250 times in 2502 cy

1621 3008 movlw 0xFA

1622 00B8 movwf 0x38

1623 260F call 0x60F

1624 0BB8 decfsz 0x38

1625 2E23 goto 0x623   

结论2:

如果可能,让你的循环递减到零。检查一个ram变量是否为零会更快一些。

但是,注意在递增循环里,do_func()要早一个时钟周期被调用。如果你希望进入函数的速度快些,可选择递增循环。
回复 支持 反对

使用道具 举报

3#
发表于 2009-4-19 01:25:25 | 只看该作者
优化提示3: Integer

Timeout Loops

如果你想查询一个端口,或者在timeout“时间到”之前执行一个函数一定的次数,你需要一个定时循环timeout loop.

unsigned int timeout;

#define hibyte(x) ((unsigned char)(x>>8))

#define lobyte(x) ((unsigned char)(x&0xff))

//the optimizer takes care of using the hi/lo correct byte of integer

·Loops to avoid with timeouts: 320000 to 380000 cycles for 20000 iterations.

for(timeout=0;timeout<20000;timeout++) do_func(); //380011 cycles

for(timeout=20000;timeout!=0;timeout--) do_func(); //320011 cycles |

· Best loop for a timeout: 295000 cycles for 20000 iterations.

//we want to execute do_func() approx. 20000 times before timing out
timeout=(20000/0x100)*0x100; //keeps lobyte(timeout)==0, which speeds up assignments

for(;hibyte(timeout)!=0;timeout--) do_func(); //295704 cycles

Notice the features of the loop shown above.

1. 它在每个循环里只测试整型数的高位字节。

2. 它检查这个字节是否到零,所以很快。

3. 当初始化timeout变量时,它又一个好处是:汇编代码清零一个ram变量只要一条指令,而赋值则需要两条指令。

结论3:

·尽可能地采用递减到零的循环,因为检查ram变量是否为零更简单。

· 在延时循环里只查询整型数的高位字节,这要快一些。  给整型数赋值时,对ram变量清零要比赋一个数值要快一些。
回复 支持 反对

使用道具 举报

4#
发表于 2009-4-19 01:26:14 | 只看该作者
优化提示4: 使用内部定时器的Timeout定时循环

当然,使用芯片片内定时器并检查中断的方式是最快的定时循环。它通常会比用延时循环快70%左右。

//set up tmr0 to set flag T0IF high when it rolls over

while(RA0==0 && !T0IF); //wait until port goes high

结论4:

·尽可能地使用内建的定时器及中断标志。
优化提示5: Case 语句

慢而且效率低

c=getch();

switch(c)

{

case 'A':
{
do something;
break;
}
case 'H':
{
do something;
break;
}
case 'Z':
{
do something;
break;
}
}

getch 快且高效率
c=getch();
switch(c)
{
case 0:
{
do something;
break;
}
case 1:
{
do something;
break;
}
case 2:
{
do something;
break;
}
}
Hi-Tech C的优化器会尽可能地把switch语句变成计算偏移的goto
回复 支持 反对

使用道具 举报

5#
发表于 2009-4-19 01:26:51 | 只看该作者
结论5:
·尽可能地在case语句里使用连续的数字。
优化提示6: Hi-Tech C里的除法

如果你使用Hi-Tech C,在你程序的任何位置有任何数学除法的运算,就将会使用到bank0里13到23个字节的空间,以及一些EPROM/Flash程序空间。
尽管变量不在bank0,这一样会发生。
Occurrence
Any mathematical division at all in the entire program using a variable of type 'long', even if all variables do not reside in bank0.
RAM usage
23 bytes in bank0

ROM/flash usage
large, it has to include ldiv routines
Fix/Explanation
Use combinations of bit shifts ie: x=x*6 is replaced by x1=x;x2=x;x=x1<<2 + x2<<1

Occurrence
Any mathematical division at all in the entire program using a variable of type 'unsigned int', even if all variables do not reside in bank0.
RAM usage
13 bytes in bank0
ROM/flash usage
large,it has to include ldiv routines
Fix/Explanation
Use combinations of bit shifts

Occurrence
Any mathematical division involving a divisor that is a power of 2, ie: x=x/64;
RAM usage
none
ROM/flash usage
low
Fix/Explanation
Use combinations of bit shifts
Occurrence
Any mathematical division involving a divisor that is not a power of 2, ie: x=x/65;
RAM usage
none
ROM/flash usage
high
Fix/Explanation
make your divisors a power of 2, ie: 2^5=32.
回复 支持 反对

使用道具 举报

6#
发表于 2009-4-19 01:27:05 | 只看该作者
结论6:
如果可能,尽量让C编译器使用简单的移位来做除法,且除数是2的幂。除数是2的幂,例如,256=2^8,可以被C编译器优化为移位操作。

如果你在程序里没有使用任何除法运算,则可以节省bank0里的23个字节和一部分程序空间-ldiv()程序。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|公司首页|Microchip单片机,模拟器件,接口电路,麦肯单片机,单片机应用交流 ( 粤ICP备09008620号 )

GMT+8, 2024-4-28 16:05 , Processed in 0.051992 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表