How to Use Reyax RYLR999 LoRa Module With Arduino

by Rachana Jain in Circuits > Arduino

16 Views, 0 Favorites, 0 Comments

How to Use Reyax RYLR999 LoRa Module With Arduino

Untitled design (1).jpg

Many IoT projects require wireless communication over long distances while running on limited power. Common technologies like Wi-Fi and Bluetooth work well for short ranges but consume significant power and are unsuitable for battery-operated outdoor systems. Cellular solutions can cover long distances, but they are costly.

LoRa (Long Range) technology solves this problem by allowing devices to exchange small amounts of data across kilometers while using very little power. In this project, we will interface the RYLR999 LoRa module with an Arduino.

Supplies

Arduino UNO R3

LCD 16x2

Jumper Wires

USB Cable Type A to B

12V Supply Adapter

5V Voltage Shifter Module

RYLR999 Module

LoRa Technology

LoRa is a low-power wireless communication method designed for long-range data transmission. It is widely used in IoT applications.

Unlike Wi-Fi or Bluetooth, LoRa focuses on:

  1. Very long communication range
  2. Low data rate
  3. Extremely low power consumption

LoRa devices usually send small packets of information like sensor readings or status updates rather than continuous data streams. This makes them ideal for battery-powered systems that need to run for months or years.

Overview of the RYLR999 Module

The RYLR999, developed by REYAX, is a versatile wireless module that combines:

  1. LoRa communication (868/915 MHz)
  2. Bluetooth Low Energy (2.4 GHz)

Both communication systems operate independently and are accessed using separate UART interfaces. This means the module can handle short-range BLE communication and long-range LoRa communication at the same time.

One unique feature of this module is its ability to act as a BLE-to-LoRa bridge, allowing data from a smartphone to be transmitted over long distances using LoRa.

RYLR999 Pin Description

pinout.png

Understanding the pinout is important before connecting the module to Arduino.

  1. VDD – Power supply input (5V regulated)
  2. GND – Ground connection
  3. RST – Reset pin (active LOW)
  4. TXD_LoRa – LoRa UART transmit output
  5. RXD_LoRa – LoRa UART receive input (AT commands)
  6. TXD_BLE – BLE UART transmit pin
  7. RXD_BLE – BLE UART receive pin

Communication Between Arduino and RYLR999

Slide1.PNG
Slide2.PNG
PINOUT6.png

Wiring Connections for the Initiator Setup

In the initiator setup, the Arduino UNO communicates with the RYLR999 LoRa module by sending transmission commands and showing the communication status on a 16×2 I2C LCD. The Arduino acts as the controller, while the LoRa module handles long-range wireless data transfer.

The RYLR999 module is powered directly from the Arduino. Its VDD pin is connected to the 5V output of the Arduino UNO, and the GND pin is connected to the common ground. Since the LoRa module operates at 3.3V logic levels and the Arduino uses 5V logic, a bi-directional voltage level shifter is used between their UART pins.

The TXD_LoRa pin of the RYLR999 is connected to the LV1 pin of Voltage shifter, while the corresponding HV1 output is connected to the Arduino’s RX pin. Similarly, the Arduino’s TX pin is connected to HV2 pin of the level shifter, and corresponding LV2 output is wired to the RXD_LoRa pin of the module.

To power the voltage shifter correctly, the Arduino’s 5V pin is connected to the HV pin, and the 3.3V pin is connected to the LV pin of the level shifter. These power connections are essential for proper voltage translation between the two devices.


I2C LCD Connections

Connecting the I2C LCD to the Arduino is straightforward. The VCC and GND pins of the LCD are connected to the corresponding 5V and GND pins on the Arduino. The SDA (data) and SCL (clock) lines are connected to the Arduino’s SDA and SCL pins.

On the Arduino UNO, SDA and SCL are also available on analog pins A4 and A5, respectively. These pins are internally connected, so either set can be used for the I2C interface.

Ensure that the A0, A1, and A2 address jumpers on the back of the I2C LCD are left unconnected. This configuration sets the LCD’s I2C address to 0x27, which matches the address used in the program.


Responder Circuit Connections

The responder circuit is simpler than the initiator setup because it does not include an LCD. In this configuration, the Arduino continuously monitors incoming LoRa messages through the RYLR999 module and processes them as required.

Apart from removing the LCD wiring, all other connections between the Arduino UNO, voltage shifter, and RYLR999 module remain the same as in the initiator circuit.

Arduino Code for Initiator Setup

Upload the following code to Arduino:

