Hi all !
Hope everyone is fine.
Since last weekend, the project went live.
I've already discussed - in part - the data collecting part.
Receiving
What I'm going now to describe is the other end, the receiving one. Here's the schematics, with the SD Card module instead of the WiFi.
Here, the Arduino MKR 1300 WAN receives the LoRa package and sends it, via I2C to the Arduino UNO, so it can display the values in the Grove LCD RGB backlight.
Here are some photos - now with the SD Card module
This one does little, it just receives data.
code
Here is my code of this part. Because I'm not near a LoRa Gateway, I'm unable to send the data to the Arduino IoT Cloud - unfortunately. This MKR only receives the data coming from the remote one and sends it to the Arduino UNO.
#include <SPI.h> #include <LoRa.h> #include <Wire.h> #define debug 0 void setup() { if (debug) { Serial.begin(115200); while (!Serial); } if (debug) { Serial.println("LoRa Receiver"); } if (!LoRa.begin(868E6)) { Serial.println("Starting LoRa failed!"); while (1); } Wire.begin(); } void loop() { // try to parse packet String message = receivePackage(); if (message != "") { if (debug) { Serial.println(message); } //convert string to char array to send to wire int messageLen = message.length() + 1; char messageChar[messageLen]; //copy it message.toCharArray(messageChar, messageLen); if (debug) { Serial.println("start transmission"); } Wire.beginTransmission(100); Wire.write(messageChar); Wire.endTransmission(); if (debug) { Serial.println("End transmission"); } } //we can delay a bit delay (100); } String receivePackage() { String package; int packetSize = LoRa.parsePacket(); if (packetSize == 0) return ""; // read packet while (LoRa.available()) { package += (char)LoRa.read(); } return package; }
Let's dig in it
The first lines just include the libraries that we need.
The next line is just for debugging. It's not needed normally and, because I'm not using a PC, it prevents hanging (although that can be avoided in the code - more later) from not having a serial console.
#define debug 0
The next lines are part of the setup function - run once when booting .
if (debug) {
Serial.begin(115200);
while (!Serial);
}
If debug is active, it waits for a serial console. If not, it just hangs indefinitely .
The next line just prints on the serial console (if debug) .
Next, it starts the LoRa communications. Since I'm in Europe, that's the frequency I'm legally allowed to use.
if (!LoRa.begin(868E6)) {
Serial.println("Starting LoRa failed!");
while (1);
}
Next, to send information to the Arduino UNO via I2C, we need to initialize the Wire library. The functions we need are in the Arduino's Wire library. More info here.
Wire.begin();
Why Wire ?
I did try using the UART (Serial), but without any luck. This way, I was more successful. I've explained this here.
I'm going to explain now the function receivePackage.
String receivePackage() {
String package;
int packetSize = LoRa.parsePacket();
if (packetSize == 0) return "";
// read packet
while (LoRa.available()) {
package += (char)LoRa.read();
}
return package;
}
This function, what it does is very simple. This is where I get the information from the remote Arduino MKR 1300 WAN.
It checks if there's any package . If the package size is 0, it means there's nothing and returns an empty string
int packetSize = LoRa.parsePacket();
if (packetSize == 0) return "";
If not, while there's information to receive, it adds the character to the package variable (string concatenation).
After there's nothing more to receive, it returns the string with the information received.
while (LoRa.available()) {
package += (char)LoRa.read();
}
return package;
The loop function comes next. Like the name suggests, this function is always executing, in a loop.
It starts by checking if there's any information to receive, by calling the above function and storing what is returned in a variable called message - also a string.
String message = receivePackage();
If the message is not empty, then, we will send it via I2C to the Arduino UNO.
Because I2C works with characters, we need to convert the string into an array of characters.
We do that by knowing the length of the string, adding +1 (never forget the terminator character - '\0') and create the array of that size.
//convert string to char array to send to wire
int messageLen = message.length() + 1;
char messageChar[messageLen];
We now copy the message - string - to the array using a function called toCharArray. In the code above we made sure that the string fits into the array.
//copy it
message.toCharArray(messageChar, messageLen);
We now can start the I2C transmission.
We start the transmission by calling beginTransmission (100). The 100 is the address of the receiving device in the I2C bus. In the Arduino UNO we have - in setup() - a call to Wire.begin(100) - joining I2C bus with the address 100.
We then write to the I2C bus, sending the char array.
We end the transmission.
Wire.beginTransmission(100);
Wire.write(messageChar);
Wire.endTransmission();
Then we delay 100ms .
There's more ways to do this - sending
In the page above, A Guide to Arduino & the I2C Protocol (Two Wire) they do another approach, in which is the "receiver" that requests the "sender" for information.
And here it is. This is my approach on the receiving MKR
Next, the Arduino UNO, that displays and saves it all.