“我们的动力源于对电子的热爱”
为大家详细介绍最近的语音台灯,不用了解各种通讯协议,直接调用函数,小白也会!
链接:https://pan.baidu.com/s/12m0TMhjH7SR9DHA_pTowBg?pwd=m4zf
提取码:m4zf
想法的产生
刷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(); //记录开始时间,单位s
if(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()单位为s
NMU1.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); //sw
pinMode(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
版权归原作者 悟黎678 所有, 如有侵权,请联系我们删除。