【NB-IoT】國產DSI2598開發板開箱評測

HowardWu發佈於2020-03-27 11:50:37

瀏覽46546

回覆0

最後編輯於2024-10-31 17:31:39

資料來源: https://makerpro.cc/2019/12/unboxing2-nb-iot-dsi2598/


作者:Victor Sue

物聯網在近幾年有爆發之勢,大量普及的集合了許多因素,包括:晶片模組成本、終端設備、網路普及、應用服務、軟體技術等日趨完善有關,物聯網有「最後一哩」的難題。雖然用來收集與分析資料的雲端基礎架構早已就緒,但仍需要可用來連結大量裝置接上網路、且兼具傳輸距離、低功耗與低成本特性的LPWAN(Low-Power Wide-Area Network,低功率廣域網路)。

因此LPWAN有數種規格互相競逐,例如Lora、Sigfox、窄頻物聯網(Narrow Band-IoT, NB-IoT)等,NB-IoT亦稱為LTE Cat. NB1,為架構在行動通訊網路上的低功率廣域網路技術。可以使終端設備簡單有效地連接行動通訊網路,資料傳輸時具備行動通訊等級加密的可靠度,適合處理少量、不頻繁的雙向數據。

主流LPWAN規格比較 (圖片來源:Google)

在感測器軟硬體方面,可以透過Arduino建構快速原型的製作,其為一個基於易於使用的硬體和軟體的開源電子架構,並可從簡單感測應用轉變為物聯網應用,可穿戴設備等嵌入式產品,而且所有Arduino都是完全開源的,開發者能夠獨立構建它們並最終使產品適應其特定需求。

鑒於Arduino和NB-IoT在物聯網產品開發上的優勢,資策會推出了結合兩者優勢的開源物聯網開發板 – DSI2598 NB-IOT開發板,使用國產晶片聯發科的NB-IoT MT2625模組,搭配Arduino原廠MCUATMEGA328P,為國內首款的Arduino NB-IoT開發板,輔以Arduino IDE為主要的程式開發環境,讓雛形打造簡單容易。

這次有幸受邀針對 DSI2598 NB-IoT 開發板做測試,並撰寫其測評文章,官方的作法很開放,完全不干涉我如何撰寫文章的內容,若您對於這片DSI2598 NB-IoT 開發板開發板有興趣,可透過這個網址進行申請(申請核准後將另行通知領取)。

DSI2598申請網址 (圖片來源:資策會)

規格介紹

DSI2598 NB-IoT 開發板是資策會為 Maker與新創推出的IoT開發板,也是國內第一款同時結合Arduino與NB-IOT的開發板,可善用Arduino豐富的生態系支援來快速建立概念驗證原型POC(Proof of Concept);其核心採用國產聯發科通訊晶片MT2625,完整支援NB-IoT R14的聯網易用性,以高整合度為大量物聯網設備提供兼具低功耗及成本效益的解決方案。

簡單地來說,DSI2598就是Arduino Nano加上NB-IoT的開箱即用開發板。話不多說,接下來讓我們來看看DSI2598的整體系統規格:

DSI 2598系統規格 (圖片來源:資策會)

DSI2598系統組成示意圖

首先,先從外觀看起,DSI2598分為一代和二代,主要差別為二代導入與Arduino Nano類似的設計,將燒錄程式用的USB to Serial內建到開發板內,大幅增加開發者的易用性,更容易將IoT的相關想法,透過DSI2598建立POC(Proof of Concept)來實際進行驗證。

DSI2598一代/二代/Arduino Nano外觀比較 (圖片來源:資策會)

DSI2598搭配Arduino原廠MCU ATMEGA328P,具備PWM、I2C、SPI、ADC、UART 等功能腳位位功能,可讓使用者套用各式Arduino程式庫,搭配各種外部感測器模組進行連接,來接收所需的環境感測數據。

第二代DSI 2598腳位說明(圖片來源:資策會)

透過Arduino讀取感測器資料,再透過NB-IoT的方式傳送至雲端主機,可以快速地完成一個簡易的資料收集點,搭配合適的物聯網雲端平台,導入AI(人工智慧)成為AIoT(人工智慧物聯網),以建立相關服務應用。

DSI2598 IOT應用架構 (圖片來源:資策會)

