欢迎来到天天文库
浏览记录
ID:59142096
大小:21.79 KB
页数:14页
时间:2020-09-11
《程序优化佳文.docx》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、程序优化 由于单片机的性能同电脑的性能是天渊之别的,无论从空间资源上、内存资源、工作频率,都是无法 与之比较的。PC机编程基本上不用考虑空间的占用、内存的占用的问题,最终目的就是实现功能就可以了。 对于单片机来说就截然不同了,一般的单片机的Flash和Ram的资源是以KB来衡量的,可想而知,单片 机的资源是少得可怜,为此我们必须想法设法榨尽其所有资源,将它的性能发挥到最佳,程序设计时必须 遵循以下几点进行优化: 1.使用尽量小的数据类型 能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变
2、量就不要用长整型(longint),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变 量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了, 而且这样的错误很难发现。 2.使用自加、自减指令 通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的 程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类 的指令,有很多C编译器都会生成二到三个字节的指令。 3.减少运算的强度 可以使用运算量小但功能相同的表达式替换原来复杂
3、的的表达式。 (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可以改为
4、N=M>>3 说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移 的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子 程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果。如N=M*9 可以改为N=(M<<3)+M; (4)自加自减的区别 例如我们平时使用的延时函数都是通过采用自加的方式来实现。 voidDelayNms(UINT16t) { UINT16i,j; for(i=0;i5、++) } 可以改为 voidDelayNms(UINT16t) { UINT16i,j; for(i=t;i>=0;i--) for(j=1000;i>=0;j--) } 说明:两个函数的延时效果相似,但几乎所有的C编译对后一种函数生成的代码均比前一种代码少1~3 个字节,因为几乎所有的MCU均有为0转移的指令,采用后一种方式能够生成这类指令。 4.while与do...while的区别 voidDelayNus(UINT16t) { while(t--) { NOP(); } } 可以改为 voidDelayNus(UINT16t)6、 { do { NOP(); }while(--t) } 说明:使用do…while循环编译后生成的代码的长度短于while循环。 5.register关键字 voidUARTPrintfString(INT8*str) { while(*str&&str) { UARTSendByte(*str++) } } 可以改为 voidUARTPrintfString(INT8*str) { registerINT8*pstr=str; while(*pstr&&pstr) { UARTSendByte(*pstr++) } } 说明:在声明7、局部变量的时候可以使用register关键字。这就使得编译器把变量放入一个多用途的寄存 器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的 速度,注意register关键字只是建议编译器而已。 6.volatile关键字 volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在 哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。一般来 说,volatile关键字只用在以下三种情况: a)中断服务函数中修改的供其它程序检测的8、变量需要加volatileb)多任务环境下各任务间共享的标志应该加volatile c)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义总之,volatile关键字是
5、++) } 可以改为 voidDelayNms(UINT16t) { UINT16i,j; for(i=t;i>=0;i--) for(j=1000;i>=0;j--) } 说明:两个函数的延时效果相似,但几乎所有的C编译对后一种函数生成的代码均比前一种代码少1~3 个字节,因为几乎所有的MCU均有为0转移的指令,采用后一种方式能够生成这类指令。 4.while与do...while的区别 voidDelayNus(UINT16t) { while(t--) { NOP(); } } 可以改为 voidDelayNus(UINT16t)
6、 { do { NOP(); }while(--t) } 说明:使用do…while循环编译后生成的代码的长度短于while循环。 5.register关键字 voidUARTPrintfString(INT8*str) { while(*str&&str) { UARTSendByte(*str++) } } 可以改为 voidUARTPrintfString(INT8*str) { registerINT8*pstr=str; while(*pstr&&pstr) { UARTSendByte(*pstr++) } } 说明:在声明
7、局部变量的时候可以使用register关键字。这就使得编译器把变量放入一个多用途的寄存 器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的 速度,注意register关键字只是建议编译器而已。 6.volatile关键字 volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在 哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。一般来 说,volatile关键字只用在以下三种情况: a)中断服务函数中修改的供其它程序检测的
8、变量需要加volatileb)多任务环境下各任务间共享的标志应该加volatile c)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义总之,volatile关键字是
此文档下载收益归作者所有