Mini LoRa WiFi & Serial Nano & RS 485

มาสรุปรวมโครงการ  mini LoRa-WiFi แบบสุดติ่งกันเลยครับ

บอร์ดนี้เป็น  บอร์ด  LoRa Node  ที่ในบอร์ดจะประกอบด้วย

  • Nano   โดยเราจะใช้ ์ Nano เป็นตัวอ่าน  Sensor DHT ทาง port D9,D10 และ มี Analog Sensor pH, DO ทำนองนี้
  • Heltec esp32   จะทำหน้าที่เป็นตัวรวบรวมสิ่งที่วัดได้จาก Nano ( ที่อ่านค่าผ่านทาง Serial)  และค่าที่อานจาก RS485  ก่อนที่จะต่อ String รวมกันแล้วส่งไปยัง  LoRaWiFI Gateway ของเราตามที่เสนอในตอนก่อน
    • จะเห็นว่า   heltec มีการสื่อสาร Serial ถึง  3 port   คือ  Serial ปกติสำหรับการ debug program , Serial1 (ขา 23,22)  สำหรับการอ่าน  modbus  และ Serial2 (ขา 17,13)  สำหรับการเชื่อมต่อกับ Nano (ขา D6,D5)
  • RS485  จะทำหน้าที่รองรับการอ่านจำพวก DO, EC, Power meter  ที่สามารถเชื่อมต่อได้สารพัด  ส่วนจะมากแค่ไหนก็อยู่ที่ heltec จะส่งออกไปได้แต่ไหน

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

มาลองดู โค้ดกันเลย

Heltec LoRa esp32

/*
  Code file name : MiniLoRa-Nano-Node-Dev-117 ...Trial Seria
  This is a simple example show the Heltec.LoRa sended data in OLED.

  The onboard OLED display is SSD1306 driver and I2C interface. In order to make the
  OLED correctly operation, you should output a high-low-high(1-0-1) signal by soft-
  ware to OLED's reset pin, the low-level signal at least 5ms.

  OLED pins to ESP32 GPIOs via this connecthin:
  OLED_SDA -- GPIO4
  OLED_SCL -- GPIO15
  OLED_RST -- GPIO16
  
  by Aaron.Lee from HelTec AutoMation, ChengDu, China
  成都惠利特自动化科技有限公司
  www.heltec.cn
  
  this project also realess in GitHub:
  https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
*/
#include "ModbusMaster.h" //https://github.com/4-20ma/ModbusMaster
/*!
  We're using a MAX485-compatible RS485 Transceiver.
  Rx/Tx is hooked up to the hardware serial port at 'Serial'.
  The Data Enable (DE) and Receiver Enable (RE) pins are hooked up as follows:
*/
#include <Arduino.h>
#include <Wire.h>  
#include <math.h>
#include <ArduinoJson.h>

#define RXX 17
#define TXX 13

#include <Adafruit_Sensor.h>

#include <DHT.h>  // กรณีนี้ต้องใช้คู่กันกับ  DHT_U.h
#include <DHT_U.h>

#define DHTPIN  12 // Pin which is connected to the DHT sensor.

//#define DHTTYPE   DHT22     // DHT 22 (AM2302)
#define DHTTYPE   DHT21     // DHT 21 (AM2301)

// See guide for details on sensor wiring and usage:
//   https://learn.adafruit.com/dht/overview

DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;

#define MAX485_RE_NEG  25 //D4 RS485 has a enable/disable pin to transmit or receive data. Arduino Digital Pin 2 = Rx/Tx 'Enable'; High to Transmit, Low to Receive
#define Slave_ID1    1
#define Slave_ID2    2
#define RX_PIN      22 //RX2 
#define TX_PIN      23  //TX2 working is 17 , 22 as well working

#include "heltec.h"
#include "images.h"

#define BAND    510E6  //you can set band here directly,e.g. 868E6,915E6

// instantiate ModbusMaster object
ModbusMaster modbus1;
ModbusMaster modbus2;
float res_dbl0;
float res_dbl1;
float res_dbl ;
unsigned int counter = 0;
String rssi = "RSSI --";
String packSize = "--";
String packet ;
String datasend ;
String datasend1 ;
String datasend2 ;
String data2 ;
String data3 ;
String data4 ;
String data5 ;
String data6 ;
String data7 ;
String data8 ;
String data9 ;
String a ;