NB-IoT部分,DSI2598採用Quectel BC26 NB-IoT模組,BC26基於聯發科MT2625芯片平台研發,支持全球頻段(B1/B2/B3/B4/B5/B8/B12/B13/B17 /B18/B19/B20/B25/B26/B28/B66),客戶只需一顆模組,產品即可覆蓋全球需求。BC26具有超小體積,尺寸僅為17.7×15.8×2.0mm,能最大限度地滿足可穿戴設備、智能家居、安防、資產追踪、智能表計、便攜式健康監控儀器等緊湊型終端設備的需求。BC26還支持低供電電壓範圍(2.1V-3.63V),更適合NB-IoT技術的應用場景。

在設計方面,BC26採用LCC封裝,兼容移遠通信GSM/GPRS系列的M26模組,方便現有的2G客戶快速、靈活地切換至NB-IoT網絡。BC26易於針對各種不同的應用進行客製化,比如家庭自動化、雲信標(cloud beacon)、智慧型電錶及多項物聯網靜態或行動應用。以下為BC26模組外觀與硬體規格:

Quectel BC26外觀尺寸 (圖片來源:Quectel官網)

啟動吧~GO~

讓我們來實際測試DSI2598 NB-IoT開發板,首先安裝Arduino與相關驅動程式,以準備DSI2598的基本開發環境:

1. 安裝Arduino IDE,請到以下網址進行下載(選擇對應的作業系統)

https://www.arduino.cc/en/main/software

2. 安裝CH341SER驅動程式,請到以下網址進行下載

http://www.wch.cn/download/CH341SER_EXE.html

3. 開啟Arduino IDE

Arduino啟動圖示 (圖片來源:Victor Sue)

4. 開啟新專案 檔案->新增

Arduino開啟新專案 (圖片來源:Victor Sue)

5. 輸入以下的Blink程式碼,此段程式碼主要是對序列埠(Serial Port)輸出字串,來對板子進行基本的功能驗證,藉此確認Arduino開發環境與板子是否正確運行。

 

 

1

2

3

4

5

6

7

8

9

10

11

DSI2598-BLINK.ino

// the setup function runs once when you press reset or power the board

void setup() {

Serial.begin(9600);

}

 

// the loop function runs over and over again forever

void loop() {

Serial.println("Hello World~");

delay(1000);

}

 

6. 將DSI2598的USB接上PC

7. 設定開發板為Arduino Nano 工具->開發板

Arduino設定開發板 (圖片來源:Victor Sue)

8. 設定序列埠

Arduino設定序列埠 (圖片來源:Victor Sue)

9. 編譯並上傳

Arduino編譯並上傳 (圖片來源:Victor Sue)

10. 完成後,開啟 工具->序列埠監看視窗(Ctrl-Shift-M),設定9600 baud,會不斷印出”Hello World~”,代表Arduino正常運行,恭喜跨出成功的第一步。

DSI2598 Blink測試 (圖片來源:Victor Sue)

NB-IoT連線測試

確定開發環境與開發板正常運作後,下一步就是打通BC26的NB-IoT連線,Aarduino控制BC26模組的介面為UART,控制方法為AT指令,UART部分Arduino採用Softserial函式庫,可以將Arduino的其他腳位通過軟體模擬成額外的串口序列埠,SoftwareSerial類並非Arduino UNO核心類庫,因此使用前你需要先聲明包含SoftwareSerial.h,其中定義的成員函數與硬件串口類似,available()、begin()、read()、write()、print()、println()、peek() 等用法相同,SofrwareSerial 函式庫有以下已知的限制:

• 使用多個軟體序列埠,同時間只有一個可以接收資料
• 只有支援中斷的腳位可以可以作為 RX 信號腳位
• 鮑率(Baud Rate)最高支援到 19200 bps•

AT指令在當代手機通訊中起著重要的作用,能夠通過AT指令控制通訊裝置進行各種行為,包括撥叫號碼、簡訊、聯網等,一般拿到通訊模組的第一件事情,就是用輸入AT,模組若回應OK的話,則代表通訊模組已正常啟動並等待控制,AT指令分為以下三種基本格式:

1. 測試命令(Test Command):在AT指令後面加上“=?”即構成測試命令。例如“AT+CSCS=?”會列舉出所有支援的字符集
2. 讀取命令(Read Command):在AT指令後面加上“?”即構成讀取命令。例如“AT+CSCS?”會列舉出當前設定
3. 執行命令(Execute Command):一般而言在AT指令後加上“=”及命令引數即可。有些命令例如AT+CMGR命令沒有引數,直接就可以執行。

讓我們來透過NB-IoT實際連上網路吧~

1. DSI2598開發板裝上隨附的FPC天線

DSI2598安裝FPC天線 (圖片來源:Victor Sue)

