基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯

炫彩智能氛围灯

文章目录

  • 炫彩智能氛围灯
    • 前言(制作背景)
    • 制作流程及技术总结(干货)
      • 第一步:准备材料
      • 第二步:硬件连线
      • 第三步:烧录代码
      • 第四步:3D打印
      • 第五步:组装
    • 效果展示(手机拍摄存在色差)
    • 遇见的问题

前言(制作背景)

若干月以前,我看到了一个关于制作炫彩智能灯的视频,这带给我浓厚的兴趣,激发了我强烈的制作欲望,遂逢某大学(鄙人本科在读)新某杯举办之际,给了我一个机会去制作这个小东西。于是乎,在找了两名志同道合的同学后,开始了打怪升级的道路。本作品可以通过电位器调节模式及亮度,也可通过Bliker app实现WIFI控制。

制作流程及技术总结(干货)

第一步:准备材料

[备注]:其实选择一块兼容WIFI模块的板子是更好的选择

1、Arduino UNO板一块
2、ESP8266模块一个(需配烧录器)
3、WB2812B灯带(这里有1米30灯珠与60灯珠两种选择,我选择了前者,后者有点密)
4、两个1024(规格可选)的电位器(配两个旋钮)
5、导线,杜邦线(各种,谨防需要)若干
6、亚克力管(外径165mm内径159mm高度273mm,封顶)
7、3D打印底座和隔层(后附STL文件,具体尺寸可自行设计,包括亚克力管的大小)
8、一块小喷锡板(用于外焊一些电容电阻)
9、470微法电容一个,220欧姆电阻一个
10、5V10A电源适配器一个,电源转接头一个
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第1张图片

第二步:硬件连线

1、灯带连接:将灯带剪为需要的长度(沿敷铜处虚线剪断),我选择了八个灯珠一组,因为我设计的高度为八层。然后借助跳线将灯带间连接起来,GND接GND,VCC接VCC,IN接OUT,并联切勿接错。
2、与UNO板的连接,见下图。其中电位器接Ax串口,可检测电位器当前的状态,用于控制灯的亮度和模式。电阻可不要,灯带接Dx串口,用于向灯带发出指令,控制灯带。电源适配器图中功率有误,实际需要电流应该根据您所需灯珠数量计算,以一个灯珠0.3w计算128个的灯珠需要38.4w,遂我选择了5V10A的电源适配器(第一次还买错了,买成了5V6A的,这里需要注意的是,电流输出大小有外电路决定,即在工作中电流输出最大可到10A但不一定为10A,可小于)。

基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第2张图片
3、ESP8266与UNO板通信连接
这里面的硬串口(RX,TX)通信应该被USB占用,同时也不推荐硬串口通信,建议选择软串口进行通信。如果需要向ESP烧录程序,此时需将GPIO0接地。
烧录模式:
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第3张图片
正常工作:
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第4张图片

第三步:烧录代码

推荐使用Arduino IDE进行烧录,简单方便。
先上代码,再讲注意重点。(代码中没有写注释,见谅,具体内容下文都有讲解)

UNO部分:

#include "FastLED.h"
#include

SoftwareSerial mySerial(10,11);//RX TX   mySerial(8,1);//RX TX

#define NUM_LEDS 128
#define DATA_PIN 6
#define LED_TYPE WS2812
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

uint8_t max_bright = 128;
uint8_t val_bright = 0;
uint8_t startIndex = 0;
uint8_t startIndex1 = 0;
uint8_t bright = 0;
uint8_t book = 0;
uint8_t tips = 1;
int val1 = 0;
int val2 = 0;
String Serial_String="";
String Strings = "";
String string_r = "";
String string_g = "";
String string_b = "";
String string_bright = "";
String string_stop = "";
String string_stop2 = "";
long previousMillis = 0;
long currentMillis = 0;

uint8_t XDU_Index[26] = {
     10,11,12,13,18,29,34,35,36,37,74,75,76,77,66,60,59,69,101,107,115,125,122,116,108,98};


void setup(){
     
  Serial.begin(115200);
  mySerial.begin(9600);
  pinMode(LED_BUILTIN,OUTPUT);
  delay(1000);
  LEDS.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness(max_bright);
}