float temp_0 = 0;
float humid_0 = 0;
float vHumidity = 0;
float vTemperature = 0;
String data1="177";
String cccode = "2036491";
long lastMillis = 0;
//===
void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, HIGH); //Switch to transmit data
}
void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, LOW); //Switch to receive data
}
//====
void logo()
{
  Heltec.display->clear();
  Heltec.display->drawXbm(0,5,logo_width,logo_height,logo_bits);
  Heltec.display->display();
}
void AM2301_setup() {
  Serial.begin(9600); 
  // Initialize device.
  dht.begin();
  Serial.println("DHTxx Unified Sensor Example");
  // Print temperature sensor details.
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Temperature");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" *C");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" *C");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" *C");  
  Serial.println("------------------------------------");
  // Print humidity sensor details.
  dht.humidity().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Humidity");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println("%");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println("%");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println("%");  
  Serial.println("------------------------------------");
  // Set delay between sensor readings based on sensor details.
  delayMS = sensor.min_delay / 1000;
}

void RS485_setup()
{
  pinMode(MAX485_RE_NEG, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, LOW);
  // Modbus communication runs at 9600 baud
  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); // serial can be no1 , no 2
  modbus1.begin(Slave_ID1, Serial1);
  modbus2.begin(Slave_ID2, Serial1);
  // Callbacks allow us to configure the RS485 transceiver correctly
  modbus1.preTransmission(preTransmission);
  modbus1.postTransmission(postTransmission);
  modbus2.preTransmission(preTransmission);
  modbus2.postTransmission(postTransmission);
  
}

void setup()
{
  //WIFI Kit series V1 not support Vext control
  Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.Heltec.Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/);
 
  Heltec.display->init();
  Heltec.display->flipScreenVertically();  
  Heltec.display->setFont(ArialMT_Plain_10);
  logo();
  delay(1500);
  Heltec.display->clear();
  
  Heltec.display->drawString(0, 0, "Heltec.LoRa Initial success!");
  Heltec.display->display();
  delay(1000);
  RS485_setup();
  //AM2301_setup(); 
  Serial2.begin(9600, SERIAL_8N1,17,13);
}

void loop()
{
  /*
  RS485_loop();
  datasend2 = String(res_dbl0)+","+String(res_dbl1)+","+String(45.00)+","+String(25.75)+","+String(100.05);
  datasend1 = String(cccode)+","+String(177)+","+String(res_dbl0)+","+String(res_dbl1);
  datasend = datasend1+","+datasend2;
  */
  Heltec.display->clear();
  Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
  Heltec.display->setFont(ArialMT_Plain_10);
  
  Heltec.display->drawString(0, 0, "GeoShrimp Data packet: ");
  //Heltec.display->drawString(0, 10, String(counter));
  Heltec.display->drawString(0,10, String(datasend1));
  Heltec.display->drawString(0,30, String(datasend2));
  Heltec.display->display();
  
  // send packet
  LoRa.beginPacket();
  
/*
 * LoRa.setTxPower(txPower,RFOUT_pin);
 * txPower -- 0 ~ 20
 * RFOUT_pin could be RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
 *   - RF_PACONFIG_PASELECT_PABOOST -- LoRa single output via PABOOST, maximum output 20dBm
 *   - RF_PACONFIG_PASELECT_RFO     -- LoRa single output via RFO_HF / RFO_LF, maximum output 14dBm
*/
/*
  LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
  LoRa.print(datasend);
  //LoRa.print(counter);
  LoRa.endPacket();
 */
  RS485_loop1();  
  delay(2000);
  RS485_loop2();
  delay(1000);
  //AM2301_loop();
  datasend2 = String(data4)+","+String(data5)+","+String(data6)+","+String(data7);
  datasend1 = String(cccode)+","+String(177)+","+String(data2)+","+String(data3);
  datasend = datasend1+","+datasend2;
  Serial.println(datasend);
 
  LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
  LoRa.print(datasend);
  //LoRa.print(counter);
  LoRa.endPacket();

  //delay(3000);                       // wait for a second
  serial_loop();

}

