CAT LoRa Starter Kit ตอนที่ 2 การรับและส่งข้อมูลไปยัง LoRa IoT by CAT (with AcSIP S76S Commands)

ในบทความนี้เราจะมาดูวิธีการส่งข้อมูลขึ้นไปยัง CAT LoRaWAN กันครับ โดยบอร์ดตัวนี้จะใช้ชิป AcSIP S76S เราสามารถควบคุมได้โดยการส่งคำสั่งผ่าน UART (Universal Asynchronous Receiver Transmitter) ที่เป็นการสื่อสารอนุกรมแบบ Asynchronous ทำให้สามารถรับและส่งข้อมูลได้ในเวลาเดียวกันแบบ Full Duplex โดยที่คำสั่งทั้งหมดที่เราสามารถใช้งานได้สามารถดาวน์โหลดได้ตามลิ้งด้านล่างนี้เลยครับ

จะเห็นได้ว่ามีคำสั่งมากมายให้เราเลือกใช้งาน แต่ในที่นี้เราจะใช้คำสั่งที่จำเป็นต้องใช้เท่านั้นนะครับ โดยคำสั่งที่ใช้งานมีดังนี้

  1. mac set_ch_freq
  2. mac set_rx2
  3. mac save
  4. mac set_class
  5. mac join abp
  6. mac set_deveui
  7. mac set_devaddr
  8. mac set_nwkskey
  9. mac set_appskey

ในที่นี้เราจะเขียนโปรแกรมส่งข้อมูลขึ้น CAT LoRaWAN โดยส่ง “0123456789ABCDEF” ขึ้นสู่ Network Server โดยโค๊ดทั้งหมดมีดังนี้

#include "Arduino.h"
#include "wiring_private.h"
#include <Wire.h>
Uart Serial2(&sercom1, 11, 10, SERCOM_RX_PAD_0, UART_TX_PAD_2);unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 20000;
//LoRa Configuration;
String DEV_EUI = "????????????????";
String DEV_ADDR = "????????";
String NWKS_KEY = "????????????????????????????????";
String APPS_KEY = "????????????????????????????????";
//LoRa Send Data
uint8_t port = 1;
String payload = "0123456789ABCDEF";
void SERCOM1_Handler(void){
Serial2.IrqHandler();
}
void Serial2_String_Write(const char *s){
while (*s)
{
Serial2.write(*s++);
}
}
void Set_LoraConfig(void){
String str1 = "";
//********************
Serial2_String_Write("mac set_ch_freq 0 923200000");//0
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 0");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 1 923400000");//1
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 1");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 2 922000000");//2
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 2");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 3 922200000");//3
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 3");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 4 922400000");//4
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 4");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 5 922600000");//5
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 5");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 6 922800000");//6
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 6");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 7 923000000");//7
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 7");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_rx2 2 923200000");//8
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_rx2 2");
Serial.println(str1);
//********************
Serial2_String_Write("mac save");//8
str1 = "";
delay(3000);
str1 = Serial2.readString();
Serial.print("mac save");
Serial.println(str1);
}
void Set_LoraConfigABP_A(void){
String str1 = "";
String cmdTemp = "";
//********************
Serial2_String_Write("mac set_class A");
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_class A");
Serial.println(str1);
//********************
cmdTemp = String("mac set_deveui ") + DEV_EUI;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_deveui");
Serial.println(str1);
//********************
cmdTemp = String("mac set_devaddr ") + DEV_ADDR;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_devaddr");
Serial.println(str1);
//********************
cmdTemp = String("mac set_nwkskey ") + NWKS_KEY;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_nwkskey");
Serial.println(str1);
//********************
cmdTemp = String("mac set_appskey ") + APPS_KEY;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_appskey");
Serial.println(str1);
//********************
Serial2_String_Write("mac save");
str1 = "";
delay(3000);
str1 = Serial2.readString();
Serial.print("mac save");
Serial.println(str1);
//********************
Serial2_String_Write("mac join abp");
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("mac join abp");
Serial.println(str1);
}
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
pinPeripheral(10, PIO_SERCOM);
pinPeripheral(11, PIO_SERCOM);
delay(5000);
if (Serial2.available()){
Serial.print(Serial2.readString());
}
delay(1000);
Set_LoraConfig();
Set_LoraConfigABP_A(); delay(250);
Wire.begin();
String str1 = "";
str1 = Serial2.readString();
Serial.println(str1);
startMillis = millis();
delay(1000);
Serial.println("LoRa Starter Kit GRAVITECH");
}
void loop() {
String str4 = "";
currentMillis = millis();
// SEND INTERVAL 20 SECOND --> EDIT PARAMETER preiod TO CHANGE TIME INTERVAL LINE 185
if (currentMillis - startMillis >= period){
// SEND UPLINK DATA
String commandSender = String("mac tx ucnf ") + String(port) + String(" ") + payload;
Serial2_String_Write(commandSender.c_str());
startMillis = currentMillis;
}
// COUNT FOR SEND UPLINK
if ((currentMillis - startMillis) / 1000 > 0) {
str4 = Serial2.readString();
if (str4 != "") {
Serial.println(str4);
}
}
}

