一、前言
本人最近參加的項目需要使用到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模塊的庫,使用起來能相對的方便不少。不過我也得學不少的東西。