嵌入式代码优化技巧:让你的程序飞起来!
“跑个LED呼吸灯,CPU占用飙到80%?
别急着换芯片,先把这几行代码改了再说。
”
——刚把这段吐槽发群里,五分钟就炸出十几条“我也是”。
嵌入式苦,苦在资源紧巴巴,还常被老板一句“加个小功能”逼到秃头。
下面这7招,全是真刀真枪在量产板上跑过的,不玩虚的,能省一个字节就省,能快一个时钟就快。
1. 查表法:别再算sin了,直接翻小抄
做电机FOC,sin、cos算一次得几十个周期,换成256点查表,Flash多占256字节,换来的是中断响应从12μs砍到3μs。
图像伽马校正、AES的S-box、FIR滤波系数,统统能塞表。
记得把表丢进.const段,让MCU的指令缓存吃现成的,别傻放RAM里。
2. 柔性数组+内存池:malloc的锅,不背
之前做LoRa传感器节点,动态分配搞得heap碎成渣,三天必重启。
后来换成柔性数组+4K预分配内存池:
```
typedef struct{
uint8_t len;
uint8_t data[];
}pkt_t;
```
池子里固定128字节块,data长度可变,碎片率直接归零。
实时性稳了,功耗也降,毕竟少了malloc那串折腾。
3. 位操作:别把CPU当傻子
Cortex-M3的BITBAND,一条指令翻转GPIO,比读改写快6倍。
CRC16用DSP的CLZ指令,8位数据流一次算完,省得软件循环啃半天。
写寄存器时,记住“读-改-写”三连击最费电,能位带就别手软。
4. 循环展开+SIMD:让NEON打群架
做720p MJPEG解码,8×8IDCT循环展开4次,再塞两条NEON指令,一帧时间从120ms压到35ms。
注意别展开过头,指令缓存撑爆反而更慢。
实测展开2~4次是甜点区。
5. 内联:别迷信static inline
GCC的LTO能跨文件内联,把关键路径的小函数全丢进.h里,加__attribute__((always_inline)),链接后一看,代码量居然还小了几百字节——编译器顺手把死代码也扬了。
副作用?
调试断点乱跳,忍忍就好。
6. 数据类型:float是电老虎
姿态解算算PID,原来全float,一次运算3mA电流。
换成Q15定点,误差不到0.1°,电流直接腰斩。8位颜色值就别uint32_t硬塞,结构体里用位域+手动对齐,省出来的RAM能多开一路ADC缓冲。
7. 循环顺序:别让缓存跑马拉松
二维数组按列访问?
Cache miss哭都没地儿哭。
改成行主序,再配个提前break:
```
for(i=0;i<len && !found;i++)
```
分支预测命中率飙到95%,功耗仪上的数字肉眼可见往下掉。
彩蛋:结构体对齐的骚操作
pragma pack
折中办法:把频繁访问的放前面,按4字节对齐,尾巴用charfiller[]凑整。
既不掉速,也不浪费。
最后提醒一句:先跑profiler,再动刀。
ARM DS-5抓一次热点,比盲改三天强。
优化到代码开始变丑时,停手——毕竟下个月还得自己维护。