从事嵌入式软件开发的坛友们,因为MCU的flash资源有限,可能会经常通过一些优化操作来节约MCU的flash空间资源,今天就带大家一起看下哪些方法可以起到优化的作用。 一、 编程技巧与代码设计 这是最有效的方法,好的编程习惯能从源头上减少代码量。 1、尽量避免使用浮点数 原因:大多数低端MCU没有硬件浮点单元,浮点运算需要通过软件库实现,非常消耗flash 和CPU时间。 对策: 使用定点数运算。例如,将电压值 3.3V 用整数 3300 表示,计算时记住小数点的位置。 如果必须用浮点,考虑使用 float 而非 double,因为 double 精度更高,占用的空间和处理代码也更多。 2、精简库函数和避免冗余功能 原因:像 printf、sprintf 这样的标准库函数非常强大,但也非常臃肿。 对策: 使用精简版的库,例如 printf 替换为iprintf(用于整数)或自己实现一个最基础的串口输出函数。 很多HAL库(如STM32的HAL)提供了代码裁剪功能,在配置头文件里禁用不用的外设和功能模块。 3、使用更小的数据类型 原则:根据数据实际可能的最大值来选择数据类型。 例子: 一个循环计数器如果不会超过 255,就用 uint8_t 而不是 int。 标志位使用 bool 或 uint8_t,而不是 int。 使用位域来紧凑存储多个布尔标志。 4、使用 const 和 static 合理放置数据 const:将只读数据(如查找表、字符串常量)声明为 const,它们会被放入flash而不是RAM。但要警惕,大的查找表依然是flash杀手。 static:对函数使用 static,如果编译器启用了链接时优化,可以帮助编译器判断该函数是否只在当前文件使用,从而可能被内联或更激进地优化。 5、减少函数调用层次和内联小函数 深层调用:过多的函数调用层次会增加栈操作的开销和代码量。 内联:对于非常短小、频繁调用的函数,可以使用 inline 关键字建议编译器将其内联展开,消除函数调用的开销。但要注意,过度内联会使代码膨胀。 宏:对于极其简单的操作,可以考虑使用宏来替代函数,但宏有自身的缺点(无类型检查、易出错)。 6、优化字符串处理 原因:字符串是flash的一大占用项。 对策: 避免在代码中直接使用冗长的字符串,尤其是 printf 中的格式字符串。 使用缩写或代码来代替完整的字符串输出。 如果有多国语言支持,考虑将字符串存储在外部存储器中,而不是全部塞进flash。 7、使用查表法代替复杂计算 对于一些耗时的复杂计算(如三角函数、对数),如果值域是有限的,可以预先计算好结果并做成查找表存入flash。这通常比实时计算库的代码量要小,而且速度更快。 二、 编译器优化 这个方法简单有效,编译器是你最重要的优化工具。 1、选择优化等级 -Os:这是最常用的优化选项,意为 Optimizefor size。编译器会优先考虑生成更小的代码,而不是极致的速度。 -O2/-O1:在速度和大小之间取得平衡。 -O3:优先考虑速度,可能会通过循环展开等方式增加代码大小,慎用。 在IDE(如 Keil, IAR, ESP-IDF, Arduino)中,通常可以在项目属性中方便地设置优化等级。 2、启用链接时优化 作用:传统的编译优化是在单个源文件(.c)层面进行的。LTO 允许编译器在链接所有文件时进行全局优化,可以更安全地移除未使用的代码和函数。 使用方法:在 GCC 中,编译和链接时都加上 -flto 选项。现代嵌入式工具链普遍支持。 3、函数级链接和垃圾收集 作用:告诉链接器只将库中和实际被调用的函数链接到最终镜像中,而不是链接整个库文件。 在GCC 中:使用 -ffunction-sections -fdata-sections 编译选项,然后使用 -Wl,--gc-sections 链接选项。 综上,介绍了一些优化flash内存空间资源的方法,希望可以帮上你。
|