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

树莓派5 Python3读取编码器GPIO报错,求GPIOZero替代实现方案

树莓派5使用GPIOZero读取旋转编码器数据

问题背景

在树莓派5上使用RPi.GPIO库读取编码器数据时,出现错误:RuntimeError: cannot determine SOC peripheral base address。这是因为树莓派5采用了全新的RP1 GPIO控制器,而RPi.GPIO库尚未适配该硬件,因此需要改用官方推荐的GPIOZero库实现功能。

原RPi.GPIO代码:

import RPi.GPIO as GPIO
from time import sleep
global counter
counter = 0
Enc_A = 17
Enc_B = 27

def init():
    GPIO.setwarnings(True)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(Enc_A, GPIO.IN)
    GPIO.setup(Enc_B, GPIO.IN)
    GPIO.add_event_detect(Enc_A,GPIO.RISING, callback=rotation_decode, bouncetime=1)
    return

def rotation_decode(Ebc_A):
    global counter
    Switch_A = GPIO.input(Enc_A)
    Switch_B = GPIO.input(Enc_B)

    if (Switch_A == 1) and (Switch_B == 0):
        counter += 1
        print (counter)
        while Switch_B == 0:
            Switch_B = GPIO.input(Enc_B)
        while Switch_B == 1:
            Switch_B = GPIO.input(Enc_B)
        return
    
    elif (Switch_A == 1) and (Switch_B == 1):
        counter -= 1
        print (counter)
        while Switch_A == 1:
            Switch_A = GPIO.input(Enc_A)
        return
    
    else:
        return
    
def main():
    try:
        init()
        while True:
            sleep(1)
    except KeyboardInterrupt:
        GPIO.cleanup()

if __name__ == '__main__':
    main()

解决方案(GPIOZero实现)

GPIOZero是树莓派官方推荐的GPIO控制库,原生支持树莓派5的RP1控制器,且API更简洁,自带防抖处理。以下是适配后的编码器读取代码:

from gpiozero import Button
from signal import pause

# 编码器引脚配置(BCM编号,与原代码一致)
ENC_A = Button(17, pull_up=True, bounce_time=0.01)  # 防抖时间10ms
ENC_B = Button(27, pull_up=True, bounce_time=0.01)

counter = 0
last_a_state = ENC_A.is_pressed  # 初始化A引脚状态

def update_counter():
    global counter, last_a_state
    current_a = ENC_A.is_pressed
    current_b = ENC_B.is_pressed

    # 仅当A引脚状态变化时处理(避免重复触发)
    if current_a != last_a_state:
        # 根据A、B引脚的相对状态判断旋转方向
        if current_b != current_a:
            counter += 1  # 正转
        else:
            counter -= 1  # 反转
        print(f"当前计数: {counter}")
        last_a_state = current_a

# 为A引脚的按下和释放事件绑定回调
ENC_A.when_pressed = update_counter
ENC_A.when_released = update_counter

try:
    pause()  # 阻塞程序,等待事件触发
except KeyboardInterrupt:
    print("\n程序已退出")

代码说明

  • 引脚初始化:Button类默认启用内部上拉电阻(pull_up=True),无需额外配置;bounce_time参数设置防抖时间,避免机械抖动导致的误触发。
  • 旋转方向判断:通过对比A、B引脚的实时状态,当A引脚状态变化时,若B引脚状态与A相反则为正转,相同则为反转。
  • 事件处理:利用GPIOZero的事件回调机制,无需手动轮询引脚状态,程序效率更高。
  • 退出处理:pause()会保持程序运行,按下Ctrl+C时会触发KeyboardInterrupt,自动清理GPIO资源。

内容的提问来源于stack exchange,提问作者Civil.Shakeri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:46:27