在AvaotaA1全志T527开发板上驱动WS2812 RGB LCD
创始人
2024-09-26 02:48:27
0

在 Avaota SBC 的开发板中,通常会有几个 WS2812 RGB LED 灯。例如 Avaota A1 的如下位置:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于 AvaotaOS,提供了硬件的 LEDC(Light Emitting Diode Controller),发光二极管控制器作为WS2812 RGB LED 灯的控制器。每个 LED 的三基色均可实现 256 级亮度显示,因此整个 LED 可完成 256ˆ3(即 16777216)种颜色的全真色彩显示。模块支持最大1024颗外控 LED级联。

WS2812 驱动介绍

LED 典型电路如图所示,其中 DI 表示控制数据输入脚,DO 表示控制数据输出脚。DI 端接收从控制器传过来的数据,每个 LED 内部的数据锁存器会存储 24bit 数据,剩余的数据经过内部整形处理电路整形放大后通过 DO 端口开始转发输出给下一个级联的 LED。因此,每经过一个LED,数据减少 24bit。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LED典型电路如上图所示,其中 DI 表示控制数据输入脚,DO 表示控制数据输出脚。DI 端接受从控制器传输过来的数据,每个 LED 内部的数据锁存器会存储 24bit (分别对应 R,G,B 三种颜色)数据,剩余的数据经过内部整形处理电路整形放大后通过 DO 端口开始转发输出给下一个级联的 LED 。因此,每经过一个 LED ,数据减少 24bit。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

WS2812 驱动配置说明

配置驱动,默认 Avaota OS 已经勾选该驱动。如果未勾选请配置

LED Drivers -> 	<*> LEDC Support for Allwinner SoCs 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置设备树,首先需要配置 PIO 节点,配置 LEDC 使用的 GPIO

&pio { 	ledc_pins_a: ledc@0{ 		pins ="PH19"; 		function ="ledc"; 		drive-strength =<10>; 	};  	ledc_pins_b: ledc@1{ 		pins ="PH19"; 		function ="gpio_in"; 	}; }; 

然后配置 LEDC 模块的数值

&ledc  { 	pinctrl-names ="default","sleep"; 	pinctrl-0=<&ledc_pins_a>; 	pinctrl-1=<&ledc_pins_b>; 	led_count =<4>; 	output_mode ="GRB"; 	reset_ns =<84>; 	t1h_ns =<800>; 	t1l_ns =<320>; 	t0h_ns =<300>; 	t0l_ns =<800>; 	wait_time0_ns =<84>; 	wait_time1_ns =<84>; 	wait_data_time_ns =<600000>; 	status ="okay"; }; 
  • pinctrl-names: 用于表示 0 和 1 的 pinctrl 哪个是默认和休眠状态。
  • pinctrl-0: 引脚配置,这里是默认使用的时候配置。
  • pinctrl-1: 同上,这里是休眠时的配置。
  • led_count: LED 灯的数目,根据硬件配置。
  • output_mode: LED 灯输出模式,根据 LED 灯的 datasheet 进行配置。
  • reset_ns: LED 灯 reset 时间控制。
  • t1h_ns: 1 码高电平时间,根据 LED 灯的 datasheet 进行配置。
  • t1l_ns: 1 码低电平时间,根据 LED 灯的 datasheet 进行配置。
  • t0h_ns: 0 码高电平时间,根据 LED 灯的 datasheet 进行配置。
  • t0l_ns: 0 码低电平时间,根据 LED 灯的 datasheet 进行配置。
  • wait_time0_ns: 两个 LED 数据之间的等待时间,根据 LED 灯的 datasheet 进行配置。
  • wait_time1_ns: 帧数据之间的等待时间,根据 LED 灯的 datasheet 进行配置。
  • wait_data_time_ns: 内部 FIFO 等待数据时间,超过时间触发异常中断。
  • status: 设备状态。

WS2812 使用说明

驱动会在 /sys/class/leds 注册每个LED对应的设备目录

/sys/class/leds/sunxi_led0r // 红色 /sys/class/leds/sunxi_led0g // 绿色 /sys/class/leds/sunxi_led0b // 蓝色 

其中 0 表示LED的编号,如果是 1 号 LED 则是

/sys/class/leds/sunxi_led1r /sys/class/leds/sunxi_led1g /sys/class/leds/sunxi_led1b 

需要调节第 0 个LED的颜色为白光且最亮,操作如下:

echo 255 > /sys/class/leds/sunxi_led0r/brightness echo 255 > /sys/class/leds/sunxi_led0g/brightness echo 255 > /sys/class/leds/sunxi_led0b/brightness 

实现七彩流水灯