void WarmLight(){
     
  fill_solid(leds, 128, CRGB(235,68,17));
}

void White(){
     
  fill_solid(leds, 128, CRGB::White);
}

void Black(){
     
  fill_solid(leds, 128, CRGB::Black);
}

void Ocean_palette()
{
     
  fill_palette(leds, NUM_LEDS, startIndex, 8, OceanColors_p, 255, LINEARBLEND);
}

void Forest_palette()
{
     
  fill_palette(leds, NUM_LEDS, startIndex, 8, ForestColors_p, 255, LINEARBLEND);
}

uint8_t mov[25] = {
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void XDU()
{
     
  uint8_t i; 
  uint8_t j;
  uint8_t index;
  for(j=0;j<128;j++){
     
    currentMillis = millis();
    if(currentMillis - previousMillis>=700){
     
      fill_solid(leds, 128, CRGB::Blue);
      for(i=0;i<26;i++){
     
        index = XDU_Index[i];
        leds[index] = CRGB::Red;
        FastLED.show();
        mov[i] = 2*(8-((index+1)%8))+1; 
      }
      for(i=0;i<26;i++) XDU_Index[i] = (XDU_Index[i]+mov[i])%128;
      previousMillis = millis();
    }
    if(analogRead(A2)<=680||(analogRead(A2)>=830&&analogRead(A2)<1000)) break;
  }
}

void PWM(){
     
  fill_palette(leds, NUM_LEDS, startIndex1++, 8, RainbowColors_p, 255, LINEARBLEND);//(leds, 数量,起始序号,灯珠间色差,色板名称,亮度,变化方式)
  if(book==0){
     
    FastLED.setBrightness(bright++);
  }else{
     
    FastLED.setBrightness(bright--);
  }
  if(bright==127){
     
    book = 1;
  }else if(bright==0){
     
    book = 0;
  }
  delay(20);
}

void read_string(){
     
  while(mySerial.available()>0){
     
    Serial_String+=(char)(mySerial.read());
  }
}

void R(){
     
  val_bright = (int)val1/1023.0*128; 
  FastLED.setBrightness(val_bright);
  
  if(val2<150) White();
  else if(170<val2&&val2<320)  WarmLight();
  else if(340<val2&&val2<490)  Forest_palette();
  else if(510<val2&&val2<660)  Ocean_palette(); 
  else if(680<val2&&val2<830)  XDU();
  else if(850<val2&&val2<980)  PWM();
}

void Wifi()
{
     
  while(mySerial.available()>0){
     
    Serial_String="";
    read_string();
  }
  if(Serial_String=="P"||Serial_String=="Q"||Serial_String=="R"||Serial_String=="S"||Serial_String=="T"||Serial_String=="B"||Serial_String=="U")
    string_stop = Serial_String;
  if(Serial_String=="1"||Serial_String=="2"||Serial_String=="3"||Serial_String=="4"||Serial_String=="5"||Serial_String=="6"||Serial_String=="7"||Serial_String=="8"||Serial_String=="9")
    string_stop2 = Serial_String;
  
  if(string_stop!=""||string_stop2!="") Serial.println(string_stop+'@'+string_stop2);
  
  if(string_stop=="P")       White();  
  else if(string_stop=="Q")  WarmLight();
  else if(string_stop=="R")  Forest_palette();
  else if(string_stop=="S")  Ocean_palette(); 
  else if(string_stop=="T")  XDU();
  else if(string_stop=="B")  Black();
  else if(string_stop=="U")  PWM();
  if(string_stop!="U"){
     
    val_bright = (int)string_stop2.toInt()/9.0*128; 
    FastLED.setBrightness(val_bright);
  }
}

void loop(){
     
  val2 = analogRead(A2);
  val1 = analogRead(A0);
  if(val2 >= 1000) Wifi();
  else R();
  startIndex++;
  FastLED.show();
}

我们从头看起。
1、FastLED.h库是一个控制LED很方便的库。这里列写几条实用的语句,详细推荐去看官方文档,或者上b站看视频。
这是我学习过程中的记录:

#include"FastLED.h"

#define NUM_LEDS 128      //LED数量
#define DATA_PIN 9        //引脚
#define LED_TYPE WS2812B  //LED型号
#define COLOR_ORDER GRB   //LED颜色顺序

uint8_t max_bright = 128; //LED亮度

CRGB leds[NUM_LEDS];      //建立leds光带


//初始化
void setup()
{
     
  Serial.begin(9600);     //启动串行通讯
  delay(1000);            //稳定性等待

  LEDS.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds,NUM_LEDS);  //初始化操作

  FastLED.setBrightness(max_bright);    //设置光带亮度
}


