在树莓派上操作GPIO

lgpio 库详解与使用指南

lgpio 是一个用于 Linux 系统的 GPIO(通用输入输出)控制库,专门为树莓派等单板计算机设计。它提供了高性能的 GPIO 操作接口,支持:

  • GPIO 读写操作
  • PWM 信号生成
  • 舵机控制
  • 中断处理
  • 硬件定时器

lgpio 安装方法

在树莓派上安装

# 更新系统
sudo apt update
sudo apt upgrade

# 安装 lgpio
sudo apt install python3-lgpio

# 或者使用 pip 安装
pip3 install lgpio

验证安装

import lgpio
print(lgpio.__version__)

核心功能

1. GPIO 设备管理

import lgpio

# 打开 GPIO 设备
handle = lgpio.gpiochip_open(0)  # 0 表示第一个 GPIO 控制器

# 关闭 GPIO 设备
lgpio.gpiochip_close(handle)

2. GPIO 配置

# 设置为输出模式
lgpio.gpio_claim_output(handle, gpio_pin, initial_value)

# 设置为输入模式
lgpio.gpio_claim_input(handle, gpio_pin)

# 设置为输入模式并启用上拉电阻
lgpio.gpio_claim_input(handle, gpio_pin, lgpio.PULL_UP)

3. GPIO 读写操作

# 写入 GPIO(输出模式)
lgpio.gpio_write(handle, gpio_pin, value)  # value: 0 或 1

# 读取 GPIO(输入模式)
value = lgpio.gpio_read(handle, gpio_pin)  # 返回 0 或 1

实际应用示例

示例 1:LED 控制

import lgpio
import time

class LEDController:
    def __init__(self, led_pin=18):
        self.led_pin = led_pin
        self.handle = None

    def init_led(self):
        """初始化 LED GPIO"""
        try:
            # 打开 GPIO 设备
            self.handle = lgpio.gpiochip_open(0)
            if self.handle < 0:
                print("无法打开 GPIO 设备")
                return False

            # 设置 LED 引脚为输出模式
            lgpio.gpio_claim_output(self.handle, self.led_pin, 0)
            print(f"LED 初始化成功,引脚: {self.led_pin}")
            return True

        except Exception as e:
            print(f"LED 初始化失败: {e}")
            return False

    def turn_on(self):
        """点亮 LED"""
        if self.handle is not None:
            lgpio.gpio_write(self.handle, self.led_pin, 1)
            print("LED 已点亮")

    def turn_off(self):
        """熄灭 LED"""
        if self.handle is not None:
            lgpio.gpio_write(self.handle, self.led_pin, 0)
            print("LED 已熄灭")

    def blink(self, times=5, interval=0.5):
        """LED 闪烁"""
        for i in range(times):
            self.turn_on()
            time.sleep(interval)
            self.turn_off()
            time.sleep(interval)

    def cleanup(self):
        """清理资源"""
        if self.handle is not None:
            lgpio.gpiochip_close(self.handle)
            self.handle = None
            print("LED 资源已清理")

# 使用示例
if __name__ == "__main__":
    led = LEDController(led_pin=18)

    try:
        if led.init_led():
            led.blink(3, 1.0)  # 闪烁 3 次,间隔 1 秒
    finally:
        led.cleanup()

示例 2:按钮输入检测

import lgpio
import time

class ButtonController:
    def __init__(self, button_pin=23):
        self.button_pin = button_pin
        self.handle = None
        self.last_state = None

    def init_button(self):
        """初始化按钮 GPIO"""
        try:
            self.handle = lgpio.gpiochip_open(0)
            if self.handle < 0:
                return False

            # 设置为输入模式,启用上拉电阻
            lgpio.gpio_claim_input(self.handle, self.button_pin, lgpio.PULL_UP)
            print(f"按钮初始化成功,引脚: {self.button_pin}")
            return True

        except Exception as e:
            print(f"按钮初始化失败: {e}")
            return False

    def read_button(self):
        """读取按钮状态"""
        if self.handle is not None:
            # 读取按钮状态(上拉电阻,按下为 0,松开为 1)
            state = lgpio.gpio_read(self.handle, self.button_pin)
            return state == 0  # 返回 True 表示按下

    def wait_for_press(self, timeout=None):
        """等待按钮按下"""
        start_time = time.time()

        while True:
            if self.read_button():
                return True

            if timeout and (time.time() - start_time) > timeout:
                return False

            time.sleep(0.01)  # 10ms 检测间隔

    def cleanup(self):
        """清理资源"""
        if self.handle is not None:
            lgpio.gpiochip_close(self.handle)
            self.handle = None

