ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
1.前言
这一篇,博主将教大家怎么去实现一个WiFi RGB彩灯。
先来一个博主已经实现功能的图片,如下:

当然,博主也拍了运行视频,请点击 传输门。
1.1 知识储备
本篇需要用到以下知识点:
- 运用到ArduinoJson库,github传送门,请读者自行下载该库放到Arduino安装目录(这里直接使用,博主后面计划会详细讲解该库,敬请期待);
- 运用到TCP Server服务,请参考 ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
- 运用到STA模式,请参考 ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
- 运用到一键配网功能,请参考 ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
1.2 设计原理
这里的局域网,博主理解为手机、ESP8266均连接同一个路由wifi,然后8266是作为服务端,手机作为客户端,手机再通过wifi给8266发送数据,8266接收到数据再把数据分发给Arduino,然后Arduino解析协议数据以达到控制效果。
设计图如下:

2.实验准备
- ESP202 8266小黄板或者NodeMcu开发板或者其他8266模块;
- Android 手机 + 博主App;
- mega2560开发板(博主偷懒想用两个硬件串口,读者也可以用UNO);
- RGB LED模块以及若干线;
3.实验步骤
我们本应用需要分成两个部分的设计——Mega2560 Arduino端以及ESP8266端。需要分别往两块板子烧录代码以及连接电路。
3.1 8266端代码
往8266烧入以下代码:
/**
* 日期:2019/02/18
* 功能:wifi lamp 8266端
* 加入SmartConfig功能
* 作者:单片机菜鸟
**/
#include <ESP8266WiFi.h>
#define MAX_SRV_CLIENTS 3 //最大同时联接数,即你想要接入的设备数量,8266tcpserver只能接入五个,哎
#define LED 2
#define DEBUG //是否开启debug功能
#ifdef DEBUG
#define DebugPrintln(message) Serial.println(message)
#else
#define DebugPrintln(message)
#endif
#ifdef DEBUG
#define DebugPrint(message) Serial.print(message)
#else
#define DebugPrint(message)
#endif
const unsigned long BAUD_RATE = 115200;// serial connection speed
WiFiServer server(8266);//你要的端口号,随意修改,范围0-65535
WiFiClient serverClients[MAX_SRV_CLIENTS];
int flag = HIGH;//默认当前灭灯
/**
* @Desc 初始化操作
*/
void setup() {
Serial.begin(BAUD_RATE);
pinMode(LED,OUTPUT);
digitalWrite(LED, HIGH);
if(!autoConfig()){
smartConfig();
DebugPrint("Connecting to WiFi");//写几句提示,哈哈
while (WiFi.status() != WL_CONNECTED) {
//这个函数是wifi连接状态,返回wifi链接状态
delay(500);
DebugPrint(".");
}
}
delay(1000);
digitalWrite(LED, LOW);
DebugPrintln("IP address: ");
DebugPrintln(WiFi.localIP());//WiFi.localIP()返回8266获得的ip地址
server.begin();
server.setNoDelay(true); //加上后才正常些
//使能软件看门狗的触发间隔
ESP.wdtEnable(5000);
}
/**
* @Desc 主函数
*/
void loop() {
uint8_t index;
if (server.hasClient()){
for (index = 0; index < MAX_SRV_CLIENTS; index++){
if (!serverClients[index] || !serverClients[index].connected()){
if (serverClients[index]) serverClients[index].stop();//未联接,就释放
serverClients[index] = server.available();//分配新的
continue;
}
}
//8266tcpserver只能接入五个 超出的需要释放
WiFiClient serverClient = server.available();
if (serverClient){
serverClient.stop();
}
}
for (index = 0; index < MAX_SRV_CLIENTS; index++){
if (serverClients[index] && serverClients[index].connected()){
//处理客户端发过来的数据
if (serverClients[index].available()){
while (serverClients[index].available())
//把数据发送给mega
Serial.write(serverClients[index].read());
}
}
}
if(Serial.available()>0){
char ch = Serial.read();
//收到ardunio发过来的进入smartconfig模式的命令
if(ch == '1'){
smartConfig();
delay(1000);
digitalWrite(LED, LOW);
DebugPrintln("IP address: ");
DebugPrintln(WiFi.localIP());//WiFi.localIP()返回8266获得的ip地址
}
}
//喂狗
ESP.wdtFeed();
}
/**
* 自动连接20s 超过之后自动进入SmartConfig模式
*/
bool autoConfig(){
WiFi.mode(WIFI_AP_STA); //设置esp8266 工作模式
WiFi.begin();
delay(2000);//刚启动模块的话 延时稳定一下
DebugPrintln("AutoConfiging ......");
for(int index=0;index<20;index++){
int wstatus = WiFi.status();
if (wstatus == WL_CONNECTED){
DebugPrintln("AutoConfig Success");
DebugPrint("SSID:");
DebugPrintln(WiFi.SSID().c_str());
DebugPrint("PSW:");
DebugPrintln(WiFi.psk().c_str());
return true;
}else{
DebugPrint(".");
delay(1000);
flag = !flag;
digitalWrite(LED, flag);
}
}
DebugPrintln("AutoConfig Faild!");
return false;
}
/**
* 开启SmartConfig功能
*/
void smartConfig()
{
WiFi.mode(WIFI_STA);
delay(2000);
DebugPrintln("Wait for Smartconfig");
// 等待配网
WiFi.beginSmartConfig();
while (1){
DebugPrint(".");
delay(500);
flag = !flag;
digitalWrite(LED, flag);
if (WiFi.smartConfigDone()){
//smartconfig配置完毕
DebugPrintln("SmartConfig Success");
DebugPrint("SSID:");
DebugPrintln(WiFi.SSID().c_str());
DebugPrint("PSW:");
DebugPrintln(WiFi.psk().c_str());
WiFi.mode(WIFI_AP_STA); //设置esp8266 工作模式
WiFi.setAutoConnect(true); // 设置自动连接
break;
}
}
}
整个代码的流程是这样的:
- 8266上电启动后,进入自动连接模式autoConfig(根据上一次成功连接的SSID和密码),最多尝试20s,在尝试连接的过程中,LED灯会每隔1s闪烁一下,表示正在连接状态;如果连接成功,就直接配置8266服务器模式。
- 如果上面操作失败(可能连接的热点不存在了或者修改了密码),那么会自动进入一键配置模式SmartConfig等待手机一键配置,这个过程是不限制时间的,LED会每隔0.5s闪一下,表示处在SmartConfig状态,这时大家可以去手机端开始一键配置。
这里代码功能其实就是把8266当做服务端,8266连接上路由wifi,然后监听连接进来的客户端(这里是手机)
读者安装好app之后,会看到如下的手机配置页面,请一步步设置:



如果提示失败,一般都是因为你的8266模块并没有进入到SmartConfig模式,可以尝试重启一下。再者就是,smartconfig不保证配网成功率100%;
3.2 mega端代码
烧写以下代码到mega2560板子,代码如下:
/**
* 日期:2019/02/18
* 功能:wifi lamp arduino端
* 作者:单片机菜鸟
**/
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
const unsigned long BAUD_RATE = 115200; // serial connection speed
const size_t MAX_CONTENT_SIZE = 50;
const size_t t_bright=1,t_color=2,t_frequency=3,t_switch=4;
//#define UNO //uncomment this line when you use it with UNO board
#define MEGA //uncomment this line when you use it with MEGA board
#ifdef UNO
SoftwareSerial mySerial(10,11);
#endif
#ifdef UNO
#define WifiSerial Serial
#define MyDebugSerial mySerial
#endif
#ifdef MEGA
#define WifiSerial Serial1
#define MyDebugSerial Serial
#endif
//该条语句用于使能DEBUG输出信息,屏蔽掉就不会输出debug调试信息
#define DEBUG
//该条语句用于使能是共阴RGB 屏蔽掉就是共阳RGB
//#define COMMON_GND
#ifdef DEBUG
#define DBGLN(message) MyDebugSerial.println(message)
#else
#define DBGLN(message)
#endif
#ifdef UNO
#define PIN_RED 3 //red 引脚
#define PIN_GREEN 5 //green 引脚
#define PIN_BLUE 6 //blue 引脚
#define PIN_ENABLE 9 //使能引脚 pwm控制亮度
#define PIN_KEY 7// 按键
#else
#define PIN_RED 2
#define PIN_GREEN 3
#define PIN_BLUE 4
#define PIN_ENABLE 5
#define PIN_KEY 6
#endif
int red = 0,green = 0,blue = 0;
int type = 4;//当前模式 1亮度 2颜色 3呼吸 4开关
int frequency = 1;//频率
int switch_status = 1;//关闭 or 开启
int bright = 1;//亮度
char response[MAX_CONTENT_SIZE];
int fadeValue = 0;//当前亮度
bool isAdd = true;//是否是从暗到亮
// 定义记录按键当前状态的变量
int state_btn;
// 定义记录按键最近一次状态变化的变量,并初始化状态为LOW。
int lastButtonState = LOW;
// 定义记录最近一次抖动的时间变量,并初始化时间为0毫秒。
long lastDebounceTime = 0;
// 定义延迟抖动的时间变量
long debouncdDelay = 60;
/**
* @Desc 初始化操作
*/
void setup() {
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
pinMode(PIN_ENABLE, OUTPUT);
pinMode(PIN_KEY,INPUT);
WifiSerial.begin(BAUD_RATE);
#ifdef DEBUG
#ifdef UNO
MyDebugSerial.begin(9600);//软串口9600稳定
#else
MyDebugSerial.begin(BAUD_RATE);
#endif
#endif
DBGLN("Arduino Init End");
}
/**
* @Desc 主函数
*/
void loop() {
if(WifiSerial.available()>0){
clrEsp8266ResponseBuffer();
int data_size = ReceiveMessage(response, sizeof(response));
if(data_size>0){
//开始解析数据
parseData(response);
}
}
if(type == t_frequency){
//呼吸灯效果
breatheRGB(frequency);
}
checkButton();
}
/**
* 读取串口缓冲区里面的数据
*/
int ReceiveMessage(char* content, size_t maxSize){
//不用 readBytes 因为比较耗时
size_t length = WifiSerial.readBytesUntil('}',content, maxSize);
content[length] = '}';
content[++length] = 0;
DBGLN(content);
return length;
}
/**
* @Desc 解析json
* 有三种
* 1.亮度控制页面(0 暗 1正常 2亮)
* {
* "t": 1,
* "bb": 2
* }
* 2.颜色控制页面
* {
* "t": 2,
* "cr": 154,
* "cg": 147,
* "cb": 255
* }
* 3.呼吸灯控制页面(0 慢呼吸 1正常 2快)
* {
* "t": 3,
* "gf": 1
* }
* 4.开关控制(0关闭 1开启)
* {
* "t": 4,
* "ss": 1
* }
**/
bool parseData(char* content) {
// -- 根据我们需要解析的数据来计算JSON缓冲区最佳大小
// 如果你使用StaticJsonBuffer时才需要
// const size_t BUFFER_SIZE = 1024;
// 在堆栈上分配一个临时内存池
// StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
// -- 如果堆栈的内存池太大,使用 DynamicJsonBuffer jsonBuffer 代替
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(content);
if (!root.success()) {
Serial.println("JSON parsing failed!");
return false;
}
type = root["t"];
switch(type){
case t_bright:
bright = root["bb"];
brightRGB(bright);
break;
case t_color:
red = root["cr"];
green = root["cg"];
blue = root["cb"];
colorRGB(red,green,blue);
break;
case t_frequency:
frequency = root["gf"];
break;
case t_switch:
switch_status = root["ss"];
bool enable = switch_status == 1;
switchRGB(enable);
break;
}
return true;
}
/**
* 控制灯亮度
*/
void brightRGB(int bright){
int level = bright%3;
int bright_level;
switch(level){
case 0://暗 50
bright_level = 50;
break;
case 1://正常 100
bright_level = 100;
break;
case 2://亮 200
bright_level = 200;
break;
}
#ifdef COMMON_GND
//共地
analogWrite(PIN_ENABLE,bright_level);
#else
analogWrite(PIN_ENABLE,255-bright_level);
#endif
}
/**
* 控制RGB颜色
*/
void colorRGB(int red, int green, int blue){
#ifdef COMMON_GND
analogWrite(PIN_RED,constrain(red,0,255));
analogWrite(PIN_GREEN,constrain(green,0,255));
analogWrite(PIN_BLUE,constrain(blue,0,255));
#else
analogWrite(PIN_RED,constrain(255-red,0,255));
analogWrite(PIN_GREEN,constrain(255-green,0,255));
analogWrite(PIN_BLUE,constrain(255-blue,0,255));
#endif
}
/**
* 控制亮灭
*/
void switchRGB(bool enable){
if(enable){
//打开
#ifdef COMMON_GND
//共地
analogWrite(PIN_ENABLE,255);
#else
analogWrite(PIN_ENABLE,0);
#endif
}else{
//关闭
#ifdef COMMON_GND
//共地
analogWrite(PIN_ENABLE,0);
#else
analogWrite(PIN_ENABLE,255);
#endif
}
}
/**
* 呼吸灯
*/
void breatheRGB(int frequency){
int level = frequency%3;
int f_level;
switch(level){
case 0://慢 50
f_level = 3;
break;
case 1://正常 100
f_level = 10;
break;
case 2://快 200
f_level = 20;
break;
}
if(isAdd){
//递增方向
fadeValue +=f_level;
if(fadeValue>=255){
fadeValue = 255;
isAdd =false;
}
}else{
//递减方向
fadeValue -=f_level;
if(fadeValue<=0){
fadeValue = 0;
isAdd =true;
}
}
analogWrite(PIN_ENABLE,fadeValue);
delay(20);
}
/**
* 检查按键功能
*/
void checkButton(){
int buttonState = digitalRead(PIN_KEY);//读取当前按键状态
if(buttonState != lastButtonState){
//如果按键发生了变化 则重新设置最近一次抖动的时间
//方法millis()可以获取当前时间,单位统一为毫秒。
lastDebounceTime = millis();
}
// 判断按键按下状态时间间隔是否大于延迟抖动的时间长度。
if(millis()-lastDebounceTime>debouncdDelay){
// 判断当前的按键状态是否和之前有所变化
if(buttonState != state_btn){
// 如果发生了变化,
// 则更新按键状态变量。
state_btn = buttonState;
if(state_btn == HIGH){
//再次确认是否真的按下了按键
DBGLN("smartconfig");
WifiSerial.write('1');
}
}
}
// 更新按键最近一次状态变化的变量
lastButtonState = buttonState;
}
void clrEsp8266ResponseBuffer(void){
memset(response, 0, MAX_CONTENT_SIZE); //清空
}
代码解释:
这里我们用到了一个按键,按下按键就给8266发个命令进入SmartConfig模式(Arduino和8266通过串口1通信)。
加上读者已经配置成功Smartconfig了,那么我们连接好电路之后就可以进行控制操作了。请看app控制页面:



接下来,如果有使能Debug的话,应该会打印以下信息:

注意:
- 最后下载到板子的时候,最好把调试信息去掉,会影响到解析速度。注释掉 #define DEBUG
- 在上面的app源码中,博主已经将smartconfig的代码抽取成一个android module,懂android开发的同学可以自行取来用。
4.实验总结
博主简单介绍如何基于之前讲的基础知识来做一个简单项目,希望大家巩固认识。
ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯的更多相关文章
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266烧录配置
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇① 走进ESP8266的世界
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇④ ESP8266与EEPROM
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
随机推荐
- MySql错误处理--错误代码和消息
附录B:错误代码和消息 目录 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 本章列出了当你用任何主机语言调用MySQL时可能出现的错误.首先列出了服务器错误消息.其次列出了客户端 ...
- 为博客添加 Gitalk 评论插件
背景 Disqus需要翻墙才能正常使用 畅言有广告 2种评论系统都很难统一管理 优化 使用Gitalk评论插件 , gitalk 使用 Github 帐号登录,界面干净整洁,支持 MarkDown语法 ...
- Spring boot 梳理 - Spring boot 与 JSP
若使用Spring boot 开发web应用中使用jsp,需要打包成war,并部署到非嵌入式servlet容器中运行,在嵌入式servlet中无法运行,且需要匹配非嵌入式servlet版本与Sprin ...
- 安装centos8
一. 镜像下载 国内源下载镜像:(推荐) http://mirrors.aliyun.com/centos/8.0.1905/isos/x86_64/CentOS-8-x86_64-1905- ...
- layDate——初步使用
layui系列中layDate的使用教程网址 https://www.layui.com/laydate/ 我这里简单举例: 1.引入js <script type="text/jav ...
- CSS3相关编码规范
一.CSS书写顺序 1.位置属性(position, top, right, z-index, display, float等)2.大小(width, height, padding, margin) ...
- phaser学习总结之Text对象详解
前言 在phaser学习总结之phaser入门教程中,我们已经入门了phaser,对phaser也有所了解但是我们并没有对phaser中的每个对象的属性和方法进行详解,本章将对phaser中的Text ...
- 织梦DEDE分类信息实现联动筛选(支持多条件多级选项)解决方案
发布时间:2017-03-25 来源:未知 浏览:404 关键词: 很多织梦建站的站长在做产品列表页的时候,产品分类多而且都是关联的,用户不能快速的找到自己需要的东西,很多情况下都需要用到筛选功能,织 ...
- [UWP] 解决FlipView图片放大的诡异bug
想要实现图片的放大缩小可以通过在Image外面套一个ScrollViewer,然后设置ScrollViewer的ZoomMode="Enabled" <FlipView It ...
- 分布式系统的延时和故障容错之Spring Cloud Hystrix
本示例主要介绍 Spring Cloud 系列中的 Eureka,如何使用Hystrix熔断器容错保护我们的应用程序. 在微服务架构中,系统被拆分成很多个服务单元,各个服务单元的应用通过 HTTP 相 ...