void loop()
{
     
  for(int i=0;i<=NUM_LEDS;i++)
  {
     
    leds[i] = CRGB::Red;   //设置光带第一个灯珠颜色为红色
    FastLED.show();        //更新LED颜色
    delay(500);            //等待500ms
  
    leds[i] = CRGB::Black; //熄灭第一个灯珠
    FastLED.show();        //更新LED颜色
    delay(500);            //等待500ms
  }
}

/*
//常用语句
fill_solid(leds+5,30,CRGB::RED);  //全部点亮/熄灭

CRGB myRGBcolor(50,0,50);         //myRGBcolor(r,g,b)
fill_solid(leds+5,30,CRGB::RED);  //点亮自定义色彩
myRGBcolor.r = 50;                //改变颜色参数

CHSV myHSVcolor(80,255,200);      //HSV定义颜色参数(色调,饱和度,明亮度)

fill_rainbow(leds,30,0,10);    //产生彩虹色,第三个参数是H,第四个参数是色调差(可选)

fill_gradient_RGB(leds,0,CRGB::RED,29,CRGB(0,0,255));   //(光带名,起始灯珠号,起始RGB,结束灯珠号,结束RGB)
fill_gradient(leds,0,CHSV(50,255,255),29,CSHV(150,255,255),SHORTEST_HUES/LONGEST_HUS);   //(光带名,起始灯珠号,起始HSV,结束灯珠号,结束HSV)

addGlitter(10);

fill_palettle(leds,30,0,8,OceanColors)p,255,LINEARBLEND/NOBLEND); //(LED,灯珠数量,其实颜色序号,灯珠色差,色板名称,亮度,颜色过渡)
//RainbowColors_p
//OceanColors_p
//CloudColors_p
//LavaColors_p
//ForestColors_p
//RainbowStripeColors_p
//PartyColors_p
//HeatColors

CRGBPalette16 myColorPalette = CRGBPalette16(
                               CRGB::Green, CRGB::Green,CRGB::Green, CRGB::Green,
                               CRGB::Green, CRGB::Green,CRGB::Green, CRGB::Green,
                               CRGB::Green, CRGB::Green,CRGB::Green, CRGB::Green,
                               CRGB::Green, CRGB::Green,CRGB::Green, CRGB::Green);

CHSVPalette16 myColorPalette = CHSVPalette16(
                               HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                               HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                               HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                               HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200));

const TProgmePalettel16 myColorPalette PROGMEM ={
                                                 HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                                                 HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                                                 HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                                                 HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),HSV(0,255,200),
                                                 }    
*/

2、设置软串口,启动并设置波特率(波特率会影响通信效率我采用与ESP9600通信)

SoftwareSerial mySerial(10,11);//RX TX
Serial.begin(115200);
mySerial.begin(9600);

3、读取串口状态,这里是电位器状态

val2 = analogRead(A2);
val1 = analogRead(A0);

4、读取ESP的通信

void read_string(){
     
  while(mySerial.available()>0){
     //判断接受信息长度
    Serial_String+=(char)(mySerial.read());//读取信息并存入变量
  }
}
if(string_stop!=""||string_stop2!="") Serial.println(string_stop+'@'+string_stop2);//这一句是向硬串口写入,用于后台监视

5、将string转为int函数

string_stop2.toInt()

ESP端代码

#define BLINKER_WIFI

#include
#include

SoftwareSerial mySerial(8,1);//RX TX

String mySerial_String = "";
String RGB_String = "";
uint8_t i = 0;
 
char auth[] = "Blinker app分配的密钥";
char ssid[] = "WIFI名称";
char pswd[] = "WIFI密码";

