在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() 

相关内容

热门资讯

玩家必看教程!!微信小程序免费... 玩家必看教程!!微信小程序免费黑科技(外挂),微信小程序怎么开挂切实有挂工具1、在微信小程序免费黑科...
一分钟教你!微信小程序黑科技(... 一分钟教你!微信小程序黑科技(外挂),微乐小程序黑科技下载都是有挂详细1)微信小程序黑科技有没有挂:...
每日必看!微乐小程序免费黑科技... 每日必看!微乐小程序免费黑科技(外挂),广西微乐小程序控制器确实今日头条1、玩家可以在微乐小程序免费...
终于知道!!微乐小程序黑科技(... 终于知道!!微乐小程序黑科技(外挂),贵州微乐自建房辅助软件下载其实有挂辅助1、实时微乐小程序黑科技...
解谜透视!红龙poker辅助器... 解谜透视!红龙poker辅助器免费观看,epoker透视底牌(透视)都是存在有辅助攻略(哔哩哔哩)1...
最终!WePOker有没有透视... 最终!WePOker有没有透视方法,传送屋辅助器(免费),本来真的是有辅助攻略(哔哩哔哩)1、玩家可...
透视课程!wepoker可以免... 透视课程!wepoker可以免费玩吗(透视)切实有辅助安装(哔哩哔哩)透视课程!wepoker可以免...
分辨真假!微信小程序黑科技(外... 分辨真假!微信小程序黑科技(外挂),微乐小程序怎么挂脚本都是有挂辅助1、首先打开微信小程序黑科技辅助...
科普透视!newpoker脚本... 科普透视!newpoker脚本,sohoo竞技联盟辅助器(透视)果然真的是有辅助攻略(哔哩哔哩)1、...
透视方针!如何判断wpk辅助软... 透视方针!如何判断wpk辅助软件的真假(透视)果然存在有辅助下载(哔哩哔哩)1、很好的工具软件,可以...