[tool] spi ws2812

This commit is contained in:
IrvingGao 2024-06-26 22:42:20 +08:00
parent 2040e3384c
commit 0e647e2e53
1 changed files with 96 additions and 69 deletions

View File

@ -1,71 +1,98 @@
import wiringpi
import time import time
import spidev
# LED灯的数量 import wiringpi
LED_N = 8
# 0码 t0H 220ns~380ns
# GPIO针脚确保这是能够输出PWM信号的针脚比如18 # python 中GPIO口无法翻转这么快python 可能执行一行代码需要800ns
GPIO_PIN = 12 # ws2812 波特率如果设置为800kHZ, 1/0.8M=1.25us (0码或者1码所需要的时间)
# 初始化WiringPi # 使用SPI产生ws2812时序产生1码和0码则可以使用传输一个byte 来代表一个0码或者1码如下
wiringpi.wiringPiSetupGpio() # 1111 1000 0xF8 #1码 高电平时间长,低电平时间短
wiringpi.pinMode(GPIO_PIN, wiringpi.OUTPUT) # 1100 0000 0xC0 #0码 高电平时间短,低电平时间长
# 则得出SPI 波特率应该设置为800K*8
# 发送单个bit
def sendBit(value, isLastBit=False): sig_1 = 0xf8
HIGH_TIME_NS = 300 # 高电平时间约为0.3us (300ns),可能需要根据实际情况调整 sig_0 = 0xc0
LOW_TIME_NS = 900 # 低电平时间约为0.9us (900ns)适用于大约1/3的时间为高电平的情况
HALF_PERIOD_NS = HIGH_TIME_NS + LOW_TIME_NS
def flatten_arrays(arrays):
if value: return [element for sublist in arrays for element in sublist]
wiringpi.digitalWrite(GPIO_PIN, 1)
time.sleep(HIGH_TIME_NS / 1000000)
else: class WS2812:
wiringpi.digitalWrite(GPIO_PIN, 0) def __init__(self, led_num=1):
time.sleep(HIGH_TIME_NS / 1000000) self.led_num = led_num
self.ws2812_data = [[sig_0 for _ in range(24)] for _ in range(led_num)]
wiringpi.digitalWrite(GPIO_PIN, 0) spi = spidev.SpiDev()
if not isLastBit:
time.sleep(LOW_TIME_NS / 1000000) # 设置一下下拉,否则第一盏灯的时序可能不正确
wiringpi.wiringPiSetup()
# 发送颜色到指定的LED wiringpi.pullUpDnControl(11, 1)
def sendColor(r, g, b): spi.open(0, 0)
for _ in range(3): spi.max_speed_hz = 6400000
sendBit(True) # 开始位 spi.mode = 0
sendByte(r)
sendByte(g) self.spi = spi
sendByte(b)
for _ in range(2): def ws2812_send_data(self):
sendBit(True) # 结束位 default_tx = self.ws2812_data
self.spi.xfer2(bytes(flatten_arrays(default_tx)))
def sendByte(value):
for bit in range(8): def ws2812_light_led(self, red, green, blue, pix_led):
sendBit((value >> (7 - bit)) & 1) default_tx = self.ws2812_data
color = green << 16 | red << 8 | blue
def refreshLEDs(): for i in range(24):
for led in range(LED_N): if color >> (24 - i - 1) & 1:
sendColor(0, 0, 0) # 先熄灭所有LED default_tx[pix_led][i] = sig_1
time.sleep(50/1000000) # 留一些时间间隔
for led in range(LED_N):
# 这里简化为只用红色演示,可根据需要修改为其他颜色
sendColor(171, 31, 120) # 浅蓝色,亮度调低
def chaseColor():
global LED_N
count = 0
while True:
count = (count + 1) % LED_N
for i in range(LED_N):
if i == count:
sendColor(171, 31, 120) # 当前LED亮浅蓝色
else: else:
sendColor(0, 0, 0) # 其他LED熄灭 default_tx[pix_led][i] = sig_0
time.sleep(0.1) # 等待一段时间再改变下一个LED
def ws2812_light_one_led(self, red, green, blue, pix_led):
try: self.ws2812_light_led(red, green, blue, pix_led)
chaseColor() self.ws2812_send_data()
except KeyboardInterrupt:
print("程序中断,清理工作...") def ws2812_light_all_led(self, red, green, blue):
finally: for i in range(self.led_num):
wiringpi.digitalWrite(GPIO_PIN, 0) # 清理工作确保GPIO输出为0 self.ws2812_light_led(red, green, blue, i)
wiringpi.pinMode(GPIO_PIN, wiringpi.INPUT)
self.ws2812_send_data()
def ws2812_rainbow(self):
colors = [[0xff, 0, 0], [0, 0xff, 0], [0, 0, 0xff]]
for i in range(self.led_num):
cur_color = colors[i % 3]
self.ws2812_light_led(cur_color[0], cur_color[1], cur_color[2], i)
self.ws2812_send_data()
def ws2812_water_lamp(self, red, green, blue, interval_time):
self.ws2812_shutoff_all()
for i in range(self.led_num):
self.ws2812_light_one_led(red, green, blue, i)
time.sleep(interval_time)
self.ws2812_shutoff_all()
def ws2812_shutoff_led(self, n):
self.ws2812_light_led(0, 0, 0, n)
self.ws2812_send_data()
def ws2812_shutoff_all(self):
for i in range(self.led_num):
self.ws2812_light_led(0, 0, 0, i)
self.ws2812_send_data()
if __name__ == '__main__':
ws2812 = WS2812(8)
while True:
ws2812.ws2812_light_all_led(0, 0, 0xff)
time.sleep(0.5)
ws2812.ws2812_light_all_led(0xff, 0, 0)
time.sleep(0.5)
ws2812.ws2812_light_all_led(0, 0xff, 0)
time.sleep(0.5)
# ws2812.ws2812_water_lamp(0xff, 0, 0, 0.2)
# time.sleep(0.5)