虽然MPLAB-C18 C语言编译器的编译效率比较高, 但与汇编语言相比, C的效率终究差一些, 因此在某些应用场合, 如何优化C的效率, 减小代码, 提高执行速度, 是许多工程师们的追求目标。下面介绍MPLAB-C18 C编译器的一些优化技巧, 与大家共享。
1 使用静态型局部变量
局部变量的缺省存储类型为自动型,存取时使用软件堆栈,即使用直接寻址方式。如果声明为静态型,则静态型局部变量编译时将分配固定地址, 访问时将使用直接寻址。显然, 直接寻址比间接寻址存取速度快,占用的代码空间少。下面举例比较静态型与自动型局部变量生成汇编代码的差别。
源程序代码
void sub1(void) {
static unsigned char local1; //静态型
unsigned char local2; // 自动型
local1+=5; // 占用5个字
local2+=6; //仅占用3个字
} 生成的汇编代码
MOVF POSTINC1,F,ACCESS
MOVLW 0X05
MOVLB 0X0
ADDWF L1,F,BANKED
MOVF POSTDEC1,F,ACCESS
MOVLW 0X06
MOVLB 0X0
MOVWF LOCAL1,BANKED
注意:①静态型局部变量将占用更多的数据存储器空间;② 如果该函数是可重载的, 则局部变量不能声明为静态型。
2 使用全局变量传递函数参数
当有足够的数据存储空间且该函数不可重载时, 可使用全局变量传递函数参数, 优化你的代码。因为全局变量编译时将分配固定地址, 访问时将使用直接寻址方式。例如调用sub1子程序, 可采用下面使用全局变量传递函数参数的方法。
unsigned char sub1_var1,sub1_var2;
void sub1(void);
void main(void){
sub1_var1=1;
sub1_var2=2;
sub1();
}
替代如下传递函数参数的方法。
void sub1(unsigned char var1,unsigned char var2)
viod main(void)
{
sub1(1,2)
}
当然也可以把var1、var2声明为静态型存储类型, 达到相同优化代码的目的。即:void sub1(static unsigned char var1, static unsigned char var2)。
3 使用合适的数据类型
MPLAB C-18支持的数据类型及占用的字节数如下:
类型 最小值 最大值 字节数
unsigned char 0 255 1
signed char -128 127 1
unsigned int 0 655536 2
signed int -32768 32767 2
unsigned short long 0 16777215 4
signed short long -8388608 8388607 4
unsigned long 0 4294967295 8
signed long -2147483648 2147483647 8
不同数据类型占用的数据存储器字节数不同, 因此尽可能使用较短的数据类型。 另外如果是无符号数, 应声明为无符号型。 例如下例变量i、j加一立即数, 其中i为int型,j为char型, 可见它们生成的代码大小不一样。
源程序代码
int i;
unsigned char j;
void main(void) {
i+=5; //占用4个字
j+=6; // 仅占用3个字
}
生成的汇编代码
MOVLW 0X06
ADDWF I,F,BANKED
MOVLW 0
ADDWF 0XB8,F,BANKED
MOVLW 0X05
MOVLB 0X0
ADDWF J,F,BANKED
4 把变量分配于ACCESS RAM区
PIC18系列数据存储器分为16个存储器组(BANK 0~15), 每个存储器组为256个字节, 使用直接寻址方式访问数据存储器时, 先要选择存储器组(BANK)。 为了快速访问数据存储器, PIC18把BANK0的0x0~0x7F和BANK15的0x80~0xFF构成ACCESS RAM。 访问ACCESS RAM时, 不需要选择BANK, 从而达到快速访问的目的。 下面举例比较变量分配于ACCESS RAM区与不在ACCESS RAM的区别。
源程序代码
unsigned char var1 //不在Access RAM区
#pragma udata access mydata near unsigned char var2 //声明于Access RAM区
#pragma
void sub1(void){
var1+=5; // 占用3个字
var2+=6; //仅占用2个字
}
生成的汇编代码
MOVLW 0X05
MOVLB 0X01
ADDWF 0xvar1,F,BANKED
MOVLW 0X06
ADDWF 0xvar2,F, ACCESS
5 使用#pragma varlocate伪指令
#pragma varlocate 伪指令告诉编译器变量所属的存储器组位置, 从而使编译器更有效地执行存储器组切换。 例如在多模块编程中, 文件1把变量I、J分配在存储器组1。
#pragma udata bank1
unsigned char I,J
在文件2中要使用变量I、J, 用# pragma varlocate 声明变量I、J位于存储器组位置1, 这样编译时可省掉一条MOVLB 指令。
extern unsigned char I,J
#pragma varlocate 1 c1,c2
void main (void)
{
I+=5; // 此处编译时可省掉一条MOVLB 指令
J+=6;
}
6 使用指针
下面举例说明使用指针与不使用指针的区别,其中例子1使用指针,例子2不使用指针。编译后,可以发现例子1生成的代码比例子2 少很多。
struct mystruct
{
char a;
char b;
}
mystruct mydata [10];
mystruct *p=&(mydata[0]);
例子1
for(i=0; i<10; i++)
{
p->.a = i;
p->.b = 88;
p++;
}
例子2
for (i=0;i,10;i++)
{
mydata[i].a=i
mydata[i].b=88; }
7 嵌入汇编
因为汇编的效率最高, 因此在有些场合例如中断服务子程序使用嵌入汇编的方法。 MPLAB-C18支持C与汇编的混合编程。
8 使用最新版本的C编译器
MPLAB-C18编译器的版本不断更新,最新版本除了支持新型号的PIC18单片机之外,还对它的优化效率不断改善。因此尽量使用最新版本的C编译器。
9 使用优化命令行选项
在优化功能命令项的选项对话框中,选中表示使能。 但请注意有些优化选项将会影响源程序级调试。限于篇幅,各优化功能命令项的作用这里不一一介绍。