2. DSI2598插入電信商的NB-IOT SIM卡,SIM卡卡槽在開發板背面

DSI2598開發板SIM卡卡槽 (圖片來源:Victor Sue)

3. DSI2598透過USB插上電腦
4. 下載程式碼https://t.ly/DKkB2
5. 開啟Arduino IDE
6. 選擇設定DSI2598的開發板(Arduino Nano)和序列埠號
7. 編譯並上傳
8. 開啟 工具->序列埠監看視窗(Ctrl-Shift-M),設定115200 baud

DSI2598 Arduino序列埠監看視窗設定 (圖片來源:Victor Sue)

9. 在下圖的輸入框內輸入以下的AT指令(藍字為輸入AT指令,綠字為模組輸出)

10. 確認NB-IoT成功上線且拿到IP,成功~ 具體AT命令請參考BC26官方網站(https://www.quectel.com/cn/product/BC26.htm 需註冊登入才能下載手冊)

 

DSI2598 NB-IoT成功上線拿到IP Address (圖片來源:Victor Sue)

上傳IDEAS Chain雲端測試

感測器、Arduino到 NB-IoT連網都OK了,接下來就是重頭戲,將資料打到雲端啦,資策會非常佛心,不僅僅提供高整合度的開發板,更提供了雲端平台 IDEAS Chain。IDEAS Chain 是什麼呢?它是資策會服創所開發之雲端數據平台,以多元服務的整合設計,讓新創團隊與開發者簡單、快速導入物聯網數據應用,降低 IoT 結合雲端服務建置門檻。話不多說,就讓我們到平台上註冊吧~

1. IDEAS Chain註冊:請先到登入 -> 沒有帳號?

https://www.ideaschain.com.tw/www/iot.html

IDEAS Chain建立帳號 (圖片來源:Victor Sue)

2. 建立帳號後會收到認證Mail,點擊確認後登入IDEAS Chain

IDEAS Chain登入 (圖片來源:Victor Sue)

3. 點擊新增專案,建立專案,填入專案名稱與專案描述

IDEAS Chain新增專案 (圖片來源:Victor Sue)

IDEAS Chain填入專案名稱與描述 (圖片來源:Victor Sue)

4. 專案建立成功,點擊專案新增裝置

IDEAS Chain專案建立成功 (圖片來源:Victor Sue)

5. 新增裝置與相關資訊

IDEAS Chain新增裝置 (圖片來源:Victor Sue)

 

IDEAS Chain新增裝置資訊 (圖片來源:Victor Sue)

6. 在裝置管理內新增感測器

IDEAS Chain裝置管理 (圖片來源:Victor Sue)

IDEAS Chain新增感測器 (圖片來源:Victor Sue)

7. 接下來就是重點了,Arduino程式碼BC26.h內有三個數值須根據剛才在IDEAS Chain新增的專案/裝置/感測器所產生的ID進行修改

那這三個數值分別要去哪找呢? 首先, AK金鑰在專案管理頁面上點擊編輯,跳轉後第一行的資訊即為AK金鑰:

IDEAS Chain專案管理-編輯 (圖片來源:Victor Sue)

 

IDEAS Chain AK金鑰 (圖片來源:Victor Sue)

DID為裝置管理的裝置編號(DID)

IDEAS Chain裝置編號(DID) (圖片來源:Victor Sue)

SID為點擊感測器上面的編輯按鈕,跳轉後第一行即為SID

IDEAS Chain感測器-編輯 (圖片來源:Victor Sue)

8. IDEAS Chain設定完成
9. DSI2598透過USB插上電腦
10. 開啟Arduino IDE
11. 輸入以下兩隻程式碼

DSI2598-ideaschain.ino

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

#include "BC26.h"

 

#define RED 11

#define GREEN 12

#define BLUE 13

 

void setup() {

// put your setup code here, to run once:

Serial.begin(115200);

mySerial.begin(9600);

pinInitial();

LED("red");

delay(500);

Serial.println("Boot BC26 ");

BC26_initail(); // 啟動與設定連線的伺服器

LED("green");

delay(2000);

LED("blue");

data_update(AK, DID, SID, String(reset_count));

delay(2000);

LED("green");

}

 

void loop() {

// put your main code here, to run repeatedly:

if(reset_count >= 3600){ // 30min後系統重開

resetFunc();

}

if(time_count >= 60){

LED("blue");

data_update(AK, DID, SID, String(reset_count));

time_count = 0;

}

LED("green");

delay(500);

time_count++;

reset_count++; // 系統重新啟動計時器累加

}

 

void pinInitial(){

pinMode(RED, OUTPUT);

pinMode(GREEN, OUTPUT);

pinMode(BLUE, OUTPUT);

digitalWrite(RED, LOW);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, LOW);

}

 