อธิบายโค๊ด

เปิดการใช้งาน Uart เพื่อเชื่อมต่อกับชิป AcSIP S76S

Uart Serial2(&sercom1, 11, 10, SERCOM_RX_PAD_0, UART_TX_PAD_2);//และเรียกใช้โดย Serial2.begin(115200); ใน setup function

ตั้งค่าความถึ่และ Chanel ที่ใช้สำหรับการเชื่อมต่อกับ CAT LoRaWAN

void Set_LoraConfig(void){
String str1 = "";
//********************
Serial2_String_Write("mac set_ch_freq 0 923200000");//0
str1 = "";
delay(100);
str1 = Serial2.readString();
Serial.print("set_ch_freq 0");
Serial.println(str1);
//********************
Serial2_String_Write("mac set_ch_freq 1 923400000");//1
...
//********************
Serial2_String_Write("mac set_ch_freq 2 922000000");//2
...
//********************
Serial2_String_Write("mac set_ch_freq 3 922200000");//3
...
//********************
Serial2_String_Write("mac set_ch_freq 4 922400000");//4
...
//********************
Serial2_String_Write("mac set_ch_freq 5 922600000");//5
...
//********************
Serial2_String_Write("mac set_ch_freq 6 922800000");//6
...
//********************
Serial2_String_Write("mac set_ch_freq 7 923000000");//7
...
//********************
Serial2_String_Write("mac set_rx2 2 923200000");
...
//********************
Serial2_String_Write("mac save");
...
}
//และเรียกใช้โดย Set_LoraConfig(); ใน setup function

กำหนดวิธีเชื่อมต่อเป็น ABP แบบ Class A โดยระบุข้อมูลที่ CAT ออกให้เพื่อใช้ในการเชื่อมต่อมี 4 อย่างดังนี้
3.1 Device EUI (deveui)
3.2 Device Address (devaddr)
3.3 Network Security Key (nwkskey)
3.4 Application Security Key (appskey)

//LoRa Configuration;
String DEV_EUI = "????????????????";
String DEV_ADDR = "????????";
String NWKS_KEY = "????????????????????????????????";
String APPS_KEY = "????????????????????????????????";
void Set_LoraConfigABP_A(void)
{
String str1 = "";
String cmdTemp = "";
//********************
Serial2_String_Write("mac set_class A");
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_class A");
Serial.println(str1);
//********************
cmdTemp = String("mac set_deveui ") + DEV_EUI;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_deveui");
Serial.println(str1);
//********************
cmdTemp = String("mac set_devaddr ") + DEV_ADDR;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_devaddr");
Serial.println(str1);
//********************
cmdTemp = String("mac set_nwkskey ") + NWKS_KEY;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_nwkskey");
Serial.println(str1);
//********************
cmdTemp = String("mac set_appskey ") + APPS_KEY;
Serial2_String_Write(cmdTemp.c_str());
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("set_appskey");
Serial.println(str1);
//********************
Serial2_String_Write("mac save");
str1 = "";
delay(3000);
str1 = Serial2.readString();
Serial.print("mac save");
Serial.println(str1);
//********************
Serial2_String_Write("mac join abp");
str1 = "";
delay(250);
str1 = Serial2.readString();
Serial.print("mac join abp");
Serial.println(str1);
}

