因为单片机的功用同电脑的功用是天渊之别的,不管从空间资源上、内存资源、作业频率,都是无法与之比较的。PC 机编程基本上不必考虑空间的占用、内存的占用的问题,终究意图便是完结功用就能够了。关于单片机来说就天壤之别了,一般的单片机的Flash 和Ram 的资源是以KB 来衡量的,可想而知,单片机的资源是少得不幸,为此咱们有必要主意设法榨尽其所有资源,将它的功用发挥到最佳,程序设计时有必要遵从以下几点进行优化:
-
运用尽量小的数据类型
能用unsiged就不必signed;
能用char就不必int;
能不必floating就不必。
能用位操作不必管用。 -
运用自加、自减指令
一般运用自加、自减指令和复合赋值表达式(如a-=1 及a+=1 等)都能够生成高质量的
程序代码,编译器一般都能够生成inc 和dec 之类的指令,而运用a=a+1 或a=a-1 之类
的指令,有许多C 编译器都会生成二到三个字节的指令。 -
削减运算的强度
能够运用运算量小但功用相同的表达式替换本来杂乱的的表达式。
(1) 求余运算
N= N %8 能够改为N = N &7
阐明:位操作只需一个指令周期即可完结,而大部分的C 编译器的“%”运算均是调用子程序来
完结,代码长、履行速度慢。一般,只需求是求2n 方的余数,均可运用位操作的办法来替代。
(2) 平方运算
N=Pow(3,2) 能够改为N=3*3
阐明:在有内置硬件乘法器的单片机中(如51 系列),乘法运算比求平方运算快得多, 因为浮点数
的求平方是经过调用子程序来完结的,乘法运算的子程序比平方运算的子程序代码短,履行速度快。
(3) 用位移替代乘法除法
N=M*8 能够改为N=M<<3
N=M/8 能够改为N=M>>3
阐明:一般假如需求乘以或除以2n,都能够用移位的办法替代。假如乘以2n,都能够生成左移
的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的办法得到代码比调用乘除法子
程序生成的代码功率高。实际上,只需是乘以或除以一个整数,均能够用移位的办法得到成果。
如N=M*9能够改为N=(M<<3)+M;
(4) 自加自减的差异
例如咱们平常运用的延时函数都是经过选用自加的办法来完结。
void DelayNms(UINT16 t)
{
UINT16 i,j;
for(i=0;i
define MAX(A,B) {(A)>(B)?(A):(B)}
阐明:函数和宏函数的差异就在于,宏函数占用了很多的空间,而函数占用了时刻。咱们要知道的是,函
数调用是要运用体系的栈来保存数据的,假如编译器里有栈查看选项,一般在函数的头会嵌入一些汇编语
句对当时栈进行查看;一起,cpu 也要在函数调用时保存和康复当时的现场,进行压栈和弹栈操作,所以,
函数调用需求一些cpu 时刻。而宏函数不存在这个问题。宏函数只是作为预先写好的代码嵌入到当时程序,
不会发生函数调用,所以只是是占用了空间,在频频调用同一个宏函数的时分,该现象特别杰出。
-
适当地运用算法
假如有一道算术题,求1~100 的和。
作为程序员的咱们会毫不犹豫地点击键盘写出以下的核算办法:
UINT16 Sum(void)
{
UINT8 i,s;
for(i=1;i<=100;i++)
{
s+=i;
}
return s;
}
很显着咱们都会想到这种办法,可是功率方面并不满意,咱们需求动脑筋,便是选用数学算法解决问题,
使核算功率进步一个等级。
UINT16 Sum(void)
{
UINT16 s;
s=(100 *(100+1))>>1;
return s;
}
成果很显着,相同的成果不同的核算办法,运转功率会有大大不同,所以咱们需求最大极限地经过数
学的办法进步程序的履行功率。 -
用指针替代数组
在许多种情况下,能够用指针运算替代数组索引,这样做常常能发生又快又短的代码。与数组索引相
比,指针一般能使代码速度更快,占用空间更少。运用多维数组时差异更显着。下面的代码作用是相同的,
可是功率不一样。
UINT8 szArrayA[64];
UINT8 szArrayB[64];
UINT8 i;
UINT8 *p=szArray;
for(i=0;i<64;i++)szArrayB[i]=szArrayA[i];
for(i=0;i<64;i++)szArrayB[i]=*p++;
指针办法的长处是,szArrayA 的地址装入指针p 后,在每次循环中只需对p 增量操作。在数组索引
办法中,每次循环中都有必要进行根据i 值求数组下标的杂乱运算。 -
强制转化
C 言语精华榜首精华便是指针的运用,第二精华便是强制转化的运用,恰当地使用指针和强制转化不光
能够供给程序功率,并且使程序更加之简练,因为强制转化在C 言语编程中占有重要的方位,下面将已五
个比较典型的比如作为解说。
比如1:将带符号字节整型转化为无符号字节整型
UINT8 a=0;
INT8 b=-3;
a=(UINT8)b;
比如2:在大端形式下(8051 系列单片机是大端形式),将数组a[2]转化为无符号16 位整型值。
办法1:选用位移办法。
UINT8 a[2]={0x12,0x34};
UINT16 b=0;
b=(a[0]<<8)|a[1];
成果:b=0x1234
办法2:强制类型转化。
UINT8 a[2]={0x12,0x34};
UINT16 b=0;
b=(UINT16)a; //强制转化
成果:b=0x1234
比如3:保存结构体数据内容。
办法1:逐一保存。
typedef struct _ST
{
UINT8 a;
UINT8 b;
UINT8 c;
UINT8 d;
UINT8 e;
}ST;
ST s;
UINT8 a[5]={0};
s.a=1;
s.b=2;
s.c=3;
s.d=4;
s.e=5;
a[0]=s.a;
a[1]=s.b;
a[2]=s.c;
a[3]=s.d;
a[4]=s.e;
成果:数组a 存储的内容是1、2、3、4、5。
办法2:强制类型转化。
typedef struct _ST
{
UINT8 a;
UINT8 b;
UINT8 c;
UINT8 d;
UINT8 e;
}ST;
ST s;
UINT8 a[5]={0};
UINT8p=(UINT8)&s;//强制转化
UINT8 i=0;
s.a=1;
s.b=2;
s.c=3;
s.d=4;
s.e=5;
for(i=0;i
define Perror(FUN) printf(“Err:%s %s %d: %s\n”,FILE,func,LINE,FUN) 类linux的perror函数完结,这儿加了犯错的文件方位,地点函数,引发犯错调用的函数FUN。
宏中#和##的用法
define STR(s) #s
define CONS(a, b) int(a##e##b)
printf(STR(vck));//输出vck
printf(“%d\n”, CONS(2,3));//2e3 输出2000