欢迎下载研华科技主题白皮书:
【AIoT】研华AIoT边缘智能及网关解决方案
[摘要] 物联网、大数据、云服务与人工智能,是产业数位转型的关键科技趋势,透过创新应用,将替各产业带来巨大商机与全新 局面。研华以坚强的硬件实力为基础,开发出多元软件服务。
https://www.eefocus.com/resource/advantech/index.php?act=detail&item=1496
这篇开始,我们就真正做《网关》升级版教程了,采用arduino+zigbee哦。
arduino简单易学,zigbee自组网(如果不懂c语言,直接用就好,我们已经刷好自组网代码)!
这次我们的教程是通过以下配件实现《网关》功能,并在手机端点击按钮,使zigbee模块上的灯闪亮(实现是发送真正的命令了{ckxxxxxxxxx}的格式)!
通过不同的格式命令就可以操作开、关、接收、发送数据!之后《温湿传感器》《zigbee插座》等就可以直接连上了!
上面就是arduino开源网关的配件。
1、SMARTRF04EB(ZIGBEE下载器)
2、CP2102(arduino下载器)
3、电源供电
4、arduino板(含w5100、zigbee插槽、SD卡座)
5、zigbee开发板 (如果只想学zigbee只需要两块开发板和zigbee模块,自组网学习哦)
6、zigbee模块
实现自己的arduino开源网关吧(自己有arduino和w5100是可以代替我们的arduino板的)。
第一部份:arduino板刷上代码。
一、安装CP2102驱动(USB驱动)
https://pan.baidu.com/s/1o6iDLcm(下载后直接安装或发现有新硬件就更新驱动)。
二、将CP2102连上arduino板底下的插槽的一定要一一对应哦。DTR->DTR
GND->GND
TX->RXI
RX->TXO
VDD3.3->VCC
三、刷arduino代码
大家可以直接在这里下载源代码:
https://pan.baidu.com/s/1i386zPV(包含arduino软件和所有的库)
下面我们就贴上代码(都有注释哦)
#include <iBoardRF24Network.h>
#include <iBoardRF24.h>
#include <digitalWriteFast.h>
#include <SPI.h>
#include <Ethernet.h>
//请到m.znck007.com申请登陆-》家中环境-》网关,里可以看到!
#define APIKEY "xxxxxxxxxxxxxxxx" //设置apikey
uint16_t sid=001;//设置sid(设备号)
//NRF24l01发送接收节点
const uint16_t this_node = 0;
const uint16_t other_node = 1;
//NRF24l01收发数据
struct payload_t
{
uint32_t ms;
uint32_t data;
char sendchar[20];
};
//NRF24l01脚针设置
iBoardRF24 radioSend(3,8,5,6,7,2);
iBoardRF24Network networkSend(radioSend);
bool ispayload=false;//NRF24l01收发判断
uint16_t sendChannel=1;//NRF24l01发送频道
uint32_t sendCount=0;//NRF24l01发送次数
char incomingData[20]={0};//NRF24l01接收到的字符(其它设置发过来)
//设置MAC地址,如果有二个请改为不同(随意)
static byte mymac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
EthernetClient client;//声明网关类
char server[] = "api.znck007.com";//声明API网址
//char urlBuf[] = "/index.php";
static long timer;//用于规定时间间隔
unsigned long last_http;//记录http时间,用于http超时判断,目前20秒无响应则重新GET。
bool ishttpget=false;//标示http是否已经结束
bool isUpdate=false;//成功则更新服务器数据为正常
char updateData[20]={0};//更新的字符(服务器通过字符分析指定某个设备)
//串口通信处理(主要用于zigbee通信)
unsigned long serialnowlast;
char serialbuff[80]={0};
char serialData;
int seriali=0;
void setup(void)
{
//设置串口波特率
Serial.begin(115200);
Serial.println("IBOARD_GATEWAY_ZIGBEE/RF24Network");
//NRF24l01初始化
SPI.begin();
radioSend.begin();
//获取IP DNS等
Serial.println("n[getDHCPandDNS]");
if (Ethernet.begin(mymac) == 0)
{
Serial.print(F("Failed to configure Ethernet using DHCPn"));
while(1);
}
else
{
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print("."); }
Serial.println("Ethernet configuration OK");
}
//连接web服务器
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected");
client.println("GET /index.php HTTP/1.1");
client.println("Host: api.znck007.com");
client.println("Connection: close");
client.println();
}
else {
// kf you didn't get a connection to the server:
Serial.println("connection failed");
client.stop();
}
//判断web服务器是否正常
timer=millis();
while ((!client.available()) && (millis()-timer)<2000);
if (client.available()) {
char c = client.read();
Serial.print(c);
client.stop();
}
timer = millis();
//完成setup
Serial.println("setup success");
}
void loop(void)
{
// //NRF24l01检测接收数处理
// //如果使用NRF24l01,请启动这里(并删除ZIGBEE检测接收数据处理)
// networkSend.begin(/*channel*/ sid, /*node address*/ this_node);
// // Pump the network regularly
// networkSend.update();
//
// // Is there anything ready for us?
// timer=millis();
// //while ((!networkSend.available()) && (millis()-timer)<2000);
// while(networkSend.available())
// {
// // If so, grab it and print it out
// RF24NetworkHeader header;
// payload_t payload;
// memset(payload.sendchar, 0, 20);
// networkSend.read(header,&payload,sizeof(payload));
// Serial.print("Received packet #");
// Serial.print(payload.data);
// Serial.print(" at ");
// Serial.print(payload.ms);
// Serial.print(" getchar ");
// Serial.println(payload.sendchar);
//
// ispayload = true;
//
// get_html_body(payload.sendchar,incomingData);
// Serial.println(incomingData);
// }
//
// if(!ishttpget)
// {
// if(ispayload)
// {
// ispayload = false;
//
// if(strstr(incomingData,"{ck") && strstr(incomingData,"}") )
// {
// last_http = millis();
// ishttpget=true;
//
// Serial.println("n>>> POST");
// static char buf[20]={0};
// sprintf(buf,"%s",incomingData);
//
// client_post(server,APIKEY,buf);
// my_result_cb();
//
// return;
// }
//
// }
//
//
// }
//ZIGBEE检测接收数据处理
if(!ishttpget)
{
unsigned long serialnow = millis();//获取现在的时间
if(serialnow - serialnowlast >= 5000)//如果数据间隔超过5秒而清空字符(为了防止数据错乱)
{
serialnowlast = millis();
memset(serialbuff, 0, 80);
seriali=0;
}
bool isSerial=false;
while( Serial.available() )//如果串口有数据(ZIGBEE或电脑发过来的)
{
if(seriali==0)
{
Serial.println("Serial->");//打印出来方便调试
}
serialData=(char)Serial.read();//读取串口数据
//Serial.print(serialData);////这里不打印,否则ZIGBEE检测到{ckxxxx}就认为是命令
serialbuff[seriali]=serialData;////保存到数组
seriali++;////数组长度+1
if(serialData=='}' || seriali>=80)//如果发现}而说明命令结束(并少于80个字符,太长会出错)
{
isSerial=true;
break;
}
}
//开始处理{ckxxxxx}字符,如POST上传到web服务器
if(isSerial)
{
serialnowlast = millis(); //更新当前时间,不然5秒就超时了
//Serial.println(serialbuff);
char body[81]={0};
get_html_body(serialbuff,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
//Serial.println(body);
Serial.println("-------------------");
//如果命令格式真确则POST到web服务器了
if(strstr(body,"{ck") && strstr(body,"}") )
{
last_http = millis();
ishttpget=true;
timer = millis();
Serial.println("n>>> POST");
//static char buf[81]={0};
//sprintf(buf,"%s",body);
client_post(server,APIKEY,body);//POST到网址,APIKEY,字符
my_result_cb();//接收web服务器返回的字符
}
memset(serialbuff, 0, 80);//清空字符
seriali=0;//字符长度为0
return;
}
}
//delay(200);
//更新web服务器命令的状态(比如发送成功还是失败还是异常等,NRF24l01用到,ZIGBEE不用这里而是直接发送{ck00xxxxxxupdate}命令就行)
if( isUpdate )
{
isUpdate=false;
last_http = millis();
ishttpget=true;
Serial.println("n>>> UPDATE");
static char buf[20]={0};
sprintf(buf,"%s",updateData);
//Serial.println(buf);
client_post(server,APIKEY,buf);//POST到网址,APIKEY,字符
my_result_cb();//接收web服务器返回的字符
isUpdate=false;
return;
}
//每2秒钟查看web服务器是有命令数据
unsigned long now = millis();
if(now - last_http >= 2000)
{
if(!ishttpget || (now - last_http) >= 20000)//20秒超时会执行,为了防卡死问题
{
last_http = millis();
ishttpget=true;
Serial.println("n>>> REQ");
static char buf[20]={0};
sprintf(buf,"{ck001000000000}"); //这个字符串代表获取新命令数据
client_post(server,APIKEY,buf);//POST到网址,APIKEY,字符
my_result_cb();//接收web服务器返回的字符
timer = millis();
}
}
}
//接收web服务器返回的字符
static void my_result_cb(){
char eth_buffer[350];
timer=millis();
while ((!client.available()) && (millis()-timer)<1000);
if (client.available()) {
for(int j=0;client.available()>0;j++)
{
char c = client.read();
eth_buffer[j]=c;
Serial.print(c);
}
client.stop();
}
Serial.println();
char body[81]={0};
get_html_body(eth_buffer,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
//Serial.println(body);
sendChannel=get_channel(body);//获取是哪个sid,这是m.znck007.com手机客服端里的sid
// //如果使用NRF24l01,请启动这里
// if( sendChannel>0 )
// {
// networkSend.begin(/*channel*/ sendChannel, /*node address*/ other_node);
//
// networkSend.update();
// Serial.println("");
// Serial.print("Sending...");
// if(sendCount>1000000) sendCount=0;
// payload_t payload = { sendChannel, sendCount++, "{ck000000000000}" };//millis()
// sprintf(payload.sendchar,"%s",body);
// RF24NetworkHeader header(/*to node*/ this_node);
// bool ok = networkSend.write(header,&payload,sizeof(payload));
// if (ok)
// {
// Serial.println("ok.");
//
// isUpdate=true;
// char front[10]={0};
// memcpy(front,body,9);
// sprintf(updateData,"%supdate}",front);
// Serial.println(updateData);
//
// }
// else
// {
// Serial.println("failed.");
// }
// }
ishttpget=false;
last_http = millis();
networkSend.begin(/*channel*/ sid, /*node address*/ this_node);
networkSend.update();
}
//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式
void get_html_body(char *p,char *s){
char rechar[81]={0};
int bufi=0;
bool isend=false;
int charnum=0;
for(bufi=0;bufi<strlen(p);bufi++){
//Serial.print(p[bufi]);
if(p[bufi]=='{'){
isend=true;
}
if(p[bufi]=='}' && isend==true){
isend=false;
rechar[charnum]=p[bufi];
break;
}
if(isend){
if(charnum<80)
{
rechar[charnum]=p[bufi];//Serial.print(rechar[charnum]);
charnum++;
}
}
}
Serial.println("");
//memcpy(s,rechar,17);
sprintf(s,"%s",rechar);
}
//获取是哪个sid,这是m.znck007.com手机客服端里的sid
int get_channel(char *buff){
if( strstr(buff,"{ck") && strstr(buff,"}") && strlen(buff)>10)
{
char charChannel[4]={0};
memcpy(charChannel,buff+3,3);
Serial.println(charChannel);
int intChannel=atoi(charChannel);
Serial.println(intChannel);
return intChannel;
}
else
{
return 0;
}
}
//W5100芯片POST字符数据到web服务器
int client_post(char *server, char *apikey, char *buf){
if (client.connect(server, 80))
{
Serial.println("connecting...");
// send the HTTP PUT request:
client.print("POST /index.php");
client.println(" HTTP/1.1");
client.println("Host: api.znck007.com");
client.print("apikey: ");
client.println(APIKEY);
client.print("Accept: *");
client.print("/");
client.println("*");
client.print("Content-Length: ");
// calculate the length of the sensor reading in bytes:
// 8 bytes for {"value":} + number of digits of the data:
size_t thisLength = strlen(buf);
client.println(thisLength);
client.println("Content-Type: application/x-www-form-urlencoded");
client.println("Connection: close");
client.println();
client.println(buf);
client.println();
}
else
{
// kf you didn't get a connection to the server:
Serial.println("connection failed");
Serial.println();
Serial.println("disconnecting.");
client.stop();
}
}
四、插上网线,打开串口就可以测试联网是否成功了!
第二部份:刷zigbee模块代码
一、将zigbee模块插到zigbee开发板上
二、连上SMARTRF04EB下载器。
将一边有凸出来的一端与(VDD、RES、NC、DC、GND的NC对应就正确了!
三、安装SMARTRF04EB驱动
https://pan.baidu.com/s/1dDH1ZX3(安装SmartRFStudio后里面包含有驱动)
提示:如果刷不成功,点击一下SMARTRF04EB上的RESET(凹进去就用笔撮)。
四、安装IAR 8.1,软件比较大,安装后看说明破解就好。
https://pan.baidu.com/s/1c0b69Ra(下载解压里面有安装说明)
五、下载zigbee自组网代码。
https://pan.baidu.com/s/1COxT8(最新ZStack-CC2530-2.5.1自组网代码,已经写好了按键、LED灯功能)
六、点击编译并下载。
七、插个LED到zigbee开发板的P1.0和-。
八、安到arduino板上。
第三步:使用手机测试
一、手机打开m.znck007.com手机控制端。
二、新建一个开关。
三、点击开关,如果发现LED灯闪,说明《网关工作正常了》!
OK,《网关》部份已经搞定了,下期我们就来上《温湿传感器》《Zigbee插座》《红外控制》!
因为我们还未使用Wifi,所以都需要与《网关》交互数据哦!
等我们Wifi产品出来就可以单独使用了!