198 lines
7.4 KiB
C++
198 lines
7.4 KiB
C++
/*
|
|
* See documentation at https://nRF24.github.io/RF24
|
|
* See License information at root directory of this library
|
|
* Author: Brendan Doherty 2bndy5
|
|
*/
|
|
|
|
/**
|
|
* A simple example of sending data from as many as 6 nRF24L01 transceivers to
|
|
* 1 receiving transceiver. This technique is trademarked by
|
|
* Nordic Semiconductors as "MultiCeiver".
|
|
*
|
|
* This example was written to be used on up to 6 devices acting as TX nodes &
|
|
* only 1 device acting as the RX node (that's a maximum of 7 devices).
|
|
* Use the Serial Monitor to change each node's behavior.
|
|
*/
|
|
#include <SPI.h>
|
|
#include "printf.h"
|
|
#include "RF24.h"
|
|
|
|
// instantiate an object for the nRF24L01 transceiver
|
|
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
|
|
|
|
// For this example, we'll be using 6 addresses; 1 for each TX node
|
|
// It is very helpful to think of an address as a path instead of as
|
|
// an identifying device destination
|
|
// Notice that the last byte is the only byte that changes in the last 5
|
|
// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5
|
|
// because they use the same first 4 bytes from pipe 1.
|
|
uint64_t address[6] = {0x7878787878LL,
|
|
0xB3B4B5B6F1LL,
|
|
0xB3B4B5B6CDLL,
|
|
0xB3B4B5B6A3LL,
|
|
0xB3B4B5B60FLL,
|
|
0xB3B4B5B605LL
|
|
};
|
|
|
|
// Because this example allow up to 6 nodes (specified by numbers 0-5) to
|
|
// transmit and only 1 node to receive, we will use a negative value in our
|
|
// role variable to signify this node is a receiver.
|
|
// role variable is used to control whether this node is sending or receiving
|
|
char role = 'R'; // 0-5 = TX node; any negative number = RX node
|
|
|
|
// For this example, we'll be using a payload containing
|
|
// a node ID number and a single integer number that will be incremented
|
|
// on every successful transmission.
|
|
// Make a data structure to use as a payload.
|
|
struct PayloadStruct
|
|
{
|
|
unsigned long nodeID;
|
|
unsigned long payloadID;
|
|
};
|
|
PayloadStruct payload;
|
|
|
|
// This example uses all 6 pipes to receive while TX nodes only use 2 pipes
|
|
// To make this easier we'll use a function to manage the addresses, and the
|
|
// payload's nodeID
|
|
void setRole(); // declare a prototype; definition is found after the loop()
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
while (!Serial) {
|
|
// some boards need to wait to ensure access to serial over USB
|
|
}
|
|
|
|
// initialize the transceiver on the SPI bus
|
|
if (!radio.begin()) {
|
|
Serial.println(F("radio hardware is not responding!!"));
|
|
while (1) {} // hold in infinite loop
|
|
}
|
|
|
|
// print example's introductory prompt
|
|
Serial.println(F("RF24/examples/MulticeiverDemo"));
|
|
Serial.println(F("*** Enter a number between 0 and 5 (inclusive) to change"));
|
|
Serial.println(F(" the identifying node number that transmits."));
|
|
|
|
// Set the PA Level low to try preventing power supply related problems
|
|
// because these examples are likely run with nodes in close proximity of
|
|
// each other.
|
|
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
|
|
|
|
// save on transmission time by setting the radio to only transmit the
|
|
// number of bytes we need to transmit a float
|
|
radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes
|
|
|
|
// Set the pipe addresses accordingly. This function additionally also
|
|
// calls startListening() or stopListening() and sets the payload's nodeID
|
|
setRole();
|
|
|
|
// For debugging info
|
|
// printf_begin(); // needed only once for printing details
|
|
// radio.printDetails(); // (smaller) function that prints raw register values
|
|
// radio.printPrettyDetails(); // (larger) function that prints human readable data
|
|
|
|
} // setup()
|
|
|
|
void loop() {
|
|
|
|
if (role <= 53) {
|
|
// This device is a TX node
|
|
|
|
unsigned long start_timer = micros(); // start the timer
|
|
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
|
|
unsigned long end_timer = micros(); // end the timer
|
|
|
|
if (report) {
|
|
// payload was delivered
|
|
|
|
Serial.print(F("Transmission of payloadID "));
|
|
Serial.print(payload.payloadID); // print payloadID
|
|
Serial.print(F(" as node "));
|
|
Serial.print(payload.nodeID); // print nodeID
|
|
Serial.print(F(" successful!"));
|
|
Serial.print(F(" Time to transmit: "));
|
|
Serial.print(end_timer - start_timer); // print the timer result
|
|
Serial.println(F(" us"));
|
|
} else {
|
|
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
|
|
}
|
|
payload.payloadID++; // increment payload number
|
|
|
|
// to make this example readable in the serial monitor
|
|
delay(500); // slow transmissions down by 1 second
|
|
|
|
} else if (role == 'R') {
|
|
// This device is the RX node
|
|
|
|
uint8_t pipe;
|
|
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
|
|
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
|
|
radio.read(&payload, bytes); // fetch payload from FIFO
|
|
Serial.print(F("Received "));
|
|
Serial.print(bytes); // print the size of the payload
|
|
Serial.print(F(" bytes on pipe "));
|
|
Serial.print(pipe); // print the pipe number
|
|
Serial.print(F(" from node "));
|
|
Serial.print(payload.nodeID); // print the payload's origin
|
|
Serial.print(F(". PayloadID: "));
|
|
Serial.println(payload.payloadID); // print the payload's number
|
|
}
|
|
} // role
|
|
|
|
if (Serial.available()) {
|
|
// change the role via the serial monitor
|
|
|
|
char c = Serial.read();
|
|
if (toupper(c) == 'R' && role <= 53) {
|
|
// Become the RX node
|
|
|
|
role = 'R';
|
|
Serial.println(F("*** CHANGING ROLE TO RECEIVER ***"));
|
|
Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to act as"));
|
|
Serial.println(F(" a unique node number that transmits to the RX node."));
|
|
setRole(); // change address on all pipes to TX nodes
|
|
|
|
} else if (c >= 48 && c <= 53 && c != role) {
|
|
// Become a TX node with identifier 'c'
|
|
|
|
role = c - 48;
|
|
Serial.print(F("*** CHANGING ROLE TO NODE "));
|
|
Serial.print(c);
|
|
Serial.println(F(" ***"));
|
|
Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to change"));
|
|
Serial.println(F(" the identifying node number that transmits."));
|
|
Serial.println(F("--- PRESS 'R' to act as the RX node."));
|
|
setRole(); // change address on pipe 0 to the RX node
|
|
}
|
|
}
|
|
|
|
} // loop
|
|
|
|
void setRole() {
|
|
if (role == 'R') {
|
|
// For the RX node
|
|
|
|
// Set the addresses for all pipes to TX nodes
|
|
for (uint8_t i = 0; i < 6; ++i)
|
|
radio.openReadingPipe(i, address[i]);
|
|
|
|
radio.startListening(); // put radio in RX mode
|
|
|
|
} else {
|
|
// For the TX node
|
|
|
|
// set the payload's nodeID & reset the payload's identifying number
|
|
payload.nodeID = role;
|
|
payload.payloadID = 0;
|
|
|
|
// Set the address on pipe 0 to the RX node.
|
|
radio.stopListening(); // put radio in TX mode
|
|
radio.openWritingPipe(address[role]);
|
|
|
|
// According to the datasheet, the auto-retry features's delay value should
|
|
// be "skewed" to allow the RX node to receive 1 transmission at a time.
|
|
// So, use varying delay between retry attempts and 15 (at most) retry attempts
|
|
radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args
|
|
}
|
|
} // setRole
|