// RS485 loop
void RS485_loop1() 
{
  long currentMillis = millis();
  if (currentMillis - lastMillis > 1000) 
  {
    uint8_t result = modbus1.readHoldingRegisters(0x02, 2);
    
    if (getResultMsg(&modbus1, result)) 
    {
      Serial.println();
      res_dbl0 = modbus1.getResponseBuffer(0) / 10;
      String res = "Soil Humidity: " + String(res_dbl0) + " %\r\n";
      data2 = String(res_dbl0);
      res_dbl1 = modbus1.getResponseBuffer(1) / 10;
      data3 = String(res_dbl1);
      res += "Soil Temperature: " + String(res_dbl1) + " C";
      Serial.println(res);
    }
    lastMillis = currentMillis;
  }
}
void RS485_loop2() 
{
  long currentMillis = millis();
  if (currentMillis - lastMillis > 1000) 
  {
    uint8_t result = modbus2.readHoldingRegisters(0x08, 2);
    
    if (getResultMsg(&modbus2, result)) 
    {
      Serial.println();
      res_dbl0 = modbus2.getResponseBuffer(0) / 100;
      data4 = String(res_dbl0);
      String res = "Volatge 1 : " + String(res_dbl0) + " Vac\r\n";
      res_dbl1 = modbus2.getResponseBuffer(1) / 100;
      data5 = String(res_dbl1);
      res += "Voltage 2 : " + String(res_dbl1) + " Vac";
      Serial.println(res);
    }
    lastMillis = currentMillis;
  }
}
bool getResultMsg(ModbusMaster *node, uint8_t result) 
{
  String tmpstr2 = "\r\n";
  switch (result) 
  {
  case node->ku8MBSuccess:
    return true;
    break;
  case node->ku8MBIllegalFunction:
    tmpstr2 += "Illegal Function";
    break;
  case node->ku8MBIllegalDataAddress:
    tmpstr2 += "Illegal Data Address";
    break;
  case node->ku8MBIllegalDataValue:
    tmpstr2 += "Illegal Data Value";
    break;
  case node->ku8MBSlaveDeviceFailure:
    tmpstr2 += "Slave Device Failure";
    break;
  case node->ku8MBInvalidSlaveID:
    tmpstr2 += "Invalid Slave ID";
    break;
  case node->ku8MBInvalidFunction:
    tmpstr2 += "Invalid Function";
    break;
  case node->ku8MBResponseTimedOut:
    tmpstr2 += "Response Timed Out";
    break;
  case node->ku8MBInvalidCRC:
    tmpstr2 += "Invalid CRC";
    break;
  default:
    tmpstr2 += "Unknown error: " + String(result);
    break;
  }
  Serial.println(tmpstr2);
  return false;
}
void AM2301_loop() {
  // Delay between measurements.
  /*
  delay(delayMS);
  // Get temperature event and print its value.
  sensors_event_t event;  
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    Serial.println("Error reading temperature!");
  }
  else {
    Serial.print("Temperature AM2301 : ");
    Serial.print(event.temperature);
    Serial.println(" *C");
    temp_0 = event.temperature;
    data6 = String(temp_0);
  }
  // Get humidity event and print its value.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.println("Error reading humidity!");
  }
  else {
    Serial.print("Humidity AM2301 : ");
    Serial.print(event.relative_humidity);
    Serial.println("%");
    humid_0 = event.relative_humidity;
    data7 =String(humid_0);
  }
  */
     
}

