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

树莓派3B GPIO引脚线程编程问题:双编码器同步读取异常

树莓派3B GPIO线程读取编码器的问题解决与注意事项

代码核心错误分析

你的代码里有两个直接导致第二个线程无法执行的问题:

  1. Thread的target参数传递错误:你写的target = encoder_right(t1)是直接调用了函数,而非传递函数对象。如果encoder_right是死循环(编码器读取通常需要持续运行),主线程会卡在执行这个函数的步骤,根本到不了创建Thread2的环节。
  2. 线程等待逻辑错误:最后一行重复调用了Thread1.join(),应该改为Thread2.join(),否则主线程只会等待第一个线程结束,不会处理第二个线程。

树莓派3B GPIO使用线程的注意事项

  • GPIO初始化(模式设置、引脚输入输出配置、上拉下拉设置)必须在主线程完成,禁止在子线程中重复配置,否则会引发资源冲突。
  • 多线程共享的变量(比如编码器计数)必须用threading.Lock保护,避免多个线程同时读写导致计数混乱。
  • 如果用GPIO中断触发编码器计数,RPi.GPIO的中断回调本身会在独立线程运行,此时要注意和自定义线程的资源竞争,同样需要用锁保护共享数据。
  • Daemon线程会在主线程结束时被强制终止,如果需要编码器线程持续运行,要么让主线程保持存活,要么不要设置daemon=True,同时正确调用join()等待所有子线程结束。
  • 高频读取编码器脉冲时,要给线程加短延时(比如time.sleep(0.001)),避免过度占用CPU资源。

修正后的完整代码示例

from threading import Thread, Lock
import RPi.GPIO as GPIO
import time
from datetime import datetime

# 共享计数变量,用锁保护避免多线程冲突
right_count = 0
left_count = 0
count_lock = Lock()

# 编码器引脚定义(根据实际接线修改)
RIGHT_ENCODER_A = 17
RIGHT_ENCODER_B = 27
LEFT_ENCODER_A = 22
LEFT_ENCODER_B = 23

def encoder_right(start_time):
    global right_count
    # 增量编码器AB相计数逻辑示例,需根据硬件调整
    last_a_state = GPIO.input(RIGHT_ENCODER_A)
    while True:
        current_a_state = GPIO.input(RIGHT_ENCODER_A)
        current_b_state = GPIO.input(RIGHT_ENCODER_B)
        # 当A相电平变化时,根据B相判断转向并计数
        if current_a_state != last_a_state:
            with count_lock:
                if current_b_state != current_a_state:
                    right_count += 1
                else:
                    right_count -= 1
            last_a_state = current_a_state
        time.sleep(0.001)

def encoder_left(start_time):
    global left_count
    last_a_state = GPIO.input(LEFT_ENCODER_A)
    while True:
        current_a_state = GPIO.input(LEFT_ENCODER_A)
        current_b_state = GPIO.input(LEFT_ENCODER_B)
        if current_a_state != last_a_state:
            with count_lock:
                if current_b_state != current_a_state:
                    left_count += 1
                else:
                    left_count -= 1
            last_a_state = current_a_state
        time.sleep(0.001)

# 主线程初始化GPIO
GPIO.setmode(GPIO.BCM)
# 设置编码器引脚为输入,带上拉电阻(根据编码器类型选择上拉/下拉)
GPIO.setup(RIGHT_ENCODER_A, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(RIGHT_ENCODER_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(LEFT_ENCODER_A, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(LEFT_ENCODER_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)

t1 = datetime.now()

# 正确创建线程:target传函数对象,args传参数元组
Thread1 = Thread(target=encoder_right, args=(t1,), daemon=True)
Thread2 = Thread(target=encoder_left, args=(t1,), daemon=True)

# 启动线程
Thread1.start()
Thread2.start()

# 主线程保持运行,实时打印计数
try:
    while True:
        with count_lock:
            print(f"右轮计数: {right_count}, 左轮计数: {left_count}")
        time.sleep(1)
except KeyboardInterrupt:
    # 捕获Ctrl+C,清理GPIO资源
    GPIO.cleanup()
    print("程序已退出")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:46:28