Note that the sub-GHz radio is not designed for streaming audio or video! It's best used for small packets of data. The data rate is adjustbale but its common to stick to around 19.2 Kbps (thats bits per second). Lower data rates will be more successful in their transmissions
You will, of course, need at least two paired radios to do any testing! The radios must be matched in frequency (e.g. 900 MHz & 900 MHz are ok, 900 MHz & 433 MHz are not). They also must use the same encoding schemes, you cannot have a 900 MHz RFM69 packet radio talk to a 900 MHz RFM96 LoRa radio.
Arduino Library
These radios have really excellent code already written, so rather than coming up with a new standard we suggest using existing libraries such as AirSpayce's Radiohead library which also suppors a vast number of other radios
This is a really great Arduino Library, so please support them in thanks for their efforts!
RadioHead RFM9x Library example
To begin talking to the radio, you will need to download the RadioHead library. You can do that by visiting the github repo and manually downloading or, easier, just click this button to download the zip corresponding to version 1.59
Note that while all the code in the examples below are based on this version you can visit the RadioHead documentation page to get the most recent version which may have bug-fixes or more functionality
Uncompress the zip and find the folder named RadioHead and check that the RadioHead folder contains RH_RF95.cpp and RH_RF95.h (as well as a few dozen other files for radios that are supported)
Place the RadioHead library folder your arduinosketchfolder/libraries/ folder.
You may need to create the libraries subfolder if its your first library. Restart the IDE.
We also have a great tutorial on Arduino library installation at:
http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use
Basic RX & TX example
Lets get a basic demo going, where one Arduino transmits and the other receives. We'll start by setting up the transmitter
Transmitter example code
This code will send a small packet of data once a second to node address #1
Load this code into your Transmitter Arduino!
// LoRa 9x_TX // -*- mode: C++ -*- // Example sketch showing how to create a simple messaging client (transmitter) // with the RH_RF95 class. RH_RF95 class does not provide for addressing or // reliability, so you should only use RH_RF95 if you do not need the higher // level messaging abilities. // It is designed to work with the other example LoRa9x_RX #include <SPI.h> #include <RH_RF95.h> #define RFM95_CS 10 #define RFM95_RST 9 #define RFM95_INT 2 // Change to 434.0 or other frequency, must match RX's freq! #define RF95_FREQ 915.0 // Singleton instance of the radio driver RH_RF95 rf95(RFM95_CS, RFM95_INT); void setup() { pinMode(RFM95_RST, OUTPUT); digitalWrite(RFM95_RST, HIGH); while (!Serial); Serial.begin(9600); delay(100); Serial.println("Arduino LoRa TX Test!"); // manual reset digitalWrite(RFM95_RST, LOW); delay(10); digitalWrite(RFM95_RST, HIGH); delay(10); while (!rf95.init()) { Serial.println("LoRa radio init failed"); while (1); } Serial.println("LoRa radio init OK!"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM if (!rf95.setFrequency(RF95_FREQ)) { Serial.println("setFrequency failed"); while (1); } Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on // The default transmitter power is 13dBm, using PA_BOOST. // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then // you can set transmitter powers from 5 to 23 dBm: rf95.setTxPower(23, false); } int16_t packetnum = 0; // packet counter, we increment per xmission void loop() { Serial.println("Sending to rf95_server"); // Send a message to rf95_server char radiopacket[20] = "Hello World # "; itoa(packetnum++, radiopacket+13, 10); Serial.print("Sending "); Serial.println(radiopacket); radiopacket[19] = 0; Serial.println("Sending..."); delay(10); rf95.send((uint8_t *)radiopacket, 20); Serial.println("Waiting for packet to complete..."); delay(10); rf95.waitPacketSent(); // Now wait for a reply uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf); Serial.println("Waiting for reply..."); delay(10); if (rf95.waitAvailableTimeout(1000)) { // Should be a reply message for us now if (rf95.recv(buf, &len)) { Serial.print("Got reply: "); Serial.println((char*)buf); Serial.print("RSSI: "); Serial.println(rf95.lastRssi(), DEC); } else { Serial.println("Receive failed"); } } else { Serial.println("No reply, is there a listener around?"); } delay(1000); }
Once uploaded you should see the following on the serial console
Now open up another instance of the Arduino IDE - this is so you can see the serial console output from the TX Arduino while you set up the RX Arduino.
Receiver example code
This code will receive and acknowledge a small packet of data.
Load this code into your Receiver Arduino!
// Arduino9x_RX // -*- mode: C++ -*- // Example sketch showing how to create a simple messaging client (receiver) // with the RH_RF95 class. RH_RF95 class does not provide for addressing or // reliability, so you should only use RH_RF95 if you do not need the higher // level messaging abilities. // It is designed to work with the other example Arduino9x_TX #include <SPI.h> #include <RH_RF95.h> #define RFM95_CS 10 #define RFM95_RST 9 #define RFM95_INT 2 // Change to 434.0 or other frequency, must match RX's freq! #define RF95_FREQ 915.0 // Singleton instance of the radio driver RH_RF95 rf95(RFM95_CS, RFM95_INT); // Blinky on receipt #define LED 13 void setup() { pinMode(LED, OUTPUT); pinMode(RFM95_RST, OUTPUT); digitalWrite(RFM95_RST, HIGH); while (!Serial); Serial.begin(9600); delay(100); Serial.println("Arduino LoRa RX Test!"); // manual reset digitalWrite(RFM95_RST, LOW); delay(10); digitalWrite(RFM95_RST, HIGH); delay(10); while (!rf95.init()) { Serial.println("LoRa radio init failed"); while (1); } Serial.println("LoRa radio init OK!"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM if (!rf95.setFrequency(RF95_FREQ)) { Serial.println("setFrequency failed"); while (1); } Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on // The default transmitter power is 13dBm, using PA_BOOST. // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then // you can set transmitter powers from 5 to 23 dBm: rf95.setTxPower(23, false); } void loop() { if (rf95.available()) { // Should be a message for us now uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf); if (rf95.recv(buf, &len)) { digitalWrite(LED, HIGH); RH_RF95::printBuffer("Received: ", buf, len); Serial.print("Got: "); Serial.println((char*)buf); Serial.print("RSSI: "); Serial.println(rf95.lastRssi(), DEC); // Send a reply uint8_t data[] = "And hello back to you"; rf95.send(data, sizeof(data)); rf95.waitPacketSent(); Serial.println("Sent a reply"); digitalWrite(LED, LOW); } else { Serial.println("Receive failed"); } } }
Now open up the Serial console on the receiver, while also checking in on the transmitter's serial console. You should see the receiver is...well, receiving packets
You can see that the library example prints out the hex-bytes received 48 65 6C 6C 6F 20 57 6F 72 6C 64 20 23 30 0 20 20 20 20 0
, as well as the ASCII 'string' Hello World
. Then it will send a reply.
And, on the transmitter side, it is now printing that it got a reply after each transmisssion And hello back to you
because it got a reply from the receiver
That's pretty much the basics of it! Lets take a look at the examples so you know how to adapt to your own radio setup
Radio Pinout
This is the pinout setup - you can change around the reset and CS pins to any pin. the IRQ pin should be an interrupt pin. On an UNO this is pin #2 or pin #3. Each chipset has different interrupt pins!
#define RFM95_CS 10 #define RFM95_RST 9 #define RFM95_INT 2
Frequency
You can dial in the frequency you want the radio to communicate on, such as 915.0, 434.0 or 868.0 or any number really. Different countries/ITU Zones have different ISM bands so make sure you're using those or if you are licensed, those frequencies you may use
// Change to 434.0 or other frequency, must match RX's freq! #define RF95_FREQ 915.0
You can then instantiate the radio object with our custom pin numbers.
// Singleton instance of the radio driver RH_RF95 rf95(RFM95_CS, RFM95_INT);
void setup() { pinMode(LED, OUTPUT); pinMode(RFM95_RST, OUTPUT); digitalWrite(RFM95_RST, HIGH); while (!Serial); // wait until serial console is open, remove if not tethered to computer Serial.begin(9600); delay(100); Serial.println("Arduino LoRa RX Test!"); // manual reset digitalWrite(RFM95_RST, LOW); delay(10); digitalWrite(RFM95_RST, HIGH); delay(10);
Remove the while (!Serial); line if you are not tethering to a computer, as it will cause the Arduino to halt until a USB connection is made!
Initializing Radio
The library gets initialized with a call to init(). Once initialized, you can set the frequency. You can also configure the output power level, the number ranges from 5 to 23. Start with the highest power level (23) and then scale down as necessary
while (!rf95.init()) { Serial.println("LoRa radio init failed"); while (1); } Serial.println("LoRa radio init OK!"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM if (!rf95.setFrequency(RF95_FREQ)) { Serial.println("setFrequency failed"); while (1); } Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on // The default transmitter power is 13dBm, using PA_BOOST. // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then // you can set transmitter powers from 5 to 23 dBm: rf95.setTxPower(23, false);
Transmission Code
If you are using the transmitter, this code will wait 1 second, then transmit a packet with "Hello World #" and an incrementing packet number
void loop() { delay(1000); // Wait 1 second between transmits, could also 'sleep' here! Serial.println("Transmitting..."); // Send a message to rf95_server char radiopacket[20] = "Hello World # "; itoa(packetnum++, radiopacket+13, 10); Serial.print("Sending "); Serial.println(radiopacket); radiopacket[19] = 0; Serial.println("Sending..."); delay(10); rf95.send((uint8_t *)radiopacket, 20); Serial.println("Waiting for packet to complete..."); delay(10); rf95.waitPacketSent();
Its pretty simple, the delay does the waiting, you can replace that with low power sleep code. Then it generates the packet and appends a number that increases every tx. Then it simply calls send to transmit the data, and passes in the array of data and the length of the data.
Note that this does not any addressing or subnetworking - if you want to make sure the packet goes to a particular radio, you may have to add an identifier/address byte on your own!
Then you call waitPacketSent() to wait until the radio is done transmitting. You will not get an automatic acknowledgement, from the other radio unless it knows to send back a packet. Think of it like the 'UDP' of radio - the data is sent, but its not certain it was received! Also, there will not be any automatic retries.
void loop() { if (rf95.available()) { // Should be a message for us now uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf); if (rf95.recv(buf, &len)) { digitalWrite(LED, HIGH); RH_RF95::printBuffer("Received: ", buf, len); Serial.print("Got: "); Serial.println((char*)buf); Serial.print("RSSI: "); Serial.println(rf95.lastRssi(), DEC);
Instead of transmitting, it is constantly checking if there's any data packets that have been received. available() will return true if a packet with proper error-correction was received. If so, the receiver prints it out in hex and also as a 'character string'
It also prints out the RSSI which is the receiver signal strength indicator. This number will range from about -15 to about -100. The larger the number (-15 being the highest you'll likely see) the stronger the signal.
Once done it will automatically reply, which is a way for the radios to know that there was an acknowledgement
// Send a reply uint8_t data[] = "And hello back to you"; rf95.send(data, sizeof(data)); rf95.waitPacketSent(); Serial.println("Sent a reply");
It simply sends back a string and waits till the reply is completely sent
Page last edited April 15, 2016
Text editor powered by tinymce.