void serial_loop()
{
Serial.println("Please wait Serial..");

  while (a == "") {
    Serial2.print("Input1"); // ส่งหัวข้อคำถาม ว่า Question1 ไปยัง Arduino
    a = Serial2.readString();  // อ่าน Serial และนำไปเก็บในตัวแปร A
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer1 ");Serial.println(a);
  data8 = String(a);
  delay(1000);
  a="";
  while (a == "") {
    Serial2.print("Input2"); // ส่งหัวข้อคำถาม ว่า Question1 ไปยัง Arduino
    a = Serial2.readString();  // อ่าน Serial และนำไปเก็บในตัวแปร A
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer2 ");Serial.println(a);
  data9=String(a);
  a="";
  while (a == "") {
    Serial2.print("Input3"); // ส่งหัวข้อคำถาม ว่า Question1 ไปยัง Arduino
    a = Serial2.readString();  // อ่าน Serial และนำไปเก็บในตัวแปร A
    delay(100);
    Serial.print(".");    
  }
  Serial.print(" Answer3 ");Serial.println(a);
  data6=String(a);
  a="";
  while (a == "") {
    Serial2.print("Input4"); // ส่งหัวข้อคำถาม ว่า Question1 ไปยัง Arduino
    a = Serial2.readString();  // อ่าน Serial และนำไปเก็บในตัวแปร A
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer4 ");Serial.println(a);
  data7 = String(a);
   
  
}

 

Arduino Nano

#include <EEPROM.h>
#include <SoftwareSerial.h>
SoftwareSerial chat(5, 6); // RX 11 , TX 10
////////  AM2302
#include <math.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>  // กรณีนี้ต้องใช้คู่กันกับ  DHT_U.h
#include <DHT_U.h>

#define DHTPIN 10 // Pin which is connected to the DHT sensor.

// Uncomment the type of sensor in use:
//#define DHTTYPE           DHT11     // DHT 11 
#define DHTTYPE           DHT22     // DHT 22 (AM2302)
//#define DHTTYPE           DHT21     // DHT 21 (AM2301)

DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
////////

int i;
int sensorValue;
float rainmm ;
float dustDensity = 35;
String response ="0";
String response_c = "0";
String a ;
float temp_0 = 0;
float tempF_0 = 0;
float humid_0 = 0;
float vHumidity = 0;
float vTemperature = 0;
String data1 ;
String data2 ; // standard
float data3 = 0; 
float data4 = 0;
float data5 = 0;
float data6 = 0;

float temperatureC = 0;
float temperatureF = 0;
int counter = 1;
int sentcount = 0;
//////////////////////////////
void AM2302_setup() {
  dht.begin();
  Serial.println("DHTxx Unified Sensor Example");
  // Print temperature sensor details.
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Temperature");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" *C");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" *C");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" *C");  
  Serial.println("------------------------------------");
  // Print humidity sensor details.
  dht.humidity().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Humidity");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println("%");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println("%");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println("%");  
  Serial.println("------------------------------------");
  // Set delay between sensor readings based on sensor details.
  delayMS = sensor.min_delay / 1000;
}


void setup()  {
  Serial.begin(9600);
  chat.begin(9600);
}

void loop() {
  AM2302_loop();
  input1_loop();
  //input2_loop();
  if (chat.readString()){
     // chat.print(1);
     if(chat.readString()== "Input1"){ //มีการถามคำถาม Question1 ส่งข้อมูลตัวแปร a ออกไป
      chat.print(String(sensorValue));
     }
     if(chat.readString()== "Input2"){ //มีการถามคำถาม Question2 ส่งข้อมูลตัวแปร b ออกไป
     chat.print(String(rainmm));
     }
     if(chat.readString()== "Input3"){ //มีการถามคำถาม Question1 ส่งข้อมูลตัวแปร a ออกไป
      chat.print(String(data3));
     }
     if(chat.readString()== "Input4"){ //มีการถามคำถาม Question2 ส่งข้อมูลตัวแปร b ออกไป
     chat.print(String(data4));
     }     
     Serial.print("Send = ");
     Serial.println(i);
  }

  i++;
  delay(1000);

}
void input1_loop() {  
  // read the value from the sensor:
  sensorValue = analogRead(A0);
  //Serial.print(" Analog read := ");Serial.println(sensorValue);
  if (sensorValue > 580) {
    rainmm = 80.437-0.0977*sensorValue;
  }
  else {
    if (sensorValue > 509) {
      rainmm = 443.6-0.717*sensorValue;
    }
    else
    {
      if (sensorValue > 466) {
        rainmm = 903.74-1.6059*sensorValue;
      }
      else{
      rainmm = 770.06-1.3314*sensorValue;
      }
    }
  }
  delay(1000);
  //answer=String(255);
  Serial.print("A0 signal : ");Serial.println(sensorValue);
  Serial.print("Rain mm : ");Serial.println(rainmm);
}
void input2_loop() {  
  // read the value from the sensor:
  sensorValue = analogRead(A0);
  //Serial.print(" Analog read := ");Serial.println(sensorValue);
  if (sensorValue > 580) {
    rainmm = 80.437-0.0977*sensorValue;
  }
  else {
    if (sensorValue > 509) {
      rainmm = 443.6-0.717*sensorValue;
    }
    else
    {
      if (sensorValue > 466) {
        rainmm = 903.74-1.6059*sensorValue;
      }
      else{
      rainmm = 770.06-1.3314*sensorValue;
      }
    }
  }
  delay(1000);
  //answer=String(255);  
}
void AM2302_loop() {
  // Delay between measurements.
  delay(delayMS);
  // Get temperature event and print its value.
  sensors_event_t event;  
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    Serial.println("Error reading temperature!");
  }
  else {
    Serial.print("Temperature: ");
    Serial.print(event.temperature);
    Serial.println(" *C");
    temp_0 = event.temperature;
    data3 = temp_0;
  }
  // Get humidity event and print its value.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.println("Error reading humidity!");
  }
  else {
    Serial.print("Humidity: ");
    Serial.print(event.relative_humidity);
    Serial.println("%");
    humid_0 = event.relative_humidity;
    data4 = humid_0;
  }
  
}

 

สำหรับผลการทดสอบ  ได้ตามคลิปนี้ครับ  โดยจอด้านซ้ายจะเป็นการแสดงผลฝั่ง  Nano  และด้านขวาจะเป็นการแสดงผลฝั่ง Heltec LoRa  จะเห็นว่ามีการส่งผ่านค่าจาก Nano  มายัง  heltec  ก่อนที่  helec  จะสร้าง  String  ส่งไปยัง  LoRa ตัวรับ  เพื่อส่งไปยัง  Server  ผ่านทาง WiFi อีกที

879 total views, 2 views today