# 使用示例
if __name__ == "__main__":
    button = ButtonController(button_pin=23)

    try:
        if button.init_button():
            print("按下按钮...")
            if button.wait_for_press(timeout=10):
                print("按钮已按下!")
            else:
                print("等待超时")
    finally:
        button.cleanup()

示例 3:舵机控制

import lgpio
import time

class ServoController:
    def __init__(self, servo_pin=18):
        self.servo_pin = servo_pin
        self.handle = None

    def init_servo(self):
        """初始化舵机"""
        try:
            self.handle = lgpio.gpiochip_open(0)
            if self.handle < 0:
                return False

            # 设置舵机引脚为输出模式
            lgpio.gpio_claim_output(self.handle, self.servo_pin, 0)
            print(f"舵机初始化成功,引脚: {self.servo_pin}")
            return True

        except Exception as e:
            print(f"舵机初始化失败: {e}")
            return False

    def set_angle(self, angle):
        """设置舵机角度 (0-180度)"""
        if self.handle is None:
            print("舵机未初始化")
            return False

        try:
            # 计算脉冲宽度(微秒)
            min_pulse = 500   # 0.5ms
            max_pulse = 2500  # 2.5ms
            pulse_width = min_pulse + (angle / 180.0) * (max_pulse - min_pulse)

            # 使用 lgpio.tx_servo 控制舵机
            lgpio.tx_servo(self.handle, self.servo_pin, int(pulse_width))

            # 等待舵机转动
            time.sleep(0.5)

            # 停止 PWM 信号
            lgpio.tx_servo(self.handle, self.servo_pin, 0)

            print(f"舵机已转到 {angle} 度")
            return True

        except Exception as e:
            print(f"设置舵机角度失败: {e}")
            return False

    def cleanup(self):
        """清理资源"""
        if self.handle is not None:
            lgpio.tx_servo(self.handle, self.servo_pin, 0)
            lgpio.gpiochip_close(self.handle)
            self.handle = None
            print("舵机资源已清理")

# 使用示例
if __name__ == "__main__":
    servo = ServoController(servo_pin=18)

    try:
        if servo.init_servo():
            # 舵机转动演示
            angles = [0, 45, 90, 135, 180, 90, 0]
            for angle in angles:
                servo.set_angle(angle)
                time.sleep(1)
    finally:
        servo.cleanup()

高级功能

PWM 控制

# 设置 PWM 频率和占空比
lgpio.tx_pwm(handle, gpio_pin, frequency, duty_cycle)

# 停止 PWM
lgpio.tx_pwm(handle, gpio_pin, 0, 0)

中断处理

# 设置 GPIO 中断回调
lgpio.callback(handle, gpio_pin, lgpio.RISING_EDGE, callback_function)

硬件定时器

# 创建硬件定时器
timer = lgpio.timer_start(frequency, callback_function)

注意事项

  1. 权限要求:需要 root 权限或 gpio 组权限
  2. 引脚冲突:避免使用系统保留的引脚
  3. 资源管理:及时清理 GPIO 资源
  4. 错误处理:添加适当的异常处理
  5. 性能考虑:避免过于频繁的 GPIO 操作

常见问题解决

权限问题

# 将用户添加到 gpio 组
sudo usermod -a -G gpio $USER

# 重新登录后生效

引脚被占用

# 查看 GPIO 使用情况
gpioinfo

# 释放被占用的引脚
sudo gpio unexportall

性能优化

  • 使用适当的检测间隔
  • 避免在循环中进行不必要的 GPIO 操作
  • 考虑使用中断而不是轮询

总结

lgpio 是一个功能强大、性能优异的 GPIO 控制库,特别适合树莓派等单板计算机的硬件控制项目。通过合理使用其提供的功能,可以实现各种复杂的硬件控制应用。

GPIO 库对比:lgpio vs gpiozero vs RPi.GPIO

概述对比

特性lgpiogpiozeroRPi.GPIO
开发语言C (Python 绑定)PythonC (Python 绑定)
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
易用性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
功能完整性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
文档质量⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
社区支持⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

详细功能对比

1. 基础 GPIO 操作

lgpio

import lgpio

# 打开设备
handle = lgpio.gpiochip_open(0)

# 配置引脚
lgpio.gpio_claim_output(handle, 18, 0)
lgpio.gpio_claim_input(handle, 23, lgpio.PULL_UP)

# 读写操作
lgpio.gpio_write(handle, 18, 1)
value = lgpio.gpio_read(handle, 23)

# 清理
lgpio.gpiochip_close(handle)

gpiozero

from gpiozero import LED, Button

# 创建对象(自动配置)
led = LED(18)
button = Button(23, pull_up=True)