/*
Code to send “Are you there?” from one Arduino to another Arduino using RLYR999 Module
and receive reply and display complete communication on I2C LCD by platwithcircuit.com
*/
#include <LiquidCrystal_I2C.h>
#define REPLY_TIMEOUT_IN_MS 300
#define REPLY_END_CHAR '\n'
#define MODULE_ADDRESS 0
#define RECEIVERS_ADDRESS 1
#define MIN_CHAR_TO_RCV 1
#define WAIT_FOR_RECIVERS_REPLY 3000
#define DELAY_BW_REPS 1000
// Init LCD at 0x27, 16x2
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
boolean boRetVal = false;
// begin serial communication at baud 115200,n,8,1
// to communicate with the RF module
Serial.begin(115200);
// initialize the LCD
lcd.init();
// Turn ON the Backlight
lcd.backlight();
// Clear the display buffer
lcd.clear();
flushBuffer(); // clear rx data
// Reset settings to factory defaults
boRetVal = boRestoreFactoryDefaults();
// setting the address if reset successfully
if (boRetVal == true) {
flushBuffer(); // clear rx data
boRetVal = boSetAddress();
}
if (boRetVal == true) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Module Init");
lcd.setCursor(0, 1);
lcd.print("Successful");
delay(1000);
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Module Init");
lcd.setCursor(0, 1);
lcd.print("Failed");
while (1)
;
}
}
void loop() {
String request = "Are you there?";
String expected_reply = "Yes";
bool boRetVal = false;
flushBuffer(); // clear rx data
// transmits String named request
boRetVal = boSendData(request);
if (boRetVal == true) {
// Displaying Sent Msg
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Msg Sent:");
lcd.setCursor(0, 1);
lcd.print(request);
delay(1000);
boRetVal = chkReply(expected_reply, REPLY_END_CHAR, WAIT_FOR_RECIVERS_REPLY);
if (boRetVal == true) {
// Displaying received Msg
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Msg Received:");
lcd.setCursor(0, 1);
lcd.print(expected_reply);
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No reply received.");
}
} else {
// Displaying Failed Msg
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Msg Sending");
lcd.setCursor(0, 1);
lcd.print("Failed");
}
delay(DELAY_BW_REPS); // wait before sending again
}
void sendCrLf(void) {
Serial.write(0x0D); // Carriage Return
Serial.write(0x0A); // Line Feed
}
void flushBuffer(void) {
while (Serial.available() > 0) {
Serial.read();
}
}
bool chkReply(String chkString, char receiveUntil, unsigned int timeout) {
String receivedString; // save received data in this string object
bool boReturnValue = false; // function's return value
// wait for reply
do {
timeout--;
delay(1); // delay of 1 ms
} while ((Serial.available() < MIN_CHAR_TO_RCV) && (timeout > 0));
if (timeout) {
// if timeout is left then a reply is received check for the string in the reply
receivedString = Serial.readStringUntil(receiveUntil);
if (receivedString.indexOf(chkString) != -1) {
boReturnValue = true;
} else {
boReturnValue = false;
}
} else {
boReturnValue = false;
}
// return result
return boReturnValue;
}
bool boRestoreFactoryDefaults(void) {
const char factoryDefaultCmd[] = "AT+FACTORY"; // command to be sent
bool boReturnValue = false; // function's return value
char downCounter = 100; // Down counter to wait for reply
String receivedString; // save received data in this string object
String chkRcvString1 = "+FACTORY";
String chkRcvString2 = "+READY";
// send command
Serial.print(factoryDefaultCmd);
sendCrLf();
// check first string in reply
boReturnValue = chkReply(chkRcvString1, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS);
if (boReturnValue == true) {
// check second string in reply
boReturnValue = chkReply(chkRcvString2, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS);
}
// return result
return boReturnValue;
}
bool boSetAddress(void) {
const char setAddressCmd[] = "AT+ADDRESS="; // command to be sent
bool boReturnValue = false; // function's return value
String chkRcvString = "+OK";
// send command
Serial.print(setAddressCmd);
Serial.print(MODULE_ADDRESS);
sendCrLf();
// check reply
boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS);
// return result
return boReturnValue;
}
bool boSendData(String data) {
const char sendDataCmd[] = "AT+SEND="; // command to be sent
bool boReturnValue = false; // function's return value
String chkRcvString = "+OK";
// send command
Serial.print(sendDataCmd);
Serial.print(RECEIVERS_ADDRESS);
Serial.print(',');
Serial.print(data.length());
Serial.print(',');
Serial.print(data);
sendCrLf();
// check reply
boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS);
// return result
return boReturnValue;
}


For Arduino Code for Responder Setup checkout: How to Interface Reyax RYLR999 LoRa Module with Arduino