使用I2C在树莓派上用Python实现软件PWM

1 投票
1 回答
1422 浏览
提问于 2025-04-18 17:54

我正在寻找一个解决方案,想用mcp23017这个GPIO扩展器和树莓派来做LED调光器,但每隔4到5秒就会出现短暂的闪烁。我发现即使直接使用GPIO,也会出现这种闪烁(如果你试的话,可以在代码中注释或取消注释相关部分)。

我不能使用rpi.gpio的软PWM或pi-blaster,因为它们无法通过I2C使用。如果你有办法让这些软件适用于I2C,那就太好了。

我觉得问题可能出在GPIO的地址处理上,但我搞不清楚具体是什么。

--更新-- 在树莓派上,使用软件是无法获得稳定的时间控制的。

#!/usr/bin/python
# -*- coding: utf-8 -*-

# uncomment line 14-20 for using I2C and comment line 24-35, switch for using GPIO directly

import smbus
import time
import RPi.GPIO as GPIO

liste = [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# print liste #debugging ...
periodendauer = 0.001 # means 1000Hz

# # to send data to mcp23017
# b = smbus.SMBus(1) # 0 indicates /dev/i2c-0, muss auf 1 stehen (für rev2)
# while True:
    # for values in liste:
        # b.write_byte_data(0x20,0x14,values) #send data via smbus(I2C) to mcp23017
        # # print values #debugging only
        # time.sleep(periodendauer)


# to send data direct to gpio-pin
GPIO.cleanup()
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
while True:
    for values in liste:
        if values > 0:
            values = True
        else:
            values = False
        GPIO.output(7,values)
        # print values #debugging only
        time.sleep(periodendauer)

1 个回答

-1

根据评论,我重新写了我的回答来回应你的问题。

我简化了你的应用程序,去掉了I2C部分和注释,也删掉了睡眠函数。这样做是为了让你看到,树莓派在你想要的那种精确计时上是多么不可靠。我在你的代码中添加了一个时间测量,记录了for循环开始和结束的时间,所以现在它测量的是整个“liste”数组的处理时间,而不是单个“values”的长度。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import time
import RPi.GPIO as GPIO
import sys

liste = [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0]

GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
while True:
    ms = time.time() * 1000.0
    for values in liste:
        if values > 0:
            values = True
        else:
            values = False
        GPIO.output(7,values)
    me = time.time() * 1000.0 - ms
    sys.stdout.write("\r{0:4.4f}".format(me)),
    sys.stdout.flush()

我家里有一块香蕉派,它的GPIO输出和树莓派一样,但请在树莓派上运行,你会得到相同的结果(可能循环时间会更长)。对我来说,结果在4到5毫秒之间,有时会出现6毫秒的脉冲,有时甚至超过10毫秒。这就是为什么你的LED会闪烁的原因。

如果你想要基于I2C的解决方案,我建议使用专门的I2C PWM驱动板,比如NXP的PCA9685,这样可以产生平滑的PWM信号。

撰写回答