[学习资料] 如何做OLED 屏幕绘图函数中节约存储空间

[复制链接]
 楼主| 小明的同学 发表于 2025-6-20 19:56 | 显示全部楼层 |阅读模式
核心优化策略

1. 分页缓冲机制 (Page Buffering)
传统方法:全帧缓冲 (1024字节 for 128x64)

优化方法:按页处理 (8页 × 128字节 = 1024字节 → 单页 128字节)

  1. // 分页绘图函数
  2. void draw_horizontal_line_page(uint8_t page, uint8_t start_x, uint8_t end_x) {
  3.     uint8_t buf[128];
  4.     read_page(page, buf); // 读取当前页
  5.    
  6.     for(uint8_t x = start_x; x <= end_x; x++) {
  7.         buf[x] |= 0x01; // 设置最低位 (y0)
  8.     }
  9.    
  10.     write_page(page, buf); // 写回修改
  11. }
节省:RAM 从 1024字节 → 128字节 (减少 87.5%)

2. 直接显存操作 (Zero-Buffer)
适用场景:简单图形(直线、矩形)

原理:不读回显存,直接写入修改

  1. void draw_vertical_line(uint8_t x, uint8_t start_page, uint8_t end_page) {
  2.     for(uint8_t page = start_page; page <= end_page; page++) {
  3.         set_cursor(x, page);
  4.         write_data(0xFF); // 整列点亮
  5.     }
  6. }
优势:零缓冲区需求,Flash 占用减少 30%


3. 位运算图形绘制
高效绘制基础图形:

  1. // 绘制矩形框 (无填充)
  2. void draw_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
  3.     draw_h_line(y1/8, x1, x2, 1 << (y1%8));     // 上边
  4.     draw_h_line(y2/8, x1, x2, 1 << (y2%8));     // 下边
  5.     draw_v_line(x1, y1/8, y2/8, 1 << (y1%8));   // 左边
  6.     draw_v_line(x2, y1/8, y2/8, 1 << (y1%8));   // 右边
  7. }
4. 精简算法实现
Bresenham 直线算法优化:

  1. void draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
  2.     int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
  3.     int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
  4.     int err = dx+dy, e2; /* error value e_xy */
  5.    
  6.     while(1) {
  7.         draw_pixel(x0, y0);
  8.         if (x0==x1 && y0==y1) break;
  9.         e2 = 2*err;
  10.         if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
  11.         if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
  12.     }
  13. }
特点:纯整数运算,无浮点,代码精简 (约 200 字节)
 楼主| 小明的同学 发表于 2025-6-20 19:57 | 显示全部楼层
数据存储优化

1. 字体压缩技术
位图垂直存储:

  1. // 传统: 5x8字体 = 5字节/字符 (ASCII 95字符 = 475字节)
  2. // 优化:
  3. const uint8_t font_5x8[] PROGMEM = {
  4.     0x00,0x00,0x00,0x00,0x00, // 空格 (32)
  5.     0x00,0x00,0x5F,0x00,0x00, // ! (33)
  6.     // ...
  7. };
RLE 压缩字体:
  1. // 行程编码压缩
  2. const uint8_t font_compressed[] = {
  3.     0x03, 0x00, // 3字节0x00 (空格)
  4.     0x01, 0x5F, 0x02, 0x00, // !: [0x5F] + 2字节0x00
  5.     // ...
  6. };
2. 位图处理优化
分块存储位图:


  1. // 128x64 位图 → 分8页存储
  2. const uint8_t bitmap_page0[] = { ... }; // 第0页数据
  3. const uint8_t bitmap_page1[] = { ... }; // 第1页数据
  4. // ...
XBM 格式直接使用:
  1. // XBM 是C数组格式,可直接编译
  2. const uint8_t **_bits[] = {
  3.     0x00, 0x18, 0x3C, 0x7E, // ...
  4. };





 楼主| 小明的同学 发表于 2025-6-20 19:58 | 显示全部楼层
架构级优化

1. 选择性功能编译

  1. // 在头文件中定义功能开关
  2. #define ENABLE_CIRCLE   0
  3. #define ENABLE_TRIANGLE 0
  4. #define ENABLE_FILL     1

  5. #if ENABLE_CIRCLE
  6. void draw_circle(...) { ... }
  7. #endif
2. 模块化链接
分离核心与扩展功能:

ssd1306_core.c (必备功能: 文本/点/线)

ssd1306_gfx.c (扩展图形: 圆/多边形)

链接时排除未使用模块



 楼主| 小明的同学 发表于 2025-6-20 19:59 | 显示全部楼层
资源节省对比表

优化技术
RAM 节省
Flash 节省
适用场景
分页缓冲机制896字节 (87.5%)无变化所有图形操作
直接显存操作100% (零缓冲)减少 20-40%简单几何图形
Bresenham 算法无变化减少 50-70%直线/圆绘制
字体垂直存储无变化减少 30-50%文本显示
RLE 字体压缩增加 10-20字节减少 40-60%中大型字体集
功能选择性编译无变化减少 20-80%功能定制化项目


 楼主| 小明的同学 发表于 2025-6-20 19:59 | 显示全部楼层
实战建议组合
基础显示需求 (传感器数据):

直接显存操作 + 精简字体

预计占用:< 1.5KB Flash + 50字节 RAM

图形界面需求 (简单菜单):

分页缓冲 + Bresenham算法 + 垂直字体

预计占用:~3KB Flash + 128字节 RAM

复杂图形应用 (波形显示):

分页缓冲 + 所有优化算法 + 选择性编译

预计占用:4-6KB Flash + 256字节 RAM
 楼主| 小明的同学 发表于 2025-6-20 20:00 | 显示全部楼层
终极优化技巧

  1. // 使用位域极致压缩图形状态
  2. struct {
  3.     uint8_t color : 1;   // 1位存储颜色
  4.     uint8_t reserved : 7;
  5. } pixel_state;

  6. // PROGMEM 存储大型资源
  7. const uint8_t large_bitmap[1024] PROGMEM = { ... };

  8. // 内联关键函数
  9. static inline void __attribute__((always_inline))
  10. set_pixel(uint8_t x, uint8_t y) {
  11.     // 内联汇编优化
  12.     asm volatile(
  13.         "lds r24, 0x%0" :: "i" (display_buffer)
  14.     );
  15. }
黄金法则:优先优化算法而非数据,80%的性能提升来自20%的关键算法优化。实际项目中,分页缓冲+直接显存操作的组合通常能提供最佳性价比。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

158

主题

1637

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部