📊 为什么SSD1306的y坐标必须是8的倍数?


一、核心原因:SSD1306的页式(Page-based)显存结构

SSD1306驱动的128×64 OLED屏幕,显存不是按「像素行」存储的,而是按页(Page) 组织的,这是硬件设计的底层逻辑:

  1. 页的定义:屏幕被垂直划分为 8个页(Page 0 ~ Page 7),每个页固定对应 8行像素(1页=8行)
    • Page 0:y=0 ~ y=7
    • Page 1:y=8 ~ y=15
    • ...
    • Page 7:y=56 ~ y=63
  2. 字节与页的对应:每个页的一行像素,用 1个字节(8位) 存储,1位对应1个像素的亮灭(1=亮,0=灭)
    • 1个字节刚好控制1行里的8个像素,1个页(8行)就用8×128个字节存储整页数据
  3. 函数的y参数本质ssd1306_drawXBitmap 里的 y不是像素行号,而是「页号」
    • 要显示在y=0~7的像素区域,y参数填 0(0/8=0)
    • 要显示在y=8~15的像素区域,y参数填 1(8/8=1)
    • 以此类推,y参数必须是整数,因此实际像素y坐标必须是8的倍数,才能对应到完整的页

二、举个例子,一眼看懂

假设你要显示一个高度为16的位图:

  • 实际像素y坐标:16(从第16行开始显示)
  • 函数y参数:16 / 8 = 2(对应Page 2,y=16~23)
  • 位图高度16,会自动占用 Page 2(16~23行) + Page 3(24~31行) 两个页,完美覆盖16行像素

如果y坐标不是8的倍数(比如y=5):

  • 5 / 8 = 0.625,不是整数,无法对应到具体的页,硬件无法定位显存位置,会出现显示错乱、花屏、内容错位的问题

三、补充:x坐标为什么没有这个限制?

x轴是按列(Column) 寻址的,每列对应1个像素,128列对应x=0~127,没有按字节分组的限制,因此x坐标可以是0~127的任意整数,不需要是8的倍数。


四、实际开发的注意事项

  1. y坐标计算:实际像素y坐标 ÷ 8 = 函数的y参数,结果必须是整数
    • 比如要垂直居中显示高度为16的位图:
      • 屏幕总高度64,起始像素y = (64 - 16) / 2 = 24
      • 函数y参数 = 24 / 8 = 3
  2. 位图高度要求:位图高度也建议是8的倍数(如8、16、32、64),否则会出现页内像素截断、显示不全的问题
  3. 非8倍数y坐标的解决方案:如果需要精细定位,只能通过软件偏移(比如在图片数据里加空白行),硬件本身不支持非页对齐的y坐标

1 条评论

  • @ 2026-4-5 16:40:43

    📋 128×64 OLED 屏幕 y 坐标速查表(SSD1306 专用)


    一、核心对应关系(页号 = 像素y ÷ 8)

    SSD1306 屏幕总高度 64 像素(y=0~63),垂直划分为 8 个页(Page 0~7),每个页对应 8 行像素,函数入参 y = 像素起始y ÷ 8(必须为整数)

    页号(函数y参数) 对应像素y范围 适用场景示例
    0 0 ~ 7 屏幕最顶部显示(标题栏、图标)
    1 8 ~ 15 第2行文字/图形
    2 16 ~ 23 第3行文字/图形
    3 24 ~ 31 屏幕垂直居中区域(常用)
    4 32 ~ 39 下半部分上半区
    5 40 ~ 47 第6行文字/图形
    6 48 ~ 55 第7行文字/图形
    7 56 ~ 63 屏幕最底部显示(状态栏、版权信息)

    二、常用位图高度的垂直居中速查

    直接套用,不用再计算!

    位图高度h 屏幕总高度 像素起始y(居中) 函数y参数(y÷8) 占用页号
    8 64 (64-8)/2 = 28 ❌(非8倍数,不支持) - 无(需调整h为16)
    16 (64-16)/2 = 24 ✅ 24÷8 = 3 Page 3、4
    32 (64-32)/2 = 16 ✅ 16÷8 = 2 Page 2、3、4、5
    64 0 ✅ 0÷8 = 0 全部8个页(全屏)

    ⚠️ 注意:位图高度h也建议为8的倍数,否则会出现页内像素截断、显示不全的问题。如果h不是8的倍数,需要在图片数据中补空白行,让总高度凑成8的倍数。


    三、常用文字行高对应(8x16 字体为例)

    少儿编程中最常用的 8x16 中文字体,每个字高度 16 像素(占2个页),行高对应如下:

    文字行数 像素起始y 函数y参数 对应页号
    第1行 0 Page 0、1
    第2行 16 2 Page 2、3
    第3行 32 4 Page 4、5
    第4行 48 6 Page 6、7

    四、代码示例(直接套用)

    1. 居中显示 64×16 位图

    // 屏幕128×64,位图宽64、高16,水平+垂直居中
    // x = (128-64)/2 = 32,y = (64-16)/2 = 24 → 函数y=24/8=3
    ssd1306_drawXBitmap(32, 3, 64, 16, image_data);
    

    2. 底部显示 64×8 状态栏

    // 位图高8,像素起始y=64-8=56 → 函数y=56/8=7
    ssd1306_drawXBitmap(0, 7, 64, 8, status_bar_data);
    

    五、避坑小贴士

    1. y参数不是像素坐标:函数里的y是「页号」,不是像素行号,千万不要直接填像素y!
    2. 非8倍数y的处理:如果需要精细定位,只能在图片数据里加空白行,硬件不支持非页对齐的y坐标
    3. x坐标无限制:x轴按列寻址,0~127任意整数都可以,不需要是8的倍数
    4. 高度溢出检查:位图高度h + 像素起始y ≤ 64,否则会超出屏幕显示不全
    • 1