#define BUTTON_1 "Button1"
#define BUTTON_2 "Button2"
#define BUTTON_3 "Button3"
#define BUTTON_4 "Button4"
#define BUTTON_5 "Button5"
#define BUTTON_6 "Button6"
#define Slider_1 "Slider1"

BlinkerButton Button1("White");   //P
BlinkerButton Button2("Warm");    //Q
BlinkerButton Button3("Forest");  //R
BlinkerButton Button4("Ocean");   //S
BlinkerButton Button5("XDU");     //T
BlinkerButton Button6("PWM");     //U
BlinkerSlider Slider1("Bright");

void slider1_callback(int32_t value){
     
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  BLINKER_LOG("get slider value: ", value);
  mySerial_String = String(value);
}

void button1_callback(const String & state)               //White
{
     
  digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on"){
     
      BLINKER_LOG("Toggle on!");
      Button1.print("on");
      mySerial_String = "P";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button1.print("off");
      mySerial_String = "B";
  }
}

void button2_callback(const String & state)            //Warm
{
     
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
     
      BLINKER_LOG("Toggle on!");
      Button2.print("on");
      mySerial_String = "Q";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button2.print("off");
      mySerial_String = "B";
  }
}
void button3_callback(const String & state)  //Forest
{
     
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
     
      BLINKER_LOG("Toggle on!");
      Button3.print("on");
      mySerial_String = "R";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button3.print("off");
      mySerial_String = "B";
  }
}
void button4_callback(const String & state)   //Ocean
{
     
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
     
      BLINKER_LOG("Toggle on!");
      Button4.print("on");
      mySerial_String = "S";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button4.print("off");
      mySerial_String = "B";
  }
}
void button5_callback(const String & state)     //XDU
{
     
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
     
      BLINKER_LOG("Toggle on!");
      Button5.print("on");
      mySerial_String = "T";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button5.print("off");
      mySerial_String = "B";
  }
}

void button6_callback(const String & state)      //PWM
{
     
  digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
     
      BLINKER_LOG("Toggle on!");
      Button6.print("on");
      mySerial_String = "U";
  }
  else if(state == "off")
  {
     
      BLINKER_LOG("Toggle off!");
      Button6.print("off");
      mySerial_String = "B";
  }
}

void dataRead(const String & data)
{
     
  Blinker.vibrate();    
  Blinker.print("ERROR");
}

void setup()
{
     
  Serial.begin(115200);
  mySerial.begin(9600);
  BLINKER_DEBUG.stream(Serial);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  
  Blinker.begin(auth, ssid, pswd);
  Blinker.attachData(dataRead);
  Button1.attach(button1_callback);
  Button2.attach(button2_callback);
  Button3.attach(button3_callback);
  Button4.attach(button4_callback);
  Button5.attach(button5_callback);
  Button6.attach(button6_callback);
  Slider1.attach(slider1_callback);
}

void loop()
{
     
  mySerial.print(mySerial_String);
  delay(100);
  Blinker.run();
}

6、Blinker用法可以看这个文档:Blinker说明文档
7、对于Button,如果想要更新按键(如on to off)需要Button.print(“on”) or Button.print(“off”)。

8、Blinker app的设置略,大家玩了这么多年手机,应该都会吧/doge

至此你的灯带应该可以进行基本的模式切换和亮度调节,通过电位器和WIFI两种方式

第四步:3D打印

STL文件
https://pan.baidu.com/s/13h840FhqFlePZeEFGJ1Lew
提取码:49p2

第五步:组装

基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第5张图片
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第6张图片
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第7张图片

效果展示(手机拍摄存在色差)

基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第8张图片
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第9张图片
基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第10张图片基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第11张图片基于Arduino UNO+ESP8266+Blinker的炫彩智能氛围灯_第12张图片

遇见的问题

1、ESP和UNO串口通信出现信息丢失等现象影响传输。我们暂时以多次写入作为解决办法,但无法传输多位信息。
2、UNO使用USB烧录时出现计算机无法识别USB现象,重启可以解决99%的问题。
3、该灯不适合显示文字图案
4、跳线不牢固,容易断裂,用热熔胶把焊接地方粘一下
5、亚克力管尽量选择允许误差足够大的规格

你可能感兴趣的:(arduino,嵌入式,物联网)