C 语言实现
#include #include #include #include #include #include #include #include  // 使用RGB 分量合成颜色值 #defineMERAGECOLOR(G, R, B)(((uint32_t)G <<16)|((uint16_t)R <<8)| B) #definePIXEL_NUM4  int fd[PIXEL_NUM][3];// 存放文件描述符数组  voidinit_leds(){ char path[100];  // 初始化LED文件描述符 for(int i =0; i < PIXEL_NUM;++i){ snprintf(path,sizeof(path),"/sys/class/leds/sunxi_led%d%c/brightness", i,'r');         fd[i][0]=open(path, O_WRONLY); if(fd[i][0]==-1){ printf("Failed to open file for LED %d, color %c\n", i,'r'); } snprintf(path,sizeof(path),"/sys/class/leds/sunxi_led%d%c/brightness", i,'g');         fd[i][1]=open(path, O_WRONLY); if(fd[i][1]==-1){ printf("Failed to open file for LED %d, color %c\n", i,'g'); } snprintf(path,sizeof(path),"/sys/class/leds/sunxi_led%d%c/brightness", i,'b');         fd[i][2]=open(path, O_WRONLY); if(fd[i][2]==-1){ printf("Failed to open file for LED %d, color %c\n", i,'b'); } } }  voidsunxi_set_led_brightness(int led_id,uint8_t r,uint8_t g,uint8_t b){ if(led_id <0|| led_id >= PIXEL_NUM){ printf("Invalid LED ID\n"); return; }  dprintf(fd[led_id][0],"%d", r); dprintf(fd[led_id][1],"%d", g); dprintf(fd[led_id][2],"%d", b); }  voidclose_leds(){ // 关闭LED文件描述符 for(int i =0; i < PIXEL_NUM;++i){ for(int j =0; j <3;++j){ if(fd[i][j]!=-1){ close(fd[i][j]); } } } }  // 生成颜色 uint32_tWS281x_Wheel(uint8_t wheelPos){     wheelPos =255- wheelPos; if(wheelPos <85){ returnMERAGECOLOR(255- wheelPos *3,0, wheelPos *3); } if(wheelPos <170){         wheelPos -=85; returnMERAGECOLOR(0, wheelPos *3,255- wheelPos *3); }     wheelPos -=170; returnMERAGECOLOR(wheelPos *3,255- wheelPos *3,0); }  // 亮度设置 voidWS281xLSet(uint32_t id,uint32_t rgb,float k){ uint8_t r, g, b; float h, s, v; uint8_t cmax, cmin, cdes;      r =(uint8_t)(rgb >>16);     g =(uint8_t)(rgb >>8);     b =(uint8_t)(rgb);      cmax = r > g ? r : g; if(b > cmax)         cmax = b;     cmin = r < g ? r : g; if(b < cmin)         cmin = b;     cdes = cmax - cmin;      v = cmax /255.0f;     s = cmax ==0?0: cdes /(float) cmax;     h =0;  if(cmax == r && g >= b)         h =((g - b)*60.0f/ cdes)+0; elseif(cmax == r && g < b)         h =((g - b)*60.0f/ cdes)+360; elseif(cmax == g)         h =((b - r)*60.0f/ cdes)+120; else         h =((r - g)*60.0f/ cdes)+240;      v *= k;  float f, p, q, t; float rf, gf, bf; int i =((int)(h /60)%6);     f =(h /60)- i;     p = v *(1- s);     q = v *(1- f * s);     t = v *(1-(1- f)* s); switch(i){ case0:             rf = v;             gf = t;             bf = p; break; case1:             rf = q;             gf = v;             bf = p; break; case2:             rf = p;             gf = v;             bf = t; break; case3:             rf = p;             gf = q;             bf = v; break; case4:             rf = t;             gf = p;             bf = v; break; case5:             rf = v;             gf = p;             bf = q; break; default: break; }      r =(uint8_t)(rf *255.0);     g =(uint8_t)(gf *255.0);     b =(uint8_t)(bf *255.0);  sunxi_set_led_brightness(id, r, g, b); }  // 测试 LEDC intmain(){ int i =0, j =0, err; int mode =0; uint8_t R =0, G =0, B =0;  init_leds();  while(1){ for(j =0; j <256; j++){ for(i =0; i < PIXEL_NUM; i++){ WS281xLSet(i,WS281x_Wheel(((i *256/ PIXEL_NUM)+ j)&255),0.1); } usleep(1000); } usleep(10000); }  close_leds();  return1; } 
Python 实现
import os import time import math  PIXEL_NUM =4 fd =[[None,None,None]for _ inrange(PIXEL_NUM)]# 文件描述符数组  definit_leds(): global fd     path =""  # 初始化LED文件描述符 for i inrange(PIXEL_NUM):         path =f"/sys/class/leds/sunxi_led{i}{'r'}/brightness"         fd[i][0]= os.open(path, os.O_WRONLY) if fd[i][0]==-1: print(f"Failed to open file for LED {i}, color {'r'}")          path =f"/sys/class/leds/sunxi_led{i}{'g'}/brightness"         fd[i][1]= os.open(path, os.O_WRONLY) if fd[i][1]==-1: print(f"Failed to open file for LED {i}, color {'g'}")          path =f"/sys/class/leds/sunxi_led{i}{'b'}/brightness"         fd[i][2]= os.open(path, os.O_WRONLY) if fd[i][2]==-1: print(f"Failed to open file for LED {i}, color {'b'}")  defsunxi_set_led_brightness(led_id, r, g, b): if led_id <0or led_id >= PIXEL_NUM: print("Invalid LED ID") return      os.write(fd[led_id][0],str(r).encode())     os.write(fd[led_id][1],str(g).encode())     os.write(fd[led_id][2],str(b).encode())  defclose_leds(): # 关闭LED文件描述符 global fd for i inrange(PIXEL_NUM): for j inrange(3): if fd[i][j]isnotNone:                 os.close(fd[i][j])  defws281x_wheel(wheel_pos):     wheel_pos =255- wheel_pos if wheel_pos <85: return merge_color(255- wheel_pos *3,0, wheel_pos *3) if wheel_pos <170:         wheel_pos -=85 return merge_color(0, wheel_pos *3,255- wheel_pos *3)     wheel_pos -=170 return merge_color(wheel_pos *3,255- wheel_pos *3,0)  defmerge_color(r, g, b): return(r <<16)|(g <<8)| b  defws281x_lset(id, rgb, k):     r =(rgb >>16)&0xFF     g =(rgb >>8)&0xFF     b = rgb &0xFF      cmax =max(r, g, b)     cmin =min(r, g, b)     cdes = cmax - cmin      v = cmax /255.0     s = cmax /255.0if cmax ==0else cdes / cmax  if cmax == r and g >= b:         h =(g - b)*60.0/ cdes +0 elif cmax == r and g < b:         h =(g - b)*60.0/ cdes +360 elif cmax == g:         h =(b - r)*60.0/ cdes +120 else:         h =(r - g)*60.0/ cdes +240      v *= k      i = math.floor(h /60)%6     f = h /60- i     p = v *(1- s)     q = v *(1- f * s)     t = v *(1-(1- f)* s)  if i ==0:         rf, gf, bf = v, t, p elif i ==1:         rf, gf, bf = q, v, p elif i ==2:         rf, gf, bf = p, v, t elif i ==3:         rf, gf, bf = p, q, v elif i ==4:         rf, gf, bf = t, p, v else:         rf, gf, bf = v, p, q      r =int(rf *255.0)     g =int(gf *255.0)     b =int(bf *255.0)      sunxi_set_led_brightness(id, r, g, b)  defmain():     init_leds() try: whileTrue: for j inrange(256): for i inrange(PIXEL_NUM):                     ws281x_lset(i, ws281x_wheel(int((float(i)*256.0/float(PIXEL_NUM)+ j))&255),0.1)                 time.sleep(0.01)# 控制LED变化速度             time.sleep(0.1) finally:         close_leds()  if __name__ =="__main__":     main() 