# 操作
led.on()
led.off()
led.toggle()

# 状态检测
if button.is_pressed:
    print("按钮被按下")

# 自动清理
led.close()
button.close()

RPi.GPIO

import RPi.GPIO as GPIO

# 设置模式
GPIO.setmode(GPIO.BCM)

# 配置引脚
GPIO.setup(18, GPIO.OUT)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# 操作
GPIO.output(18, GPIO.HIGH)
value = GPIO.input(23)

# 清理
GPIO.cleanup()

2. PWM 控制对比

lgpio

# 硬件 PWM,性能最佳
lgpio.tx_pwm(handle, 18, 1000, 50)  # 1kHz, 50% 占空比
lgpio.tx_servo(handle, 18, 1500)     # 舵机控制

gpiozero

from gpiozero import PWMLED, Servo

# 软件 PWM
led = PWMLED(18)
led.pulse()  # 自动脉冲

servo = Servo(18)
servo.mid()  # 中间位置

RPi.GPIO

# 软件 PWM
pwm = GPIO.PWM(18, 1000)  # 1kHz
pwm.start(50)              # 50% 占空比
pwm.stop()

3. 中断处理对比

lgpio

def callback_function(gpio, level, tick):
    print(f"GPIO {gpio} 状态变化: {level}")

# 设置中断
lgpio.callback(handle, 23, lgpio.RISING_EDGE, callback_function)

gpiozero

from gpiozero import Button

def button_pressed():
    print("按钮被按下")

button = Button(23)
button.when_pressed = button_pressed

RPi.GPIO

def callback_function(channel):
    print(f"GPIO {channel} 中断触发")

GPIO.add_event_detect(23, GPIO.RISING, callback=callback_function)

性能对比

延迟测试结果

操作类型lgpiogpiozeroRPi.GPIO
GPIO 写入延迟~1μs~50μs~10μs
GPIO 读取延迟~1μs~50μs~10μs
PWM 精度硬件级软件级软件级
中断响应~5μs~100μs~20μs

资源占用

指标lgpiogpiozeroRPi.GPIO
CPU 占用最低中等
内存占用最低中等
启动时间

代码复杂度对比

LED 控制

  • lgpio(最复杂)
import lgpio
import time

handle = lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(handle, 18, 0)

try:
    while True:
        lgpio.gpio_write(handle, 18, 1)
        time.sleep(1)
        lgpio.gpio_write(handle, 18, 0)
        time.sleep(1)
finally:
    lgpio.gpiochip_close(handle)
  • gpiozero(最简单)
from gpiozero import LED
import time

led = LED(18)

try:
    led.blink()
    time.sleep(10)
finally:
    led.close()
  • RPi.GPIO(中等)
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

try:
    while True:
        GPIO.output(18, GPIO.HIGH)
        time.sleep(1)
        GPIO.output(18, GPIO.LOW)
        time.sleep(1)
finally:
    GPIO.cleanup()

安装和配置对比

  • lgpio
# 安装
sudo apt install python3-lgpio

# 权限配置
sudo usermod -a -G gpio $USER

# 验证
python3 -c "import lgpio; print('安装成功')"
  • gpiozero
# 安装
sudo apt install python3-gpiozero

# 权限配置(通常自动配置)
# 无需额外配置

# 验证
python3 -c "from gpiozero import LED; print('安装成功')"
  • RPi.GPIO
# 安装
sudo apt install python3-rpi-lgpio
sudo apt install python3-rpi.gpio

# 权限配置
sudo usermod -a -G gpio $USER

# 验证
python3 -c "import RPi.GPIO; print('安装成功')"

迁移指南

从 RPi.GPIO 迁移到 lgpio

# 旧代码 (RPi.GPIO)
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
GPIO.output(18, GPIO.HIGH)

# 新代码 (lgpio)
import lgpio
handle = lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(handle, 18, 1)
lgpio.gpio_write(handle, 18, 1)

从 gpiozero 迁移到 lgpio

# 旧代码 (gpiozero)
from gpiozero import LED
led = LED(18)
led.on()

# 新代码 (lgpio)
import lgpio
handle = lgpio.gpiochip_open(0)
lgpio.gpio_claim_output(handle, 18, 0)
lgpio.gpio_write(handle, 18, 1)

遇到的问题


  1. 树莓派 5 报告 RuntimeError: Cannot determine SOC peripheral base address

在树莓派上可以理解 RPI.GPIO 是作为一个前端组件,简化了对 GPIO 的操作,但其还需要后端的支持,在树莓派 5 上需要 lpgio 的支持,可以通过以下指令安装,安装完成后,可以继续使用 RPI.GPIO.

sudo apt install python3-rpi-lgpio