import wiringpi import argparse import time parser = argparse.ArgumentParser(description='') parser.add_argument("--channel", type=int, default=1, help='specify the spi channel') parser.add_argument("--port", type=int, default=0, help='specify the spi port') parser.add_argument("--speed", type=int, default=6400000, help='specify the spi speed') parser.add_argument("--mode", type=int, default=0, help='specify the spi mode') args = parser.parse_args() # 0码 t0H 220ns~380ns #(python 中GPIO口无法翻转这么快,python 可能执行一行代码需要800ns) # ws2812 波特率如果设置为800kHZ, 1/0.8M=1.25us (0码或者1码所需要的时间) # 方案1. # 使用SPI产生ws2812时序,产生1码和0码,则可以使用传输一个byte 来代表一个0码或者1码,如下: # 1111 1000 0xF8 #1码 高电平时间长,低电平时间短 # 1100 0000 0xC0 #0码 高电平时间短,低电平时间长 # 则得出SPI 波特率应该设置为800K*8 # 方案2. 见led_bak.py # 使用SPI产生ws2812时序,产生1码和0码,则可以使用传输一个半个byte 来代表一个0码或者1码,如下: # 1100 0x0c #1码 高电平时间长,低电平时间短 # 1000 0x08 #0码 高电平时间短,低电平时间长 # 则得出SPI 波特率应该设置为800K*4 sig_1 = 0xf8 sig_0 = 0xc0 def flatten_arrays(arrays): return [element for sublist in arrays for element in sublist] class WS2812: def __init__(self, led_num=10): self.led_num = led_num self.ws2812_data = [[sig_0 for _ in range(24)] for _ in range(led_num)] wiringpi.wiringPiSPISetupMode(args.channel, args.port, args.speed, args.mode) # 设置一下下拉,否则第一盏灯的时序可能不正确 wiringpi.wiringPiSetup() wiringpi.pullUpDnControl(11, 1) print("ws2812_data len", len(self.ws2812_data)) print("spi mode: 0x%x" % args.mode) print("max speed: %d Hz (%d KHz)\n" % (args.speed, args.speed / 1000), end='') def ws2812_send_data(self): default_tx = self.ws2812_data wiringpi.wiringPiSPIDataRW(args.channel, 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: default_tx[pix_led][i] = sig_0 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() def ws2812_gradient_run(self, start_red, start_green, start_blue, end_red, end_green, end_blue, steps, delay): for step in range(steps): # 计算当前步的颜色 curr_red = start_red + (end_red - start_red) * step // steps curr_green = start_green + (end_green - start_green) * step // steps curr_blue = start_blue + (end_blue - start_blue) * step // steps # 清除当前颜色并应用新的渐变色 self.ws2812_shutoff_all() for i in range(self.led_num): self.ws2812_light_led(curr_red, curr_green, curr_blue, (i + step) % self.led_num) # 循环显示渐变色 self.ws2812_send_data() time.sleep(delay) if __name__ == '__main__': ws2812 = WS2812(8) while True: # 示例:从蓝色渐变到红色,再从红色渐变回蓝色,每种颜色渐变10步,每步间隔0.1秒 ws2812.ws2812_gradient_run(0, 0, 0xff, 0xff, 0, 0, 10, 0.02) time.sleep(1) # 等待1秒后开始反向渐变 ws2812.ws2812_gradient_run(0xff, 0, 0, 0, 0, 0xff, 10, 0.02) time.sleep(1) # 再次等待1秒,形成完整的循环 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_shutoff_all() time.sleep(0.5) ws2812.ws2812_water_lamp(0xff, 0, 0, 0.2) time.sleep(0.5)