//และเรียกใช้โดย Set_LoraConfig(); ใน setup function

ถ้าไม่มีอะไรผิดพลาด เมื่อเรา upload และ run โปรแกรม เราจะพบข้อความใน Terminal แสดงดังนี้

  1. ในตอน Setup function จะปรากฏข้อความดังภาพ
public setup(){
...
}

2. ในตอน Loop Function จะแสดงข้อความดังภาพ เนื่องจากเราวนลูปให้ส่งข้อความไป LoraWAN ทุก ๆ 20 วินาที

public loop(){
...
}

3. ทดลองส่งข้อมูลมายัง Node ผ่านเว็บของ CATTELECOM

  • port = 9
  • payload = 090807060504030201

จากผลของ Terminal จะเห็นข้อความ

>> Ok คือการตอบกลับเมื่อส่งคำสั่งไปยัง AcSIP S76S สำเร็จ

>> tx_ok คือการตอบกลับเมื่อส่งคำสั่ง mac tx ucnf FFFF ไปยัง AcSIP S76S

>> mac rx คือการรับข้อมูลที่ส่งมาจาก Network Server

จากที่กล่าวมาข้อมูลอยู่ในรูปที่เราไม่สามารถนำมาใช้ได้เลยทันที เราจำเป็นต้องทำการตัดเอาเฉพาะข้อมูลที่ต้องการมาใช้เท่านั้นก่อน

ในการส่งข้อมูลนั้นเราต้องการ 2 สิ่งคือ

  1. Port ที่จะส่ง — เลขจำนวนเต็มแบบไม่มีเครื่องหมาย
  2. ข้อมูลที่จะส่ง — โดยข้อมูลที่จะส่งต้องอยู่ในรูปแบบของเลขฐาน 16 (0–9,A-F) และเป็นจำนวนคู่ เท่านั้น
uint8_t port = 1;
String payload = "0123456789ABCDEF";

โดยการส่งข้อมูลจะทำการส่งแบบอนุกรม เขียนไปยัง Serial2 ในรูปแบบคำสั่งของชิบ AcSIP S76S

// ประกอบเป็นคำสั่งสำหรับส่งข้อมูลในรูปแบบ "mac tx ucnf 1 0123456789ABCDEF"
String commandSender = String("mac tx ucnf ") + String(port) + String(" ") + payload;
//เขียนข้อมูลไปยัง Serial2
Serial2_String_Write(commandSender.c_str());

และใน LoraWAN มีกฏห้ามส่งข้อมูลต่อเนื่องติด ๆ กัน ต้องส่งห่างกันอย่างน้อย 20 วินาที เราจึงต้องเขียนควบคุมเวลาการส่งให้ส่งออกทุก ๆ 20 วินาทีด้วย

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 20000; //ตัวแปรกำหนดไว้ที่ 20 วินาที
///////////////////////////////////
public loop(){
...
currentMillis = millis();
if (currentMillis - startMillis >= period){

// SEND UPLINK DATA
...
startMillis = currentMillis;
}

...
}

เราจะเขียนรับข้อมูลไว้ในฟังก์ชั่น loop() โดยจะหน่วงเวลาไว้ที่ 1 วินาที ใช้ฟังก์ชั่น readString() ของ Serial2 แล้วแสดงออกมาทาง Terminal

public loop(){
...
if ((currentMillis - startMillis) / 1000 > 0) {
str4 = Serial2.readString();
if (str4 != "") {
Serial.println(str4);
}
}
...
}

ในบทความนี้ก็ขอจบไว้เพียงเท่านี้ครับ บทความหน้าเราจะมาเปลี่ยนให้มันเป็น Library พร้อมใช้งานกัน ชีวิตจะง่ายขึ้นเยอะ สวัสดีครับ