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