Arduino 使用 BC26/BC35 连接至阿里云平台
一、前言
本人最近参加的项目需要使用到NB-IoT模块,在网上寻找了一圈之后,发现Arduino常用的NB-IoT模块如下:
这两个模块均来自DFRobot,还有一些独立的模块。网上有关于这些通信模块的资料,大多数都是跟Arduino UNO或者STM32做的调试,没有见过有人使用Arduino Mega 2560与这些模块连接。
因为本次的项目需要使用到非常多的针脚,UNO的针脚数无法满足需求,而Mac电脑没办法对32芯片进行烧写,故只能选择Mega2560。
这就有了一个新的问题,模块的兼容性能否满足需求?
二、开始调试前的准备工作
1.通信模块的选择与软件版本
本次选择的模块是BC260Y
和BC35
软件版本使用的是
2.固件的烧录
因为原厂的固件是不支持MQTT协议的,这块需要到手后专门烧录支持MQTT的AT固件,具体的烧录办法需要向商家询问,由于固件和参考资料属于官方的限制性文档,故在这里不再公布。
只是烧录时有几个要点需要注意:
1)烧录软件尽量放在系统的根目录,且路径上不要出现中文或者空格,因为会增加烧录失败的可能性;
2)要烧录的固件的文件层次不要太深,尽量放在系统根目录下,且路径上不要出现中文或者空格,同样也会增加烧录失败的风险;、
3)使用的USB转TTL下载器一定要在电脑上装驱动,例如我的USB TTL下载器是CH340C的芯片,那么我就需要在电脑上安装对应芯片的驱动程序;
PS:本人烧录固件的前几次都是因为这样的原因而失败的,还有中间需要手动复位,就是说RESET
针脚需要手动短暂接地。
3.调试前需要一个干净的桌面
这一点很重要很重要很重要!!!!!!!!!!!!!!!!!!!!
本人在调试的时候在这方面刚刚吃过亏,一定要有一个整洁的桌面。
因为一个非常离谱的错误导致一下午都耗在调试上了。
起因是这样的,在调试程序的时候,突然就跑通了一次,然后就再没跑通了,无论怎样改程序、改接线,都没用,单独测2560和通信模块都没问题,合在了一起就不行,并且在这过程中还排除了库文件不兼容的问题。那么问题就出在了模块与2560的接线上了,因为我测试的时候,因为杜邦线太长了,就团成了一团,并且线的周围有一个扬声器和一团高频信号线和一团交流电线。直到我清理了一下桌面,顺直了杜邦线之后,突然程序就再没报过错了。说明了这些环境对信号的传输造成了影响,估计是信号串扰吧。
图片中可以清晰的看到有一根HDMI线、一根雷电3的线、两根交流电供电线、若干USB数据线,左边和右边还有扬声器。长出来的杜邦线就被我团成了一团放在了这堆线上面(类似的场景,我没拍,就拿这张图还原个情景再现)然后调试就出Bug了。
所以调试前一定要有一个干净整洁的桌面!!!!!
三、开始调试硬件
直接上程序,这个程序是店家提供的,我们来做个逐步的分析
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
DynamicJsonDocument json(200);
SoftwareSerial mySerial(50,52) ;//RX TX
void CommandtoNBIOT (String cmd, char *res)
{
while (1)
{
mySerial.println(cmd);
delay(300);
while (mySerial.available() > 0)
{
if (mySerial.find(res))
{
digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
digitalWrite(7, LOW); // turn the LED off by making the voltage LOW
delay(100);
Serial.println(res);
return;
}
else
{
Serial.print(cmd);
Serial.println(" Return ERROR!");
}
}
delay(200);
}
}
void MQTT_PubData(void)//发布数据到平台
{ //"/sys/a1qmGxDM8cd/mzhtest001/thing/event/property/post","{"id":"26","version":"1.0","params":{"CurrentTemperature":{"value":23},"RelativeHumidity":{"value":58}},"method":"thing.event.property.post"}"
char sendjson[] = "{\"id\":\"26\",\"version\":\"1.0\",\"sys\":{\"ack\":0},\"params\":{\"CurrentTemperature\":{\"value\":50},\"CurrentHumidity\":{\"value\":10}},\"method\":\"thing.event.property.post\"}";
char T_json[200];
sprintf(T_json, sendjson); //,humidata
mySerial.println("AT+QMTPUB=0,0,0,0,\"/sys/gbruRYswLWR/WEATHER/thing/event/property/post\""); //send message,主题更改
delay(100);
mySerial.println(T_json);
mySerial.write(0x1A);
delay(300);
// wait for a second
while (mySerial.available() > 0)
{
// char inByte = mySerial.read();
// Serial.print(inByte);
if (mySerial.find("+QMTPUB: 0,0,0"))
{
Serial.println("+QMTPUB: 0,0,0");
break;
}
}
}
void BC260Y_init(void)//初始化MQTT连接
{
Serial.println("1");
// prints title with ending line break
CommandtoNBIOT("AT", "OK");
mySerial.println("ATE0&W");//关闭回显
delay(300);
CommandtoNBIOT("AT+CPIN?", "+CPIN: READY"); //返+CPIN:READY,表明识别到卡了
Serial.println("2");
CommandtoNBIOT("AT+CGATT?", "+CGATT: 1"); //返+CGACT: 1,就能正常工作了
Serial.println("3");
mySerial.println("AT+QMTCLOSE=0");//关闭上一次socekt连接
delay(300);
mySerial.println("at+qmtcfg=\"aliauth\",0, \"gbruRYswLWR\",\"WEATHER\",\"d9661e128b5590cf5b7f880d991c7f7e\"");//配置三元素
delay(300);
CommandtoNBIOT("AT+QMTOPEN=0,\"iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883", "+QMTOPEN: 0,0"); //建立服务器的IP和端口连接
delay(300);
CommandtoNBIOT("AT+QMTCONN=0,\"WEATHER\"", "+QMTCONN: 0,0,0"); //建立服务器的IP和端口连接
delay(300);
}
void setup() {
// put your setup code here, to run once:
// initialize digital pin 13 as an output.
pinMode(7, OUTPUT);
Serial.begin(9600); //
mySerial.begin(9600);
delay(2000);
BC260Y_init();
}
void loop() {
// put your main code here, to run repeatedly:
MQTT_PubData();//发布数据
Serial.println("Data_Pub_Success");
delay(4000);
}
首先来说第一部分,定一个软串口
SoftwareSerial mySerial(50,52) ;//RX TX
我个人更建议使用如下的方式
SoftwareSerial mySerial = SoftwareSerial(50,52) ;//RX TX
这里定义了50号数字口是RX,52号数字口是TX
接线的方法如下:
BC260/BC35 Arduino
TX0 ------------------> D50
RX0 ------------------> D52
GND ------------------> GND
VIN ------------------> 5 V
接着让软串口在9600
波特率上运行着
void setup() {
pinMode(7, OUTPUT); //我在7针脚上接了一个灯
Serial.begin(9600); //让串口在9600波特率上运行
mySerial.begin(9600); //让软串口在9600波特率上运行
delay(2000);
BC260Y_init(); //初始化BC260/BC35
}
这段程序展示了如何将AT指令发送到通信模块上
void CommandtoNBIOT (String cmd, char *res)
{
while (1)
{
mySerial.println(cmd);
delay(300);
while (mySerial.available() > 0)
{
if (mySerial.find(res))
{
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(100);
Serial.println(res);
return;
}
else
{
Serial.print(cmd);
Serial.println(" Return ERROR!");
}
}
delay(200);
}
}
使用mySerial.println(cmd)
发送AT指令。切记,必须使用println
来发送,若没有换行符,通信模块不执行该指令。
等待一段时间后用find
在通信模块串口返回的值中寻找有没有我要的返回值。
例如,我输入AT
后应该返回OK
,那么里面的 cmd 对应 AT,res 对应 OK。
若没有得到想要的返回值,该模块会一直循环发送指令。
初始部分代码如下:
void BC260Y_init(void)//初始化MQTT连接
{
Serial.println("1");
// prints title with ending line break
CommandtoNBIOT("AT", "OK");
mySerial.println("ATE0&W");//关闭回显
delay(300);
CommandtoNBIOT("AT+CPIN?", "+CPIN: READY"); //返+CPIN:READY,表明识别到卡了
Serial.println("2");
CommandtoNBIOT("AT+CGATT?", "+CGATT: 1"); //返+CGACT: 1,就能正常工作了
Serial.println("3");
mySerial.println("AT+QMTCLOSE=0");//关闭上一次socekt连接
delay(300);
mySerial.println("at+qmtcfg=\"aliauth\",0, \"${ProductKey}\",\"${deviceName}\",\"${DeviceSecret}\"");//配置三元素
delay(300);
CommandtoNBIOT("AT+QMTOPEN=0,\"iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883", "+QMTOPEN: 0,0"); //建立服务器的IP和端口连接
delay(300);
CommandtoNBIOT("AT+QMTCONN=0,\"${deviceName}\"", "+QMTCONN: 0,0,0"); //建立服务器的IP和端口连接
delay(300);
}
数据发送部分的代码参考
void MQTT_PubData(void)//发布数据到平台
{
char sendjson[] = "{\"id\":\"26\",\"version\":\"1.0\",\"sys\":{\"ack\":0},\"params\":{\"CurrentTemperature\":{\"value\":50},\"CurrentHumidity\":{\"value\":10}},\"method\":\"thing.event.property.post\"}";
char T_json[200];
sprintf(T_json, sendjson); //,humidata
mySerial.println("AT+QMTPUB=0,0,0,0,\"/sys/${ProductKey}/${deviceName}/thing/event/property/post\""); //send message,主题更改
//具体的请参考阿里云的topic相关文档
delay(100);
mySerial.println(T_json);
mySerial.write(0x1A);
delay(300);
// wait for a second
while (mySerial.available() > 0)
{
// char inByte = mySerial.read();
// Serial.print(inByte);
if (mySerial.find("+QMTPUB: 0,0,0"))
{
Serial.println("+QMTPUB: 0,0,0");
break;
}
}
}
那么如何快速判断模块是否能够使用呢?
#include <SoftwareSerial.h>
SoftwareSerial bcserial = SoftwareSerial(50,52); //rx tx
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT);
Serial.begin(9600);
bcserial.begin(9600);
delay(100);
while (1)
{
Serial.print("AT\r\n");
bcserial.println("AT");
delay(300);
Serial.println(bcserial.read());
while (bcserial.available() > 0)
{
if (bcserial.find("OK"))
{
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(100);
Serial.println('OK');
return;
}
else
{
Serial.print("AT");
Serial.println(" Return ERROR!");
}
}
delay(200);
}
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("OKKKKKK");
}
如果返回的像是这样的信息,就说明该模块与Arduino之间连接良好
四、阿里云平台的设置
首先得要开通阿里云的物联网平台,测试的话就使用公共实例即可
1.添加产品并添加功能
在左边的设备管理里面的产品,创建产品:
产品名称自定
点击 查看 之后选择功能定义然后点击添加自定义功能(我这个是已经添加过并发布的了
)
然后点击发布上线即可。
2.添加设备
点击设备管理,然后点击添加设备,出现如下的画面,设备名字自己定义即可
然后将设备的三要素填写的Arduino的程序中的对应位置上,然后烧录进Arduino,等待设备的激活连接。
激活成功之后在物理型数据里就能看到刚刚添加的功能的数据了。
五、小结
第一次折腾NB-IoT,踩了好些的坑,更多的坑则是让我的搭档踩了(我俩都第一次接触这个)。
把这个发出来仅仅是记录了一下能成功运行的整个流程。
Arduino的程序在使用起来还是过于的麻烦,后续有计划打算封装一个兼容BC260Y和BC35 NB-IoT模块的库,使用起来能相对的方便不少。不过我也得学不少的东西。