/** * See documentation at https://nRF24.github.io/RF24 * See License information at root directory of this library * written in 2014 by tong67 (https://github.com/tong67) * Updated 2020 by 2bndy5 (http://github.com/2bndy5) for the * SpenceKonde ATTinyCore (https://github.com/SpenceKonde/ATTinyCore) */ /** * The RF24 library uses the [ATTinyCore by * SpenceKonde](https://github.com/SpenceKonde/ATTinyCore) * * This sketch is a duplicate of the ManualAcknowledgements.ino example * (without all the Serial input/output code), and it demonstrates * a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using * the RF24 class to communicate with another node. * * A simple example of sending data from 1 nRF24L01 transceiver to another * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. * This example still uses ACK packets, but they have no payloads. Instead the * acknowledging response is sent with `write()`. This tactic allows for more * updated acknowledgement payload data, where actual ACK payloads' data are * outdated by 1 transmission because they have to loaded before receiving a * transmission. * * This example was written to be used on 2 devices acting as "nodes". */ /* * ********** Hardware configuration (& schematics) ******************* * * When direct use of 3V does not work (UNO boards tend to have poor 3V supply), * use 5V with LED (1.8V ~ 2.2V drop) instead. * For low power consumption solutions floating pins (SCK and MOSI) should be * pulled HIGH or LOW with 10K resistors. * * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4 * ^^ * +-\/-+ // * PB5 1|o |8 Vcc --- nRF24L01 VCC --- |<|--- 5V * nRF24L01 CE --- PB3 2| |7 PB2 --- nRF24L01 SCK LED * nRF24L01 CSN --- PB4 3| |6 PB1 --- nRF24L01 MOSI * nRF24L01 GND --- GND 4| |5 PB0 --- nRF24L01 MISO * +----+ * * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are * free to use for other purposes. This "3 pin solution" is from * Ralph Doncaster (AKA NerdRalph) which is outlined on his blog at * http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html * Original RC combination was 1K/100nF. 22K/10nF combination worked better. * * For best settle time delay value to use for RF24::csDelay in RF24::csn(), use * the examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino sketch. * * This configuration is enabled in the RF24 library when CE_PIN and * CSN_PIN parameters to the constructor are equal. Notice (in the schematic * below) that these pins aren't directly to the ATTiny85. Because the CE pin * is always HIGH, the power consumption is higher than it would be for the * typical 5 pins solution. * ^^ * +-\/-+ nRF24L01 CE --------| // * PB5 1|o |8 Vcc --- nRF24L01 VCC -------x----------x--|<|-- 5V * PB3 2| |7 PB2 --- nRF24L01 SCK ---|<|---x-[22k]--| LED * PB4 3| |6 PB1 --- nRF24L01 MOSI 1n4148 | * nRF24L01 GND -x- GND 4| |5 PB0 --- nRF24L01 MISO | * | +----+ | * |-----------------------------------------||----x-- nRF24L01 CSN * 10nF * * ATTiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 & assuming 1.9V to 3V on VCC * Schematic provided and successfully tested by * Carmine Pastore (https://github.com/Carminepz) * * +-\/-+ * nRF24L01 VCC ---- VCC 1|o |14 GND --- nRF24L01 GND * PB0 2| |13 AREF * PB1 3| |12 PA1 * PB3 4| |11 PA2 --- nRF24L01 CE * PB2 5| |10 PA3 --- nRF24L01 CSN * PA7 6| |9 PA4 --- nRF24L01 SCK * nRF24L01 MOSI --- PA6 7| |8 PA5 --- nRF24L01 MISO * +----+ */ #include "SPI.h" #include "RF24.h" // CE and CSN are configurable, specified values for ATTiny85 as connected above #define CE_PIN 3 #define CSN_PIN 4 //#define CSN_PIN 3 // uncomment for ATTiny85 3 pins solution // instantiate an object for the nRF24L01 transceiver RF24 radio(CE_PIN, CSN_PIN); // Let these addresses be used for the pair uint8_t address[][6] = { "1Node", "2Node" }; // It is very helpful to think of an address as a path instead of as // an identifying device destination // to use different addresses on a pair of radios, we need a variable to // uniquely identify which address this radio will use to transmit bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit // Used to control whether this node is sending or receiving bool role = false; // true = TX node, false = RX node // For this example, we'll be using a payload containing // a string & an integer number that will be incremented // on every successful transmission. // Make a data structure to store the entire payload of different datatypes struct PayloadStruct { char message[7]; // only using 6 characters for TX & RX payloads uint8_t counter; }; PayloadStruct payload; void setup() { // append a NULL terminating character for printing as a c-string payload.message[6] = 0; // initialize the transceiver on the SPI bus if (!radio.begin()) { while (1) {} // hold in infinite loop } // Set the PA Level low to try preventing power supply related problems // because these examples are likely run with nodes in close proximity to // 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)); // char[7] & uint8_t datatypes occupy 8 bytes // set the TX address of the RX node into the TX pipe radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 // set the RX address of the TX node into a RX pipe radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 if (role) { // setup the TX node memcpy(payload.message, "Hello ", 6); // set the outgoing message radio.stopListening(); // put radio in TX mode } else { // setup the RX node memcpy(payload.message, "World ", 6); // set the outgoing message radio.startListening(); // put radio in RX mode } } // setup() void loop() { if (role) { // This device is a TX node bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report if (report) { // transmission successful; wait for response and print results radio.startListening(); // put in RX mode unsigned long start_timeout = millis(); // timer to detect no response while (!radio.available()) { // wait for response or timeout if (millis() - start_timeout > 200) // only wait 200 ms break; } radio.stopListening(); // put back in TX mode // print summary of transactions if (radio.available()) { // is there a payload received? PayloadStruct received; radio.read(&received, sizeof(received)); // get payload from RX FIFO payload.counter = received.counter; // save incoming counter for next outgoing counter } } // report // to make this example readable in the serial monitor delay(1000); // slow transmissions down by 1 second } else { // This device is a RX node if (radio.available()) { // is there a payload? PayloadStruct received; radio.read(&received, sizeof(received)); // get incoming payload payload.counter = received.counter + 1; // increment incoming counter for next outgoing response // transmit response & save result to `report` radio.stopListening(); // put in TX mode radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO radio.txStandBy(150); // keep retrying for 150 ms radio.startListening(); // put back in RX mode } } // role } // loop