概述
手头有一块ws2812的灯板,想着能不能玩点什么。于是做了个APP去控制ws2812。写一篇博文记录下,废话不多说,看我怎么做。
(注:本文是小白简易教程)
首先来看下实际效果B站链接,点击这里。
这是整体的框图,控制是单向的,并不需要接收反馈。
一、简单概念介绍
MQTT协议:
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
简单来说,MQTT是一种轻量级小开销的网络协议,适合嵌入式等小型设备的云端通信,很适合物联网,在智能家居中有很多的应用。因为信息量小,所以也很快,但前提是得有网络接入点。
信息的传输是通过主题(topic)管理的。发布者有需要分发的数据时,其向连接的消息代理发送携带有数据的控制消息。代理会向订阅此主题的客户端分发此数据。发布者不需要知道订阅者的数据和具体位置;同样,订阅者不需要配置发布者的相关信息。
再多的就不多加深入了,有兴趣可以进一步自己去了解。
WS2812:
这是一个RGB灯,大概长这样(灯条状的也有,五花八门)。
WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
WS2812/2811只需一根信号线就能控制灯带上所有led。多个灯带间可以通过串联轻松延长。在30hz的刷新频率下一个信号线能够控制至多500个led。
简而言之啊,它就是一个可以任意调整RGB值的彩色灯,很酷,很炫。
只要给他接上电源(VSS),接地(GND),再给一个输出(DIN),就可以控制复数个ws2812了,单个ws2812的引脚图如上,每个ws2812之间的DOUT和DIN是相互连接的,你输入的数据就像火车,从每个ws2812的DIN流进,再从DOUT流出,流向下一个ws2812的DIN一直到底。对整个灯板(条)来说,你只要接好以下三根线就可以了。
值得注意的是怎么去控制(怎么发送命令)。每个器件都有它自己的规则,ws2812也不例外。来看看它的01码(如下图)。我们发现,只要控制高电平和低电平的时间占比为2:1,就是1码,当这个比为1:2的时候则为0码,但是我们发现这个时间的误差为纳秒级的,这对你的控制装备的时钟就有要求。
有了01码后就好说了,我们知道设定RGB有三个值,分别是R值、G值和B值,三个值的范围是(0-255),换成二进制也就是八位,也就是说我们只要往(DIN)写入8*3=24位01码,我们就可以控制一个灯的颜色了。多个ws2812以此类推,它是串联过去的。
你或许觉得这样会很麻烦,但是不用担心,我们有现成的控制库可以使用,所以前面的内容懂个大概就好了。
ESP8266:
这个东西我相信有不少人都很熟悉的,简单来说就是一块可以接入互联网的小板子,它有WIFI模块,内部集成MCU可以实现单片机之间的通信。这里我们用它控制WS2812同时使它联网。
Android 开发:
这里我们得准备一台手机,零基础也没有关系,因为我也差不多哈哈。但这并不妨碍我们在实际动手的过程中学习。
ONENET平台:
中国移动的一个物联网平台,我们就是在它提供的服务上,来实现APP与esp8266的通信的。
二、每个部分的开发操作流程
我们自下而上好了。
esp8266:
这边我用的是arduino的IDE,旁边写有注释的,自己留意。看不懂的地方可以再留言。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>//灯厂的库
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 4//定义esp输出管脚,GPIO4,也就是板子上标的2
#define NUMPIXELS 64//用的是8*8的ws2812,自然是64个
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);//像素初始化,是库的标准使用方法,可以自己与GitHub上看
WiFiClient espClient;
PubSubClient client(espClient);
const char* wifissid = "your wifi"; //改成自己家wifi
const char* password = "your wifi password"; //改成自己家wifi
const char* mqtt_server = "183.230.40.39";//onenet的订阅IP地址
const char* mqtt_id = "device ID"; //设备ID,写自己的
const char* product_id="product ID";//产品ID,写自己的
const char* key="API_key";
const char* Mqtt_sub_topic = "topic_pub"; //订阅的TOPIC,用自己的topic名字
const char* Mqtt_pub_topic = "topic_sub"; // 上报消息给手机APP的TOPIC
long last_time=0;
uint8_t RDE,GRE,BLE,LIG;//RGB数值
//获取x的y次方; x^y
unsigned int power(int x, int y)
{
unsigned int result = 1;
while (y--)
result *= x;
return result;
}
//将字符串的内容转换为 16进制,这里用到了上面的power函数,是为了能够吧消息中的字符串信息转化为esp可以控制ws2812的数值
unsigned int hex_conver_dec(String src)
{
char str_array[src.length()+1];
src.toCharArray(str_array, src.length()+1);
char *tmp = str_array;
int len = 0;
unsigned int hexad = 0;
char sub = 0;
while (1)
{
if (*tmp == '0') //去除字符串 首位0
{
tmp++;
continue;
}
else if (*tmp == 'X')
{
tmp++;
continue;
}
else if (*tmp == 'x')
{
tmp++;
continue;
}
else
break;
}
len = strlen(tmp);
for (len; len > 0; len--)
{
sub = toupper(*tmp++) - '0';
if (sub > 9)
sub -= 7;
hexad += sub * power(16, len - 1);
}
return hexad;
}
void setup() {
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
pixels.begin();
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 6002);
client.setCallback(callback);
}
//设置WIFI信息
void setup_wifi() {
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifissid);
WiFi.begin(wifissid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//回调函数
void callback(char* topic, byte* payload, unsigned int length) {
String msg="";
String LED_set = "";
float k;
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
msg+= (char)payload[i];
}
Serial.println(msg);
RDE=hex_conver_dec(msg.substring(0,2));
GRE=hex_conver_dec(msg.substring(2,4));
BLE=hex_conver_dec(msg.substring(4,6));
LIG=hex_conver_dec(msg.substring(6,8));
k=(float)LIG/100;
show(RDE,GRE,BLE,k);
Serial.println(RDE);
Serial.println(GRE);
Serial.println(BLE);
Serial.println(k);
}
//检测连接
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(mqtt_id,product_id,key)) {
Serial.println("connected");
//连接成功以后就开始订阅
client.subscribe(Mqtt_sub_topic,1);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
//灯光部分,根据RGB值显示灯光矩阵控制色温,这里的代码写的有点烂,因为我是在原来的基础上改动的,当时写的和最近写的有不少出入,方便就这么改了,放心功能是正常的
void show(uint8_t r,uint8_t g,uint8_t b,float k)
{
uint32_t rgb,RGB1;
uint8_t RDE1,GRE1,BLE1;
RGB1= ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
rgb=changeL(RGB1,k);
RDE1= (uint8_t) (rgb >> 16);
GRE1= (uint8_t) (rgb >> 8);
BLE1= (uint8_t) (rgb);
pixels.fill(pixels.Color(RDE1,GRE1,BLE1),0,NUMPIXELS);//设置RGB的值
pixels.show();//展示
}
//根据色彩亮度改变色温,依照公式,改变亮度不是简单的降低每个RGB的值,那样会改变颜色的,这个可以去网上查阅资料。亮度范围是0-1。
uint32_t changeL(uint32_t rgb, float k) {
uint8_t r, g, b;
float h, s, v;
uint8_t cmax, cmin, cdes;
r = (uint8_t) (rgb >> 16);
g = (uint8_t) (rgb >> 8);
b = (uint8_t) (rgb);
cmax = r > g ? r : g;
if (b > cmax)
cmax = b;
cmin = r < g ? r : g;
if (b < cmin)
cmin = b;
cdes = cmax - cmin;
v = cmax / 255.0f;
s = cmax == 0 ? 0 : cdes / (float) cmax;
h = 0;
if (cmax == r && g >= b)
h = ((g - b) * 60.0f / cdes) + 0;
else if (cmax == r && g < b)
h = ((g - b) * 60.0f / cdes) + 360;
else if (cmax == g)
h = ((b - r) * 60.0f / cdes) + 120;
else
h = ((r - g) * 60.0f / cdes) + 240;
v *= k;
float f, p, q, t;
float rf, gf, bf;
int i = ((int) (h / 60) % 6);
f = (h / 60) - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i) {
case 0:
rf = v;
gf = t;
bf = p;
break;
case 1:
rf = q;
gf = v;
bf = p;
break;
case 2:
rf = p;
gf = v;
bf = t;
break;
case 3:
rf = p;
gf = q;
bf = v;
break;
case 4:
rf = t;
gf = p;
bf = v;
break;
case 5:
rf = v;
gf = p;
bf = q;
break;
default:
break;
}
r = (uint8_t) (rf * 255.0);
g = (uint8_t) (gf * 255.0);
b = (uint8_t) (bf * 255.0);
uint32_t returnColor = ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
return returnColor;
}
//执行连接
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
ONENET:
onenet的本质就是一台服务器,我选择它的原因是它是免费的而且比较可靠,当然你也可以选择阿里云或者其他的什么云或者物联网接入平台,反正我们的根本目的就是找到一台可以为我们提供MQTT协议的服务器。
既然要在这个平台上操作,我们首先得有自己的账号,然后进入控制台,我习惯用旧版,点击切换至旧版,
如下选择多协议接入
然后添加产品,记得协议选择MQTT
信息自己填,放心大胆,创建成功后,点击产品,从左侧的设备列表中添加设备,信息自己填,放心大胆
注意以下几个信息:产品ID,设备ID,APIkey。服务器的地址和端口号我们是知道的,但是想想onenet上这么多用户这么多产品设备我们怎么知道信息从哪里发往哪里呢。我们可以这么理解,onenet是一个小区,产品ID就是楼栋的几幢几幢(楼号),而设备ID就是某栋楼的某扇门,但是开门还需要钥匙,这就是我们的APIkey了。通过层层问路,就到达了我们的目的地。所以这几个信息我们是要留意的,我们要把相应的信息填入到我们发送端APP中去和esp8266中,这样才能建立通信不是么。
这样我们云端的部分就完成了,就差我们的APP啦。
注:onenet有自己的调试工具,相关信息可以去查找其他网络资料。
Android APP开发:
如果我自己来说,绝对是长篇了,因为这本来就是一个大块知识。这里我推荐一个up主:阿正啷个哩个啷。他讲的简短易用,学了之后就能开发简单的APP了。
这里我直接把我的工程放上来,当然直接拿过去用可能会存在版本问题,所以可以打开来自己参考。用的是Android Studio,怎么搭配环境都是基本的了,老生常谈自己领会吧。当然我会把apk也直接放上来,可以直接体会下我这个小项目。
度盘链接:
https://pan.baidu.com/s/18fANWXFaUWuhEhBZSW_LYg
提取码:
chgi
三、总结
物联网也总是这么一个把东西接入网络,然后互相通信。都说了是Internet of thing了嘛。这个工程虽然看上去很简单,但也融合了不少的知识,比如嵌入式开发,安卓开发,一些基本的网络知识等等。坐而言不如起而行,有时候实际动手才是学知识的最快来源。感谢你阅读到最后,大家一起勉励!
最后
以上就是调皮时光为你收集整理的物联网浅尝:使用MQTT接入onenet平台,结合APP使用esp8266控制ws2812的全部内容,希望文章能够帮你解决物联网浅尝:使用MQTT接入onenet平台,结合APP使用esp8266控制ws2812所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复