您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 嵌入式系统程序可移植性设计及性能优化
嵌入式系统程序可移植性设计及性能优化【摘要】在嵌入式系统的程序设计中,由于软硬件平台的多变性,对程序的可移植性、可扩充性、可裁减性及可维护性等有更严格的要求。本文从宏定义设计、数据结构设计及函数设计等方面,简单介绍了可移植性的设计问题。在嵌入式应用中非常注重代码的时空效率,即产生的代码运行时间和占用的存储空间尽可能少。程序设计一章介绍了如何提高程序的运行效率的相关技巧。【关键词】嵌入式,可移植性,可维护,可裁减,宏定义设计,数据结构设计,时空效率目录1宏定义设计-1-1.1为何要采用宏定义?-1-1.2宏定义的基本规则-1-1.3依赖关系定义宏改善移植性-1-1.4通过偏移量和掩码进行位操作-2-2数据结构设计-4-2.1结构体中成员对齐规则-4-2.1.1自然对界.......................................................................................-4-2.1.2指定对界.......................................................................................-4-2.2合理设计成员顺序-5-2.2.1减少结构体存储空间...................................................................-5-2.2.2填充部分域,避免字节对齐问题...............................................-6-2.2.3字节对齐问题实例.......................................................................-7-2.3采用位域构造结构体-8-2.3.1位域设计传输协议.......................................................................-8-2.3.2位域的可移植性问题...................................................................-9-2.3.3位域设计硬件配置字.................................................................-10-2.4通过union和struct传递不同格式报文-11-2.5将相关功能变量封装为结构体-13-3函数设计-15-3.1避免过多函数参数,提高调用性能-15-3.2合理设计模块,减小耦合度-16-3.3用宏函数提高时间效率-18-3.3.1宏参数的基本规则.....................................................................-18-3.3.2宏语句的基本规则.....................................................................-18-3.3.3宏的副作用.................................................................................-20-3.4Const修饰输入指针参数-21-4程序设计-22-4.1循环转置-22-4.2减小运算强度-23-4.2.1位操作实现求余运算.................................................................-23-4.2.2用移位实现乘除法运算.............................................................-23-4.2.3将循环体内的乘法运算改成循环自加运算.............................-23-4.3减少不变计算-24-4.3.1循环内部避免恒定式.................................................................-24-4.3.2避免结构体深度访问.................................................................-25-4.4减少存储访问指令周期和个数-26-4.5查表-28-4.6使用自加、自减指令-28-4.7根据频率进行case排序-29-4.8函数指针表替代switch-case-30-嵌入式系统程序可移植性设计及性能优化之一――――宏定义设计【摘要】本节介绍了嵌入式系统程序设计中采用宏定义进行常量定义的必要性。说明了宏常量定义的基本规则以及如何采用依赖关系定义宏常量来保证其可移植性和裁减性。最后介绍了如何利用宏定义实现掩码偏移量等来高效的进行位操作。【关键词】嵌入式,可移植性,宏定义,依赖关系,掩码,偏移量,位操作1宏定义设计-1-1.1为何要采用宏定义?-1-1.2宏定义的基本规则-1-1.3依赖关系定义宏改善移植性-1-1.4通过偏移量和掩码进行位操作-2-1宏定义设计1.1为何要采用宏定义?在程序设计过程中,对于经常使用的一些常量,如果将它直接写到程序中去,一旦常量的数值发生变化,就必须逐个找出程序中所有的常量,并逐一进行修改,这样必然会降低程序的可维护性。因此,应尽量通过预处理命令方式将常量定义为特定的字符,这样常量就有了统一的表现形式,不会出现输入错误导致的不一致性。另外宏常量意义明确,大大改善了代码的可读性。只读的变量也可以实现上述宏常量所带来的可移植性、可靠性及可读性等特点,但其要占据存储空间,需要访问内存,相比宏常量的立即数寻址而言效率要低。在C++中提倡用const只读变量来定义常量,是因为这样可以提供更严格的类型安全检查。但由于C中const只读变量不能用于某些场合,因此在嵌入式C中仍多数采用宏来定义常量。1.2宏定义的基本规则下面以一个实例来说明宏定义的基本规则,如用预处理指令#define声明一个常量,用以表明1年中有多少秒,不考虑润年#defineC_SECONDS_PER_YEAR(60*60*24*365)ULa)命名风格,为了与普通变量区分开来,宏定义通常全部大写,多个单元之间用下划线隔开;b)整个表达式应括起来,若有参数则应将每个参数都括起来,防止替换扩展后可能带来的异常问题;c)常量表达式先合并后再替换。预处理器将为你计算常量表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有运行性能代价的。d)为常量添加类型信息。宏的不足之一在于缺乏类型安全检查,人为的提供类型信息可以有效检查出此类问题。UL告诉编译器这个常量是无符号长整型数,因此将其赋值给u16型变量会出现告警。1.3依赖关系定义宏改善移植性嵌入式系统程序的最大特点是硬件平台的多变性,因此需要根据具体的应用情况更改大量配置,而这些配置基本都是由宏定义来实现的,放在特定的头文件中,与其他的代码隔离,在一定程度上改善了代码的可移植性。但有些时候,多个宏定义有严重的依赖关系,增减某个宏会引起其他定义的更改,如何定义这些宏对嵌入式程序的可移植性有很大影响。A常量分别定义#defineC_DD_MODULE_ID_AOM(0x00010101)/*AOM模块ID*/#defineC_DD_MODULE_ID_RRCM(0x00010102)/*RRCM模块ID*/#defineC_DD_MODULE_ID_RLC(0x00010103)/*RLC模块ID*/#defineC_DD_MODULE_ID_TRM(0x00010104)/*TRM模块ID*/#defineC_DD_MODULE_ID_MCP_MIN(C_DD_MODULE_ID_AOM)#defineC_DD_MODULE_ID_MCP_MAX(C_DD_MODULE_ID_TRM)B依赖定义#defineC_DD_MODULE_ID_MCP_MIN(0x00010101)/*MCP最小模块ID*/#defineC_DD_MODULE_ID_AOM(C_DD_MODULE_ID_MCP_MIN)/*AOM模块ID*/#defineC_DD_MODULE_ID_RRCM(C_DD_MODULE_ID_AOM+1)/*RRCM模块ID*/#defineC_DD_MODULE_ID_RLC(C_DD_MODULE_ID_RRCM+1)/*RLC模块ID*/#defineC_DD_MODULE_ID_TRM(C_DD_MODULE_ID_RLC+1)/*TRM模块ID*/#defineC_DD_MODULE_ID_MCP_MAX(C_DD_MODULE_ID_TRM)/*MCP最大模块ID*/“A常量分别定义”方式,因为各个宏定义值必须连续,若更改或者删除C_DD_MODULE_ID_AOM,其他的定义基本都受到影响,将严重影响到代码的可扩充性和可裁减性。“B依赖定义”方式,其原则是:a)base用常量定义;b)第一个定义为base;c)其他的在上一个基础上加1;d)max项即为最后一项。这样整体改动起来只需要更改base;在中间删除或添加部分项时只需要更改一个上下衔接处即可;添加则比较简单,只需要在原有最后项后添加即可。这种方式若改动部分定义对其他定义的影响最小,大大改善了代码的可移植性。1.4通过偏移量和掩码进行位操作嵌入式系统经常需要和硬件打交道,而配置硬件寄存器则是系统初始化阶段的重要任务,如何清晰明了的进行配置决定了代码的可读性。尽管可以使用位域,但位域是不可移植的,因此利用宏定义来解决可移植性问题。对于每一个待操作相应位来说,应具备以下几个标识:待操作的位名称B_NAME;操作位所占据的位宽B_WIDTH_NAME操作位第一位的偏移量B_SHIFT_NAME操作位的掩码B_MASK_NAME以PRI为例进行说明:#definePRIDD_C64_EDMA_OPT_PRI#defineC_WIDTH_DD_C64_EDMA_OPT_PRI(3)#defineC_SHIFT_DD_C64_EDMA_OPT_PRI(29)可以手动定义对应位的掩码,如下:#defineC_MASK_DD_C64_EDMA_OPT_PRI(0xe0000000)但更好的方式是利用位宽和偏移量来自动构成掩码#defineBIT_MASK(_name)(((1UC_WIDTH_##_name))-1)(C_SHIFT_##_name)#defineC_MASK_DD_C64_EDMA_OPT_PRIBIT_MASK(PRI)BIT_MASK(PRI)经过宏替换后即为:(((1U(C_WIDTH_DD_C64_EDMA_OPT_PRI))-1)/(C_SHIFT_DD_C64_EDMA_OPT_PRI)对于每个位的取值也应该用宏定义来表示,这样清晰明确#defineC_DD_C64_EDMA_OPT_URGENT_PRI(0x0)#defineC_DD_C64_EDMA_OPT_HIGH_PRI(0x1)#defineC_DD_C64_EDMA_OPT_MEDIUM_PRI(0x2)#defineC_DD_C64_EDMA_OPT_LOW_PRI(0x3)具备了掩码和偏移量即可对各个位进行操作了#defineSET_BITS(_reg,_name_val)/((_reg)=((_reg)&~(BIT_MASK(_name)))/|(((_val)(C_SHIFT_##_name))&(BIT_MASK(_name))))通过如下方式调用设置优先级SET_BITS(u32Opt,PRI,C_DD_C64_EDMA_OPT_HIGH_PRI);即实现了将u3
本文标题:嵌入式系统程序可移植性设计及性能优化
链接地址:https://www.777doc.com/doc-4225143 .html