void LED(String string){

if(string == "red"){

digitalWrite(RED, HIGH);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, LOW);

// delay(1000);

}else if(string == "green"){

digitalWrite(RED, LOW);

digitalWrite(GREEN, HIGH);

digitalWrite(BLUE, LOW);

// delay(1000);

}else if(string == "blue"){

digitalWrite(RED, LOW);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, HIGH);

// delay(1000);

}else if(string == "none"){

digitalWrite(RED, LOW);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, LOW);

// delay(1000);

}else if(string == "yellow"){

digitalWrite(RED, HIGH);

digitalWrite(GREEN, HIGH);

digitalWrite(BLUE, LOW);

// delay(1000);

}else if(string == "purple"){

digitalWrite(RED, HIGH);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, HIGH);

// delay(1000);

}else if(string == "sky"){

digitalWrite(RED, LOW);

digitalWrite(GREEN, HIGH);

digitalWrite(BLUE, HIGH);

// delay(1000);

}else if(string == "white"){

digitalWrite(RED, HIGH);

digitalWrite(GREEN, HIGH);

digitalWrite(BLUE, HIGH);

// delay(1000);

}else if(string == "nocolor"){

digitalWrite(RED, LOW);

digitalWrite(GREEN, LOW);

digitalWrite(BLUE, LOW);

// delay(1000);

}

}

BC26.h

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

#include

SoftwareSerial mySerial(8, 9);

 

String AK = "xxxxxxxxxxxxxxxxxxxx"; // 平台的AK金鑰參數

String DID = "0150455698870876"; // 平台的裝置ID參數

String SID = "S000001"; // 平台的感測器ID參數

 

String data = ""; // 儲存來自BC26回覆的字串參數

String data_on = ""; // 擷取部分字串參數的儲存參數

int sta = 1; // 迴圈的status參數判斷

int time_count = 0;

int count = 0; // 副程式中來自BC26的回覆次數計數器

//int count1 = 0; // 副程式中的時間計數器

int band = 8; // 設定頻段(B8)

int IP_count1 = 0;

void(* resetFunc) (void) = 0; // 宣告系統重置參數

int reset_count = 0; // 系統重新啟動計時器宣告

String data_tcp_build = "AT+QSOC=1,1,1"; // 建立TCP通訊的AT指令

String tcpserver_connect = "AT+QSOCON=0,7789,\"150.117.122.166\"";

String noreply = "no reply, reset all";

 

void serial_read(){

while (mySerial.available()){ //Check if there is an available byte to read,

delay(10); //Delay added to make thing stable

char c = mySerial.read(); //Conduct a serial read

if (c == '\n') {break;} //Exit the loop when the "" is detected after the word

data += c; //Shorthand for data = data + c

}

 

if (data.length() > 0) { // 判斷data內有值在更換

data.trim();

delay(100);

Serial.println(data);

if(sta == 1){

count++;

}

if(sta == 1){

if(count >= 1){ // Turn on BC26 status

// Serial.println("Turn on BC26");

sta++;

count = 0;

}

}else if(sta == 2){

if(data == "OK"){ // 設置頻段

sta++;

}

}else if(sta == 3){ // wait for IP status

for(int i = 0; i < 3; i++){

data_on += data[i];

}

if(data_on == "+IP"){

sta++;

}else if(data_on =="+CG"){

sta++;

}

}else if(sta == 4){

for(int i = 0; i < 7; i++){ data_on += data[i]; } if(data_on == "+QSOC=0"){ // 開啟TCP通訊通道 sta++; } }else if(sta == 5){ if(data == "OK"){ // 連線至伺服器 sta++; } }else if(sta > 5){ // 傳輸資料與伺服器端訊息回傳

// +QSONMI

for(int i = 0; i < 8; i++){ data_on += data[i]; } if(data_on == "+QSONMI=" || data_on == "AT+QSOSE"){ sta++; }else if(data[0] == 'O' && data[1] == 'K'){ sta++; } } } data = ""; data_on = ""; } void BC26_reset(){ // reset BC26 mySerial.println("AT+QRST=1"); while (sta == 1) { // 等待模組訊息回覆 serial_read(); delay(1*1000); count++; if (count > 10) { // 超過10秒未有回覆,重新啟動系統

count = 0;

Serial.println(noreply);

resetFunc();

}

}

