原创文章,未经许可,禁止转载!

4 信仰灯

为女神打造礼物的第一期

视频教程:https://www.bilibili.com/video/BV14t4y1q7Cc/

既然是为女神打造礼物,那高逼格的信仰灯肯定是必不可少的。下面来看下效果。

发光效果

全彩Led

使用的全彩 led 的模块是 ws2812,这种 led 是可以串联起来的,每一颗 led 是一个 pixel(像素),可以单独发光,我上面的 gif 里面有1个1像素的和2个8像素的,并且他们之间还可以串联,下面简单介绍下这种 led 的工作原理。

每像素上其实是有3个很小的发光led的,他们分别是发红光,绿光和蓝光的led,也就是三原色,这三种颜色的光根据亮度叠加在一起就组合成各种颜色,就像我们在水彩画里面用各种颜色的颜料混在一样。看下图4-1,ws2812中的3个小led通过控制3个颜色的亮度发出了紫色的光。

图4-1 三原色

我们用的液晶显示器还有电视机也是同样的原理,大家也可以用手机上的微距功能,对着自己的显示器或者电视机拍照看一下。

图4-2 液晶显示器成像

连接方式

先看下图4-3

图4-3 引脚

可以看到不管是几个像素的模块,他们都有4种引脚,VCC, GND, IN(DI), OUT(DO)。VCC引脚用来供电,GND引脚用来接地,IN引脚用来接收芯片的数据,OUT引脚用来传递剩余的数据。这里有些芯片有2个VCC,GND,他们的功能是一样的,你可以认为2个VCC之间或者2个GND之间使用导线连通的,这么设计的目的是为了串联使用。

对于多像素的的模块来说,多个led是模块已经串联好的,比如上图4-3中,模块已经串联好了8个led,可以认为从左到右分别是led0-led7,如果在串联一个相同的模块,那后面的模块就是 led8-led15。

下面讲一下具体的连接方式,这里用1个像素的模块来表示,看下图4-4

图4-4 串联方式

首先,各个模块的VCC的供电部分连接在了一起,这时就可以体会到2个VCC的好处了,串联起来很方便。同样GND也是一样的。这样从8266的3.3v端将电通过第一个像素传递给后面的其他像素了。

在下来就是数据线,每个模块之间前一个模块的out连接后一个模块的in,通过8266的GPIO口会把3个模块的数据传给PIXEL0的in端,然后PIXEL0会拿走第一个数据,再将剩余的数据传给第二个模块,然后第二个模块拿走自己的数据后把剩余的数据传递给第三个模块,这样8266只需要一个引脚就可以将所有的数据传递下去了。

那么多像素模块其实也是这样连接的,只是内部封装隐藏了,你看不到,但是原理是一样的。

编码-点亮led

打开 Ardiuno IDE,如下图4-5,点击工具(tools),选择库管理(Library Manager),查找 Adafruit NeoPixel 库,点击安装(install)。安装完成后关闭库管理窗口开始编码。

图4-5 安装neopixel库

首先,需要引入 Adafruit_NeoPixel.h 头文件,这里面包含了操作ws2812模块的操作函数,毕竟控制这样的模块也是非常复杂的,我们没必要去造轮子,用别人做好的库就行了。

然后需要定义一个led模块 Adafruit_NeoPixel led = Adafruit_NeoPixel(1, D1, NEO_GRB + NEO_KHZ800),参数1表示模块有几个像素,我们这里先定义1个像素。第二个参数是用哪个gpio来控制模块,这里我用的是D1,也就是 GPIO5 ,这里的D1也可以直接写数字5。第三个参数是模式,基本上所有的ws2812都是这个规格,如果买到其他规格的模块,请参考手册。

led的颜色控制是通过4个数值来进行控制的,分别是 red(红色),green(绿色),blue(蓝色),brightness(亮度)。这四个值的范围都是0-255,0表示最暗,255表示最亮,当red是255,green和blue为0的时候,灯就会亮起红色。而亮度值其实是一个系数,对最终的颜色做整体调整。其实每个颜色到255就到头了,这时亮度也是255就表示led最亮,其实,所有的数值都是要除以255的,最终只有rgb的3个颜色值,而且最大值为1.0,颜色的计算公式如下:

rgb = (red / 255, green / 255,blue / 255)* brightness / 255

那我们怎么知道想要的颜色的数值呢?随便找一个画图软件,看下图4-6,比如我这里用的是windows自带的画图软件,打开调色板,选择led想要发光的颜色,对应旁边的rgb框里就有相应的数值,抄出来就可以了。

图4-6 颜色数值获取

