You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带旋转编码器的OLED键盘菜单与密码输入功能故障求助

问题排查与解决方案

一、旋转编码器菜单切换不稳定问题

编码器切换异常基本是硬件抖动或软件逻辑漏洞导致,新手常踩这两个坑:

  • 硬件层面:编码器引脚未加下拉/上拉电阻,或接线松动引发信号干扰。如果用树莓派这类带内部上拉的板子,必须在代码里启用内部上拉。
  • 软件层面:无防抖处理,或旋转方向判断逻辑有缺陷(比如只检测单引脚电平变化,未结合前后状态对比),导致误判旋转方向或重复触发。

代码修改建议(编码器部分)

  1. 启用引脚内部上拉:
    import RPi.GPIO as GPIO
    import time
    
    # 替换为你的实际引脚
    CLK_PIN = 17
    DT_PIN = 27
    SW_PIN = 22
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(CLK_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(DT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(SW_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
  2. 增加双重防抖+状态跟踪的旋转判断逻辑:
    last_clk_state = GPIO.input(CLK_PIN)
    current_menu_index = 0
    menu_items = ["详情页", "设置模式"]  # 替换为你的菜单列表
    
    def encoder_callback(channel):
        global last_clk_state, current_menu_index
        clk_state = GPIO.input(CLK_PIN)
        dt_state = GPIO.input(DT_PIN)
    
        # 仅在CLK电平变化时触发判断,避免无效触发
        if clk_state != last_clk_state:
            # 手动防抖:忽略短时间内的电平波动
            time.sleep(0.01)
            clk_state = GPIO.input(CLK_PIN)
            dt_state = GPIO.input(DT_PIN)
    
            if clk_state != last_clk_state:
                # 根据CLK与DT的电平差判断旋转方向
                if dt_state != clk_state:
                    current_menu_index = (current_menu_index + 1) % len(menu_items)
                else:
                    current_menu_index = (current_menu_index - 1) % len(menu_items)
                update_menu_display()  # 替换为你的菜单刷新函数
        last_clk_state = clk_state
    
    # 绑定中断,内置防抖+自定义防抖双重保障
    GPIO.add_event_detect(CLK_PIN, GPIO.BOTH, callback=encoder_callback, bouncetime=20)
    
    用% len(menu_items)确保索引不会越界,彻底避免跳转到错误页面。

二、键盘页面底部内容截断与行间距错误问题

SSD1306 128x64的像素高度为64,默认8x8字体下最多显示8行(64÷8=8)。行间距错误或内容行数超限,都会导致重叠、截断。

问题分析与代码修改

  1. 行间距错误:确保每行的y坐标是8的倍数(比如第一行y=0,第二行y=8,以此类推),禁止手动设置不规则间距。
  2. 底部内容截断:若键盘元素过多,需做分页显示(比如小写一页、大写+功能键一页),或调整布局压缩无效间隔。

代码修改建议(OLED显示部分)

假设使用ssd1306库,键盘页面绘制逻辑调整如下:

from ssd1306 import SSD1306_I2C
import smbus2

i2c = smbus2.SMBus(1)
oled = SSD1306_I2C(128, 64, i2c)

def draw_keyboard_page(current_char_idx):
    oled.fill(0)
    # 拆分键盘布局为4行,适配OLED最大显示行数
    keyboard_rows = [
        ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
        ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
        ['Z', 'X', 'C', 'V', 'B', 'N', 'M'],
        ['←', ' ', '确认']
    ]

    start_y = 0
    for row_idx, row in enumerate(keyboard_rows):
        # 计算每行起始x坐标,让内容居中显示
        row_total_width = len(row)*8 + (len(row)-1)*2  # 字符宽度+间隔
        start_x = (128 - row_total_width) // 2
        current_x = start_x

        for char in row:
            oled.text(char, current_x, start_y)
            current_x += 8 + 2  # 字符宽度+间隔
        start_y += 8

        # 超出OLED高度则停止绘制(避免底部截断)
        if start_y >= 64:
            break

    # 绘制选中字符的标记(示例:下划线)
    # 此处省略标记逻辑,确保不超出底部边界
    oled.show()
  • 用start_y +=8保证行间距一致,彻底解决行重叠问题。
  • 通过居中计算避免左右偏移导致的内容截断,若需更多功能键,直接做分页切换即可。

内容的提问来源于stack exchange,提问作者Myles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:37:19