相关内容

热门资讯

无独有偶!上饶打炸祈福(辅助挂... 无独有偶!上饶打炸祈福(辅助挂)果然有挂(曝光开挂辅助下载)-哔哩哔哩上饶打炸祈福是一种具有地方特色...
有玩家发现!微乐智能辅助app... 有玩家发现!微乐智能辅助app(辅助挂)一贯有挂(细节开挂辅助插件)-哔哩哔哩1、在微乐智能辅助ap...
日前!广西老友辅助app(辅助... 日前!广西老友辅助app(辅助挂)一贯确实有挂(细节开挂辅助工具)-哔哩哔哩1、上手简单,内置详细流...
今天上午!微乐富足和靠谱吗(辅... 今天上午!微乐富足和靠谱吗(辅助挂)果然真的有挂(带你开挂辅助安装)-哔哩哔哩1、完成微乐富足和靠谱...
经调查!拱趴大菠萝辅助工具(辅... 经调查!拱趴大菠萝辅助工具(辅助挂)果然是有挂(带你开挂辅助插件)-哔哩哔哩暗藏猫腻,小编详细说明拱...
随着!先锋脚本辅助(辅助挂)果... 随着!先锋脚本辅助(辅助挂)果然真的是有挂(传授开挂辅助软件)-哔哩哔哩先锋脚本辅助软件透明挂微扑克...
此事备受玩家关注!西元文山攻略... 此事备受玩家关注!西元文山攻略(辅助挂)一直是有挂(实测开挂辅助插件)-哔哩哔哩亲,关键说明,西元文...
据玩家消息!科乐游戏辅助脚本视... 您好,科乐游戏辅助脚本视频这款游戏可以开挂的,确实是有挂的,需要了解加去威信【485275054】很...
出现新变化!小程序广东雀神智能... 出现新变化!小程序广东雀神智能挂件(辅助挂)一贯是有挂(发现开挂辅助脚本)-哔哩哔哩1、首先打开小程...
长期以来!微乐a3纸牌有脚本(... 长期以来!微乐a3纸牌有脚本(辅助挂)果然有挂(正版开挂辅助下载)-哔哩哔哩1、微乐a3纸牌有脚本系...