接下来,对我们定义的led对象调用 led.setPixelColor(0, led.Color(255, 0, 0)) 函数设置颜色,第1个参数0表示设置第0个像素的颜色。第2个参数 通过调用 led.Color(255, 0, 0) 得到一个颜色值。通过led.Color函数设置会比较直观,它的第1个参数表示红色的数值,第二个参数表示绿色的值,第三个参数表示蓝色的值。然后设置亮度,最后调用led.show(),把修改作用到模块上,这样就得到了一个亮红灯的led。具体请看下方代码:

// 首先,引入库文件
#include <Adafruit_NeoPixel.h>

// 定义一个led模块
// 参数1:这个模块有几个led 像素
// 参数2:使用哪一个gpio口输出
// 参数3:模式,一般ws2812都是 NEO_GRB + NEO_KHZ800,其他模式的模块可以参考手册
Adafruit_NeoPixel led = Adafruit_NeoPixel(1, D1, NEO_GRB + NEO_KHZ800);

// 初始化
void setup() {
    led.begin();  // 打开led
    led.setBrightness(50); // 设置led的亮度为50,最大为255
}

// 循环函数
void loop() {
    led.setPixelColor(0, led.Color(255, 0, 0)); // 设置红色为255
    led.show();  // 将修改作用到led模块上
}

下面我们来看一个稍微复杂的例子,做一个手机上呼吸灯,

// 首先,引入库文件
#include <Adafruit_NeoPixel.h>

// 定义一个led模块
Adafruit_NeoPixel led = Adafruit_NeoPixel(1, D1, NEO_GRB + NEO_KHZ800);

// 定义一个全局变量,这个变量用来记录程序的第几次循环
uint32_t frame = 0;

// 定义一个角度转弧度的函数,这里的三角函数用的是弧度制
float Deg2Rad(uint32_t deg) {
  return deg / 180.0f * 3.1415926;
}

// 初始化
void setup() {
    led.begin();  // 打开led
    led.setBrightness(50); // 设置led的亮度为50,最大为255
    frame = 0;    // 初始化循环计数为0
}

// 循环函数
void loop() {
  uint8_t c = fabs(sin(Deg2Rad(frame))) * 255;  // 通过frame计数来计算周期函数sin,并且取绝对值
  led.setPixelColor(0, led.Color(c, 0, 0));     // 将led的第0个像素红色设置为前面计算的c值
  led.show(); // 将修改作用到led模块上
  delay(10);  // 延迟10毫秒

  if (frame % 180 == 0) {   // 如果循环次数是180的倍数,则延迟1秒
    delay(1000);
  }

  frame++;    // 将循环计数+1
}

下面来看一下效果:

可以看到红色的呼吸灯,并且虽然我这里用了8个像素的模块,但是由于只设置了第一个像素,所以只有第一个像素有颜色。下面我们来做一个更加复杂的例子,会用到全部的8个像素,流水灯。

#include <Adafruit_NeoPixel.h>

// 这里还是用D1来控制,设置了8个像素
Adafruit_NeoPixel led = Adafruit_NeoPixel(8, D1, NEO_GRB + NEO_KHZ800);

// 定义一个全局变量,这个变量用来记录程序的第几次循环
uint32_t frame = 0;

// 初始化
void setup() {
    led.begin();  // 打开led
    led.setBrightness(50); // 设置led的亮度为50,最大为255
    frame = 0;
}

// 循环函数
void loop() {
  uint8_t red = rand() % 256;    // 红色随机值
  uint8_t green  = rand() % 256; // 绿色随机值
  uint8_t blue = rand() % 256;   // 蓝色随机值

  for (uint16_t i = 0; i < 8; i++) {  // 循环让所有的led都熄灭
    led.setPixelColor(i, led.Color(0, 0, 0));  
  }

  // 通过frame滚动,让frame对应的led显示前面得到的红绿蓝的值,让frame对应的前一个和后一个led也是用同样的颜色十分之一
  led.setPixelColor(frame % 8, led.Color(red / 10, green / 10, blue / 10));     
  led.setPixelColor((frame + 1) % 8, led.Color(red, green, blue));
  led.setPixelColor((frame + 2) % 8, led.Color(red / 10, green / 10, blue / 10));
  led.show(); // 将修改作用到led模块上

  frame++;
  delay(100);  
}

下面来看下效果

图 4-8 流水灯

关于ws2812的玩法还有很多,大家可以自行研究。也可以在灯上找一个柔光罩,这样和信仰灯就很接近了。最后如果在登上照一个放了水的杯子会非常好看,我个人特别喜欢把玻璃瓶的花露水照在上面,然后关掉房间的灯,感觉非常好看,大家也可以试试。

发表评论