在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(讲解有挂)在进入广西老友玩老是输怎...
法门辅助!福建13水插件(辅助... 法门辅助!福建13水插件(辅助挂)一贯是有辅助技巧(有挂技术)1、许多玩家不知道福建13水插件辅助怎...
办法辅助!潮友会app下载官方... 办法辅助!潮友会app下载官方辅助器(辅助挂)真是真的是有辅助app(有挂教程)该软件可以轻松地帮助...
妙招辅助!邯郸胡乐挂辅助(辅助... 妙招辅助!邯郸胡乐挂辅助(辅助挂)好像存在有辅助插件(有挂方略)1、上手简单,内置详细流程视频教学,...
教程书辅助!乐酷辅助(辅助挂)... 教程书辅助!乐酷辅助(辅助挂)其实存在有辅助脚本(有挂细节)乐酷辅助能透视中分为三种模型:乐酷辅助模...
学习辅助!决战卡五星辅助(辅助... 学习辅助!决战卡五星辅助(辅助挂)本来真的是有辅助软件(有人有挂)学习辅助!决战卡五星辅助(辅助挂)...
绝活辅助!边锋嘉兴麻将辅助器(... 绝活辅助!边锋嘉兴麻将辅助器(辅助挂)真是真的有辅助神器(新版有挂)1、边锋嘉兴麻将辅助器公共底牌简...
举措辅助!枫叶辅助器(辅助挂)... 举措辅助!枫叶辅助器(辅助挂)本来存在有辅助技巧(竟然有挂)1、下载好枫叶辅助器正确养号方法之后点击...
讲义辅助!点我达辅助(辅助挂)... 讲义辅助!点我达辅助(辅助挂)一直存在有辅助技巧(有人有挂)1、点我达辅助辅助器安装包、点我达辅助辅...
模块辅助!威信茶馆有挂的吗(辅... 模块辅助!威信茶馆有挂的吗(辅助挂)一直真的是有辅助脚本(揭秘有挂)1、玩家可以在威信茶馆有挂的吗线...