RF Transceiver Pair
with Arduino
d. bodnar revised 04-08-2015
I have been experimenting with a pair of
very small RF transceivers, RFM69HW, that were purchased on
eBay These
units operate at 915 MHz and cost a bit over $10.00 for the pair.
|
Hardware Setup The RFM69HW operates at 3.3 volts. Most Arduinos and other devices use 5 volts. This means that you must use an Arduino that also works at 3.3 volts. I used the ProMini and used a small programmer from Deal Extreme that costs about $6.00 from China or about $7 from their US warehouse - note that this programmer can be set to provide 3.3 volts or 5 volts by changing a solder jumper. The unit on the left is jumpered for 5 volt operation. To set it for 3.3 volts remove the solder between the center pad and the one marked 5v and place a solder bridge from the center pad to the pad marked 3.3v as shown on the right. The programmer connects as shown here: I added wires terminating in female connectors to test the transceivers.
The red labels show the connection pins to the Arduino.
The antenna is 3.6" long with an 3.6" wire connected to ground. This makes up a dipole antenna that I taped to a coffee stirrer. |
Schematic The schematic below includes the RF unit, the Arduino and the temperature sensor |
Range Once the high power command (see note below) is properly set the range is quite impressing - so far I have found reliable communication up to 200 yards. It surely could be much more. |
Software for Testing I used two programs for testing. These were included as examples with the RFM69_master library. |
Struct_send-v2 - sends test
dataPLEASE NOTE that the example programs have commented out the high power setting: radio.setHighPower(); //uncomment only for RFM69HW! Be sure to remove the comment to activate high power #include <RFM69.h> #include <SPI.h> #include <SPIFlash.h> #define NODEID 99 #define NETWORKID 100 #define GATEWAYID 1 #define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) #define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! #define LED 9 #define SERIAL_BAUD 9600 #define ACK_TIME 30 // # of ms to wait for an ack int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms) byte sendSize=0; boolean requestACK = false; SPIFlash flash(8, 0xEF40); //was 30 EF40 for 16mbit windbond chip RFM69 radio; typedef struct { int nodeId; //store this nodeId unsigned long uptime; //uptime in ms long temp; //float temp; //temperature maybe? } Payload; Payload theData; void setup() { Serial.begin(SERIAL_BAUD); radio.initialize(FREQUENCY,NODEID,NETWORKID); radio.setHighPower(); //uncomment only for RFM69HW! radio.encrypt(KEY); char buff[50]; sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); if (flash.initialize()) Serial.println("SPI Flash Init OK!"); else Serial.println("SPI Flash Init FAIL! (is chip present?)"); } long lastPeriod = -1; void loop() { //process any serial input if (Serial.available() > 0) { char input = Serial.read(); if (input >= 48 && input <= 57) //[0,9] { TRANSMITPERIOD = 100 * (input-48); if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000; Serial.print("\nChanging delay to "); Serial.print(TRANSMITPERIOD); Serial.println("ms\n"); } if (input == 'r') //d=dump register values radio.readAllRegs(); //if (input == 'E') //E=enable encryption // radio.encrypt(KEY); //if (input == 'e') //e=disable encryption // radio.encrypt(null); if (input == 'd') //d=dump flash area { Serial.println("Flash content:"); int counter = 0; while(counter<=256){ Serial.print(flash.readByte(counter++), HEX); Serial.print('.'); } while(flash.busy()); Serial.println(); } if (input == 'e') { Serial.print("Erasing Flash chip ... "); flash.chipErase(); while(flash.busy()); Serial.println("DONE"); } if (input == 'i') { Serial.print("DeviceID: "); word jedecid = flash.readDeviceId(); Serial.println(jedecid, HEX); } } //check for any received packets if (radio.receiveDone()) { Serial.print('['); Serial.print(radio.SENDERID, DEC); Serial.print("] "); for (byte i = 0; i < radio.DATALEN; i++) Serial.print((char)radio.DATA[i]); Serial.print(" [RX_RSSI:"); Serial.print(radio.readRSSI()); Serial.print("]"); if (radio.ACKRequested()) { radio.sendACK(); Serial.print(" - ACK sent"); delay(10); } Blink(LED,5); Serial.println(); } int currPeriod = millis()/TRANSMITPERIOD; if (currPeriod != lastPeriod) { //fill in the struct with new values theData.nodeId = NODEID; theData.uptime = millis(); theData.temp = 210099987 ; //it's hot! Serial.print("Sending struct ("); Serial.print(sizeof(theData)); Serial.print(" bytes) ... "); if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData))) Serial.print(" ok!"); else Serial.print(" nothing..."); Serial.println(); Blink(LED,3); lastPeriod=currPeriod; } } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); }
|
Struct_receive-v2 - receives
test dataPLEASE NOTE that the example programs have commented out the high power setting: radio.setHighPower(); //uncomment only for RFM69HW! Be sure to remove the comment to activate high power #include <RFM69.h> #include <SPI.h> #include <SPIFlash.h> #define NODEID 1 #define NETWORKID 100 #define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) #define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! #define LED 9 #define SERIAL_BAUD 9600 #define ACK_TIME 30 // # of ms to wait for an ack RFM69 radio; SPIFlash flash(8, 0xEF40); //was 30 EF40 for 16mbit windbond chip bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network typedef struct { int nodeId; //store this nodeId unsigned long uptime; //uptime in ms long temp;//float temp; //temperature maybe? } Payload; Payload theData; void setup() { Serial.begin(SERIAL_BAUD); delay(10); radio.initialize(FREQUENCY,NODEID,NETWORKID); radio.setHighPower(); //uncomment only for RFM69HW! radio.encrypt(KEY); radio.promiscuous(promiscuousMode); char buff[50]; sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); if (flash.initialize()) Serial.println("SPI Flash Init OK!"); else Serial.println("SPI Flash Init FAIL! (is chip present?)"); } byte ackCount=0; void loop() { //process any serial input if (Serial.available() > 0) { char input = Serial.read(); if (input == 'r') //d=dump all register values radio.readAllRegs(); if (input == 'E') //E=enable encryption radio.encrypt(KEY); if (input == 'e') //e=disable encryption radio.encrypt(null); if (input == 'p') { promiscuousMode = !promiscuousMode; radio.promiscuous(promiscuousMode); Serial.print("Promiscuous mode "); Serial.println(promiscuousMode ? "on" : "off"); } if (input == 'd') //d=dump flash area { Serial.println("Flash content:"); int counter = 0; while(counter<=256){ Serial.print(flash.readByte(counter++), HEX); Serial.print('.'); } while(flash.busy()); Serial.println(); } if (input == 'D') { Serial.print("Deleting Flash chip content... "); flash.chipErase(); while(flash.busy()); Serial.println("DONE"); } if (input == 'i') { Serial.print("DeviceID: "); word jedecid = flash.readDeviceId(); Serial.println(jedecid, HEX); } } if (radio.receiveDone()) { Serial.print('['); Serial.print(radio.SENDERID, DEC); Serial.print("] "); Serial.print(" [RX_RSSI:"); Serial.print(radio.readRSSI()); Serial.print("]"); if (promiscuousMode) { Serial.print("to ["); Serial.print(radio.TARGETID, DEC); Serial.print("] "); } if (radio.DATALEN != sizeof(Payload)) Serial.print("Invalid payload received, not matching Payload struct!"); else { theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else Serial.print(" nodeId="); Serial.print(theData.nodeId); Serial.print(" uptime="); Serial.print(theData.uptime); Serial.print(" temp="); Serial.print(theData.temp); } if (radio.ACKRequested()) { byte theNodeID = radio.SENDERID; radio.sendACK(); Serial.print(" - ACK sent."); // When a node requests an ACK, respond to the ACK // and also send a packet requesting an ACK (every 3rd one only) // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY if (ackCount++%3==0) { Serial.print(" Pinging node "); Serial.print(theNodeID); Serial.print(" - ACK..."); delay(3); //need this when sending right after reception .. ? if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0, 50)) // 0 = only 1 attempt, no retries; wait up to 50mS Serial.print("ok!"); else Serial.print("nothing"); } } Serial.println(); Blink(LED,3); } } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); }
|
The two programs below were tested with additional data (kount) on 4-8-15 |
Struct_send-temperature-v3b /*d. bodnar 2-12-15 combines transciever & one wire temperature to send temperature over RF - WORKING! */ #include <RFM69.h> #include <SPI.h> #include <SPIFlash.h> #define NODEID 99 #define NETWORKID 100 #define GATEWAYID 1 #define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) #define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! #define LED 9 #define SERIAL_BAUD 9600 #define ACK_TIME 30 // # of ms to wait for an ack #include <OneWire.h> #include <DallasTemperature.h> // Data wire is plugged into port 3 on the Arduino #define ONE_WIRE_BUS 3 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); float ftemp=0; // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); long loopCount; //times through loop int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms) byte sendSize=0; boolean requestACK = false; SPIFlash flash(8, 0xEF40); //was 30 EF40 for 16mbit windbond chip RFM69 radio; typedef struct { int nodeId; //store this nodeId unsigned long uptime; //uptime in ms long temp; //float temp; //temperature maybe? long kount; //times through loop } Payload; Payload theData; void setup() { Serial.begin(SERIAL_BAUD); radio.initialize(FREQUENCY,NODEID,NETWORKID); radio.setHighPower(); //uncomment only for RFM69HW! radio.encrypt(KEY); char buff[50]; sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); sensors.begin(); if (flash.initialize()) Serial.println("SPI Flash Init OK!"); else Serial.println("SPI Flash Init FAIL! (is chip present?)"); } long lastPeriod = -1; void loop() { loopCount=loopCount + 1; //process any serial input if (Serial.available() > 0) { char input = Serial.read(); if (input >= 48 && input <= 57) //[0,9] { TRANSMITPERIOD = 100 * (input-48); if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000; Serial.print("\nChanging delay to "); Serial.print(TRANSMITPERIOD); Serial.println("ms\n"); } if (input == 'r') //d=dump register values radio.readAllRegs(); //if (input == 'E') //E=enable encryption // radio.encrypt(KEY); //if (input == 'e') //e=disable encryption // radio.encrypt(null); if (input == 'd') //d=dump flash area { Serial.println("Flash content:"); int counter = 0; while(counter<=256){ Serial.print(flash.readByte(counter++), HEX); Serial.print('.'); } while(flash.busy()); Serial.println(); } if (input == 'e') { Serial.print("Erasing Flash chip ... "); flash.chipErase(); while(flash.busy()); Serial.println("DONE"); } if (input == 'i') { Serial.print("DeviceID: "); word jedecid = flash.readDeviceId(); Serial.println(jedecid, HEX); } } //check for any received packets if (radio.receiveDone()) { Serial.print('['); Serial.print(radio.SENDERID, DEC); Serial.print("] "); for (byte i = 0; i < radio.DATALEN; i++) Serial.print((char)radio.DATA[i]); Serial.print(" [RX_RSSI:"); Serial.print(radio.readRSSI()); Serial.print("]"); if (radio.ACKRequested()) { radio.sendACK(); Serial.print(" - ACK sent"); delay(10); } Blink(LED,5); Serial.println(); } Serial.print("Requesting temperatures..."); sensors.requestTemperatures(); // Send the command to get temperatures Serial.println("DONE"); Serial.print("Temperature for the device 1 (index 0) is: "); Serial.println(sensors.getTempCByIndex(0)); ftemp =sensors.getTempCByIndex(0); ftemp = ftemp * 9; ftemp = ftemp / 5; ftemp = ftemp + 32; Serial.println(ftemp); int currPeriod = millis()/TRANSMITPERIOD; if (currPeriod != lastPeriod) { //fill in the struct with new values theData.nodeId = NODEID; theData.uptime = millis(); theData.temp = ftemp ; //it's hot! theData.kount = loopCount; //just a counter to keep track of loops through Serial.print("Sending struct ("); Serial.print(sizeof(theData)); Serial.print(" bytes) ... "); if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData))) Serial.print(" ok!"); else Serial.print(" nothing..."); Serial.println(); Blink(LED,3); lastPeriod=currPeriod; } } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); } |
Struct_receive-temperature-v2b#include <RFM69.h> #include <SPI.h> #include <SPIFlash.h> #define NODEID 1 #define NETWORKID 100 #define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) #define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! #define LED 9 #define SERIAL_BAUD 9600 #define ACK_TIME 30 // # of ms to wait for an ack RFM69 radio; SPIFlash flash(8, 0xEF40); //was 30 EF40 for 16mbit windbond chip bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network typedef struct { int nodeId; //store this nodeId unsigned long uptime; //uptime in ms long temp;//float temp; //temperature maybe? long kount; } Payload; Payload theData; void setup() { Serial.begin(SERIAL_BAUD); delay(10); radio.initialize(FREQUENCY,NODEID,NETWORKID); radio.setHighPower(); //uncomment only for RFM69HW! radio.encrypt(KEY); radio.promiscuous(promiscuousMode); char buff[50]; sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); if (flash.initialize()) Serial.println("SPI Flash Init OK!"); else Serial.println("SPI Flash Init FAIL! (is chip present?)"); } byte ackCount=0; void loop() { //process any serial input if (Serial.available() > 0) { char input = Serial.read(); if (input == 'r') //d=dump all register values radio.readAllRegs(); if (input == 'E') //E=enable encryption radio.encrypt(KEY); if (input == 'e') //e=disable encryption radio.encrypt(null); if (input == 'p') { promiscuousMode = !promiscuousMode; radio.promiscuous(promiscuousMode); Serial.print("Promiscuous mode "); Serial.println(promiscuousMode ? "on" : "off"); } if (input == 'd') //d=dump flash area { Serial.println("Flash content:"); int counter = 0; while(counter<=256){ Serial.print(flash.readByte(counter++), HEX); Serial.print('.'); } while(flash.busy()); Serial.println(); } if (input == 'D') { Serial.print("Deleting Flash chip content... "); flash.chipErase(); while(flash.busy()); Serial.println("DONE"); } if (input == 'i') { Serial.print("DeviceID: "); word jedecid = flash.readDeviceId(); Serial.println(jedecid, HEX); } } if (radio.receiveDone()) { // Serial.print('['); // Serial.print(radio.SENDERID, DEC); // Serial.print("] "); // Serial.print(" [RX_RSSI:"); // Serial.print(radio.readRSSI()); // Serial.print("]"); if (promiscuousMode) { Serial.print("to ["); Serial.print(radio.TARGETID, DEC); Serial.print("] "); } if (radio.DATALEN != sizeof(Payload)) Serial.print("Invalid payload received, not matching Payload struct!"); else { theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else Serial.print(" nodeId="); Serial.print(theData.nodeId); Serial.print(" uptime="); Serial.print(theData.uptime); Serial.print(" temperature="); Serial.print(theData.temp); Serial.print(" kount="); Serial.print(theData.kount); } if (radio.ACKRequested()) { byte theNodeID = radio.SENDERID; radio.sendACK(); // Serial.print(" - ACK sent."); // When a node requests an ACK, respond to the ACK // and also send a packet requesting an ACK (every 3rd one only) // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY /* if (ackCount++%3==0) { Serial.print(" Pinging node "); Serial.print(theNodeID); Serial.print(" - ACK..."); delay(3); //need this when sending right after reception .. ? if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0, 50)) // 0 = only 1 attempt, no retries; wait up to 50mS Serial.print("ok!"); else Serial.print("nothing"); } */ } Serial.println(); Blink(LED,300); } } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); } |