“我们的动力源于对电子的热爱”
为大家详细介绍最近的语音台灯,不用了解各种通讯协议,直接调用函数,小白也会!
链接:https://pan.baidu.com/s/12m0TMhjH7SR9DHA_pTowBg?pwd=m4zf
提取码:m4zf
目录
想法的产生
软件描写
使用Blinker.app
将设备接入米家
Arduino IDE
环境搭建:
EC11编码按键
WS2812
工程代码
代码详解
硬件搭建
灯板
台灯主板
亮度控制
电池充电芯片4056
灯板供电升压 芯片XL6007E1
ESP-12S
供电切换
WS2812焊接
外壳
工程链接
想法的产生
刷B站时发现一位博主 用8266+blinker库制作了一个语音台灯,讲解的非常详细
原视频链接:
ESP8266联动小爱同学/点灯科技远程控灯,小白也能轻松搞定。_哔哩哔哩_bilibili
会用到的点灯科技公司网址:点灯科技-点灯物联网解决方案
有不懂的可以直接查看开发文档,遇到的问题都可以在论坛上查到
我能不能做一个像米家台灯一样的物联网台灯呢,于是就有了这个项目
台灯要可以小爱同学语音控制,还可以在手机上查看台灯的状态信息,还有实体按键控制
8266-12s + EC11编码按钮 + WS2812
软件描写
使用Blinker.app
需要到点灯科技官网下载
注册好后进入此界面(台灯是我已经注册好的) ,点击右上角+添加设备,点击独立设备
我用的ESP8266,所以选择网络接入,接下来生成密钥(设备身份证)
界面就会生成新的设备了, 可以点击编辑按钮添加组件,当组件触发后只需要在8266中的回调函数执行相应任务就行了
将设备接入米家
需要8266烧入代码,点灯科技有示例代码,认真看就懂
#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT //小爱同学light接口函数#include <Blinker.h>char auth[] = "********"; //换成APP获取到的密匙
char ssid[] = "********"; //WiFi账号
char pswd[] = "********"; //WIFI密码
Blinker库下载:https://github.com/blinker-iot/blinker-library/archive/master.zip
只能说人家介绍的非常详细:点灯科技-点灯物联网解决方案
看不明白的也可以跟着视频:ESP8266联动小爱同学/点灯科技远程控灯,小白也能轻松搞定。_哔哩哔哩_bilibili
进入米家APP>我的>其他平台设备>添加,找到电灯科技,返回时就会看到绑定的点灯科技了,点击同步设备就可以看到我们的台灯了
Arduino IDE
环境搭建:
本次的台灯用到了两个库
#include <FastLED.h>
//下载地址:https://github.com/blinker-iot/blinker-library/archive/master.zip#include <Blinker.h>
//可直接在IDE > 项目 > 加载库 > 添加库 里面找到
EC11编码按键
我自己写的不太好用,这位老师讲的好,编码器代码源于:
【Arduino实验篇】第29课 旋转编码器实验_哔哩哔哩_bilibili
int getEncodeTurn(void) //按键编码器
{static int oldA = HIGH;static int oldB = HIGH;static int swcount = 0; //按键开关延时int result = 0;int newA = digitalRead(add); //add.cut.sw是自己定义的引脚int newB = digitalRead(cut);if(newA != oldA || newB != oldB){if(oldA == HIGH && newA == oldA){result = (oldB * 2 - 1);}}oldA = newA;oldB = newB;if(!digitalRead(sw)){ //按压检测,开关台灯delay(30);if(!digitalRead(sw)){while(!digitalRead(sw)){;} //松手检测,长按就会触发看门狗,重启,替代复位开关if(LED!=0){LED = 0;}else {LED = startled;} //开启时等于初始亮度delay(100);} }return result;
}
WS2812
我的指示灯灯珠的IN脚接的是GPIO16,好像用常见的库点不亮灯,找问题花了一点时间,发现FastLED.h可以驱动.我需要自己调颜色,用到了一下操作:
跟多使用方法可以看看:FastLED库 – 太极创客 (taichi-maker.com)
#include <FastLED.h>#define LED_PIN 16 //我的LED信号线IN接在16引脚
#define NUM_LEDS 1 //我的灯带一共级联了1颗LED
CRGB leds[NUM_LEDS];void setup() {FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);FastLED.setBrightness(100); //可以设置全局亮度,调低亮度不刺眼
}void loop() {leds[0].r = 0; leds[0].g = 100; leds[0].b = 30; FastLED.show();delay(1000);leds[0].r = 100; leds[0].g = 20; leds[0].b = 0; FastLED.show();delay(1000);leds[0].r = 0; leds[0].g = 80; leds[0].b = 100; FastLED.show();delay(1000);
}
工程代码
直接粘,省的下载
#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT //小爱同学light接口函数#include <FastLED.h>
#include <Blinker.h>char auth[] = "**********"; //换成APP获取到的密匙
char ssid[] = "**********"; //WiFi账号
char pswd[] = "**********"; //WIFI密码#define LED_PIN 16 //我的LED信号线IN接在16引脚
#define NUM_LEDS 1 //我的灯带一共级联了1颗LED
CRGB leds[NUM_LEDS];#define add 4 //+
#define sw 2 //sw
#define cut 5 //-
#define stdby 14 //充电停止
#define chrg 12 //充电检测
#define pwm 13 //pwm输出引脚#define BUTTON_1 "ButtonKey"
#define Slider_1 "SliderKey"
#define Slider_2 "SliderKey"BlinkerButton Button1("sw"); //按钮名称”sw“
BlinkerSlider Slider1("lightw"); //滑块名称”lightw“
BlinkerSlider Slider2("timing"); //滑块名称”timing“
BlinkerNumber NMU1("runtime"); //文本显示运行时间,"runtime"为文本框名称
BlinkerNumber NMU2("battery"); //文本显示电压,"battery"为文本框名称
BlinkerImage Image1("charge"); //APP充电图标显示int LED = 0; //LED亮度1-100
int startled = 20; //台灯开启的初始亮度
int timeoff = 0; //台灯关闭时间
int timestart; //记录定时开始的时间
int chstate = 8; //供电状态,控制指示灯颜色和app图片
float batteryv = 0; //电池电压
bool oState = false;
bool blinkerrun = true; //按键是否有触发判断
bool Mi_get = false; //小爱同学是否触发//·································································//
void button1_callback(const String & state) //APP按钮控制开关
{BLINKER_LOG("get button state: ", state);Blinker.vibrate(); //手机震动if (state=="on") { if(LED == 0){ //灯已经打开就不操作LED = startled; //开灯占空比设置为20}Button1.print("on"); // 反馈给APP按键开关状态 } else if(state=="off"){LED = 0; //占空比为0,实现关灯Button1.print("off"); // 反馈给APP按键开关状态 timeoff = 0; //台灯关闭时间清零Slider2.print(0); //调整定时滑块 } Slider1.print(LED); //调整亮度滑块
}
void slider1_callback(int32_t value) //滑块亮度控制
{ LED=value; //接收亮度值if(LED == 0){Button1.print("off"); // 反馈给APP按键开关状态 timeoff = 0; //台灯关闭时间清零Slider2.print(0); //调整定时滑块 }else{Button1.print("on"); // 反馈给APP按键开关状态 }Slider1.print(LED); //调整亮度滑块 }
void slider2_callback(int32_t value) //APP滑块定时
{ BLINKER_LOG("get slider value: ", value);if(value!= 0){timeoff = value; //接收台灯关闭时间timestart = Blinker.runTime(); //记录开始时间,单位sif(LED == 0){ //如果灯还未开,启动定时器并开灯LED = startled; Button1.print("on"); // 反馈给APP按键开关状态 Slider1.print(LED); // 调整亮度滑块 } }
}
void timing(void) //定时处理
{if(timeoff > 0){if(Blinker.runTime() - timestart == 60){ //一分钟进入一次timeoff--;Slider2.print(timeoff); //调整滑块 if(timeoff == 0){LED = 0; //关闭灯Button1.print("off"); //反馈给APP按键开关状态Slider1.print(LED); //调整亮度滑块 }}}
}
void miotPowerState(const String & state)//小爱同学语音控制开关
{Mi_get = true; //小爱同学触发标志if (state == BLINKER_CMD_OFF) { LED = 0; //占空比为0,实现关灯 BlinkerMIOT.powerState("off");BlinkerMIOT.print();}else if (state == BLINKER_CMD_ON) {if(LED == 0){LED = startled; //如果灯是关闭的,开灯占空比设置为20 } BlinkerMIOT.powerState("on"); BlinkerMIOT.print();}
}
void miotBright(const String & bright) //小爱同学亮度控制的回调函数
{Mi_get = true; //小爱同学触发标志LED = bright.toInt();BlinkerMIOT.brightness(LED);BlinkerMIOT.print();
}
void miotQuery(int32_t queryCode) // 查询设备状态回调函数
{Mi_get = true; //小爱同学触发标志switch (queryCode){case BLINKER_CMD_QUERY_ALL_NUMBER : // 查询所有设备BLINKER_LOG("MIOT Query All");BlinkerMIOT.powerState(oState ? "on" : "off"); BlinkerMIOT.brightness(LED); //小爱同学查询亮度BlinkerMIOT.print();break;case BLINKER_CMD_QUERY_POWERSTATE_NUMBER : // 查询电源类设备BLINKER_LOG("MIOT Query Power State");BlinkerMIOT.powerState(oState ? "on" : "off");BlinkerMIOT.print();break;default : // 查询其他设备BlinkerMIOT.powerState(oState ? "on" : "off");BlinkerMIOT.print();break;}
}
void miotMode(uint8_t mode) //小爱同学模式控制
{Mi_get = true; //小爱同学触发标志if (mode == BLINKER_CMD_MIOT_NIGHT) {LED = 5; // 夜光模式} else if (mode == BLINKER_CMD_MIOT_READING) {LED = 60; // 阅读模式}else if (mode == BLINKER_CMD_MIOT_COMPUTER) {LED = 20; // 电脑模式}BlinkerMIOT.mode(mode);BlinkerMIOT.print();
}
void Mi_ser() //小爱同学触发处理
{static int count = 0;if(Mi_get){count++;if(count >= 500){Mi_get = false; //小爱同学触发标志count = 0; if(LED==0){Button1.print("off"); // 反馈给APP按键开关状态 timeoff = 0; //台灯关闭时间清零Slider2.print(timeoff); //调整定时滑块 }else{Button1.print("on"); Slider1.print(LED); //调整亮度滑块 }}}
}
void heartbeat() //心跳包数据同步,30-60s上传一次,包含运行时间数据
{ int runtime = 0; //台灯运行时间runtime = Blinker.runTime(); //Blinker.runTime()单位为sNMU1.print(runtime / 60); //上传台灯运行时间Slider1.print(LED); //调整亮度滑块 Image1.print(chstate); //供电状态 NMU2.print(batteryv); //上传电池电压
}
void charge_ser() //指示灯颜色,含有电池电压检测
{ static bool flag = true;batteryv = 6.0*analogRead(A0)/1024-0.18;if(!digitalRead(stdby)){ //充满电,低电平有效chstate = 2; leds[0].r = 0; //绿色leds[0].g = 50; leds[0].b = 15; FastLED.show(); } else if(!digitalRead(chrg)){ //充电chstate = 3; leds[0].r = 40; //橙色leds[0].g = 10; leds[0].b = 0; FastLED.show();} else if(batteryv < 3.4 && digitalRead(chrg)){chstate = 1;leds[0].r = 40; //红色leds[0].g = 0; leds[0].b = 0; FastLED.show();}else if(digitalRead(stdby) && digitalRead(chrg) //电池供电&& batteryv >= 3.4){chstate = 0;if(LED == 0){leds[0].r = 0; leds[0].g = 0; leds[0].b = 0; FastLED.show();}else{leds[0].r = 0; //蓝色leds[0].g = 40; leds[0].b = 50; FastLED.show();}}
}
void bright_led() //输出PWM波
{static int showled;static int first;static int lon;static bool flag = false;if(first != LED){ //检测变化first = LED;flag = true;}if(showled > LED*9){if(flag){lon = (showled - LED*9)/15; //将一次变化分为20次执行flag = false;}showled -=lon; if(showled < LED*9){showled = LED*9;} //防止偏差过大}else if(showled < LED*9){if(flag){lon = (LED*9 - showled)/15;flag = false;}showled += lon; if(showled > LED*9){showled = LED*9;} }Serial.println(showled);analogWrite(pwm,showled); //输出PWM波
}
int getEncodeTurn(void) //按键编码器
{static int oldA = HIGH;static int oldB = HIGH;static int swcount = 0; //按键开关延时int result = 0;int newA = digitalRead(add);int newB = digitalRead(cut);swcount++;if(swcount > 3000){ //延时swcount=0; blinkerrun = true; //按键编码器发后,blinker禁用一段时间 Slider1.print(LED); //调整亮度滑块if(LED==0){Button1.print("off");} // 反馈给APP按键开关状态 else{Button1.print("on");} }if(newA != oldA || newB != oldB){swcount=0; blinkerrun = false;if(oldA == HIGH && newA == oldA){result = (oldB * 2 - 1);Serial.println(result); }}oldA = newA;oldB = newB;if(!digitalRead(sw)){ //按压检测,开关台灯blinkerrun = false; //按键操作时,禁用blinker操作swcount=0; delay(30);if(!digitalRead(sw)){while(!digitalRead(sw)){;} //松手检测,长按就会触发看门狗,重启if(LED!=0){LED = 0;}else {LED = startled;} //开启时等于初始亮度delay(100);} }return result;
}
void setup()
{ Serial.begin(115200);FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);FastLED.setBrightness(50); //可以设置全局亮度,调低亮度不刺眼pinMode(add,INPUT); //+pinMode(sw,INPUT); //swpinMode(cut,INPUT); //- pinMode(stdby,INPUT); //充电停止pinMode(chrg,INPUT); //充电检测 pinMode(pwm, OUTPUT); //亮度analogWriteFreq(25000); //输出pwm频率为25kHz Blinker.begin(auth, ssid, pswd);Button1.attach(button1_callback); // 按键回调Slider1.attach(slider1_callback); // 滑块回调Slider2.attach(slider2_callback); // 滑块回调BlinkerMIOT.attachBrightness(miotBright); // 灯光亮度控制回调BlinkerMIOT.attachMode(miotMode); // 模式控制回调BlinkerMIOT.attachPowerState(miotPowerState); // 电源控制回调BlinkerMIOT.attachQuery(miotQuery); // 查询设备状态回调Blinker.attachHeartbeat(heartbeat); // 心跳包回调}
void loop()
{if(blinkerrun){ //blinkerrun来源于getEncodeTurn(); 按键编码器触发标志Blinker.run(); timing(); //定时处理 charge_ser(); //指示灯Mi_ser(); //小爱同学触发处理Serial.println("run!"); } int change = getEncodeTurn(); //获得编码器信息LED = LED + change;if(LED<0){LED = 0;}if(LED>100){LED = 100;}bright_led(); //PWM输出 Serial.print("LED:"); Serial.println(LED); }
代码详解
举一个按钮的例子:
按钮名称要和点灯APP上的名称一致,例如我将按钮组件命为“SW”,
BlinkerButton Button1("sw"); //按钮名称”sw“
然后在setup里面注册一下按钮的回调函数
Button1.attach(button1_callback); // 按键回调
当APP组件触发后就会执行回调函数里面的内容,我创建的是一个开关按钮,所以它会返回state状态值"on"或"off"
void button1_callback(const String & state) //APP按钮控制开关
{ if (state=="on") { } else if(state=="off"){}
}
我们也可以从设备端将状态传给APP上的按钮,按钮就会呈现"on"或"off"状态
Button1.print("on");
Button1.print("off");
实验代码:
#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT //小爱同学light接口函数#include <Blinker.h>char auth[] = "**********"; //换成APP获取到的密匙
char ssid[] = "**********"; //WiFi账号
char pswd[] = "**********"; //WIFI密码#define BUTTON_1 "ButtonKey"BlinkerButton Button1("sw"); //按钮名称”sw“void button1_callback(const String & state) //APP按钮控制开关
{ if (state=="on") { } else if(state=="off"){}
}void setup() {Serial.begin(115200);Blinker.begin(auth, ssid, pswd);Button1.attach(button1_callback); // 按键回调
}void loop() {Blinker.run();}
话不多说,其他函数点灯科技里介绍很详细:点灯科技-点灯物联网解决方案
硬件搭建
灯板
我采用了3串4并的模式,用的5050灯珠,在嘉立创开的铝基板(白色阻焊不能白嫖,用丝印代替) ,供电电压达到9v就很亮了
台灯主板
焊接好的实物
亮度控制
采用8266直接控制MOS管,这个不太严谨,但能用
也就是台灯是PWM控制亮度的,开关频率达到了30kHz,一点也不晃眼
电池充电芯片4056
最大充电电流可达1A,可以通过调节,就是图中的R1,我选取1.2K,充电电流实测可达0.9A
并且4056有两个引脚输出充电状态,可以用8266检测,并将信息有一个2812指示灯显示
灯板供电升压 芯片XL6007E1
灯板供电实际8.5V左右,升压可以通过图中 R25 R24比值决定,但要注意此芯片最多输出2A电流
ESP-12S
第一版用的三色RGB灯,需要三个io口,就导致GPIO0 GPIO15也使用上了,出现了一些问题。后面用到2812就解决问题了。IO口注意事项如下:
用了8266的ADC检测电池电压,8266有10位ADC,输入最高1V。用了10k,2k电阻分压。
供电切换
简易的供电切换电路,有外部供电时就用外部供电并为电池充电。
开关用的是,需要将一个引脚剪掉,节省空间,放下电池(家里有条件的可以加两节18650)
WS2812焊接
需要将灯直立起来,且只需要焊接 三个引脚
外壳
为了打印出外壳,终于去学了下Solid Works,比原来的建模软件好用多了!
支撑的杆用的是PVC管子:粗杆用的外经10mm,壁厚1mm,细杆用的外经8mm,壁厚1mm
为大家整理好了:
工程链接
链接:https://pan.baidu.com/s/12m0TMhjH7SR9DHA_pTowBg?pwd=m4zf
提取码:m4zf