count = 0;

}

 

void ask_for_IP(){ // 查詢IP狀況

mySerial.println("AT+CGPADDR=1");

while (sta == 3) { // 等待模組訊息回覆

serial_read();

delay(1*1000);

count++;

if (count > 10) { // 每10秒問一次IP狀況

IP_count1++;

mySerial.println("AT+CGPADDR=1");

count = 0;

if(IP_count1 > 6){ // 一分鐘後仍沒找到IP,重新開機

Serial.println(noreply);

resetFunc();

}

}

}

count = 0;

IP_count1 = 0;

}

 

void set_band(int band){ // 設置頻段

String AT_band = "AT+QBAND=1,";

AT_band.concat(band);

mySerial.println(AT_band);

while (sta == 2) { // 等待模組訊息回覆

serial_read();

delay(1*1000);

count++;

if (count > 10) { // 超過10秒未有回覆,重新啟動系統

count = 0;

Serial.println(noreply);

resetFunc();

}

}

count = 0;

}

 

void build_TCP_connect(){ // 建立TCP連線通道

mySerial.println(data_tcp_build);

}

 

void connect_toserver(){ // 與伺服器連接

mySerial.println(tcpserver_connect);

}

 

String str2hex(String str){ // API字串轉hex格式function

String hex_string = "";

for(int i = 0; i < str.length(); i++){ hex_string += String(str[i], HEX); } return hex_string; } String api_string(String AK, String DID, String SID, String data){ String api_pass = "{\"a\":\""; api_pass.concat(AK); api_pass.concat("\",\"d\":\""); api_pass.concat(DID); api_pass.concat("\",\"s\":\""); api_pass.concat(SID); api_pass.concat("\",\"v\":\""); api_pass.concat(data); api_pass.concat("\"}"); Serial.print("api_pass: "); Serial.println(api_pass); return api_pass; } void reading(int sta_pre, int sta){ while(sta_pre == sta){ // 等待模組訊息回覆 serial_read(); delay(1*1000); break; count++; } if(count > 10){ // 超過10秒未有回覆,

count = 0;

Serial.println("no replay, send next data after 2 seconds");

delay(1*1000);

sta_pre++;

}

count = 0;

sta_pre = sta;

}

 

void data_update(String AK, String DID, String SID, String data){ // 資料上傳function

Serial.println("Sending data......");

int sta_pre = sta;

build_TCP_connect();

reading(sta_pre, sta);

 

connect_toserver();

reading(sta_pre, sta);

 

mySerial.print("AT+QSOSEND=0,"+String(api_string(AK, DID, SID, data).length()+2)+",");

mySerial.println(str2hex(api_string(AK, DID, SID, data))+"0d0a");

reading(sta_pre, sta);

 

mySerial.println("AT+QSODIS=0");

reading(sta_pre, sta);

 

mySerial.println("AT+QSOCL=0");

reading(sta_pre, sta);

}

 

void BC26_initail(){

BC26_reset();

delay(1*1000);

set_band(band);

delay(20*1000); // 等待20秒連線

ask_for_IP(); // 查詢IP狀況

delay(5*1000);

}

 

void long_delay(int hr, int minut, int sec){ // 設定delay時間長度

for(int i = 0; i < (hr*60*60 + minut*60 + sec); i++){

delay(1000);

}

}

 

12. 編譯並上傳
13. 到IDEAS Chain上的裝置管理即可觀看資料上傳的狀態,點擊黃色鈕可以查看資料上傳的紀錄

IDEAS Chain資料上傳的狀態 (圖片來源:Victor Sue)

IDEAS Chain資料上傳的紀錄 (圖片來源:Victor Sue)

結語

整體來說,DSI2598開發板硬體上具備高度的整合性,同時融入Arduino的易用性,與NB-IoT的低功號遠距連線,加以資策會服創所開發之IDEAS Chain雲端數據平台,提供從地到雲一條龍的全套服務,對於開發IoT專案的Maker與新創團隊,能夠以最快的速度,將創意發想轉化成POC進行驗證。

對於之後的量產設計,更提供完整的BOM與電路設計(請參考網址https://t.ly/XGYEV),並提供小型量產的媒合(請參考官網 https://www.ideas-hatch.com ),希望未來DSI2598的開發資源能夠整合到單一Github上,提供各方團隊開發各式IoT的應用與服務,也能讓世界看到台灣有如此優秀的開源硬體開發套件。