Components and supplies
Arduino Nano R3
Pushbutton switch 12mm
SparkFun Transceiver Breakout - nRF24L01+
LED (generic)
Breadboard (generic)
Project description
Code
morse transceiver
arduino
Simply upload to Arduino Nano #1 with radioNumber = 0 and then to #2 with radioNumber = 1.
1/* 2 Nov 2017 - morse tranceiver by ppenguin 3 Based on below described. 4 5 Simple morse code transceiver using 2 nodes consisting of NRF24 transceiver, a push button 6 and a RGB led connected to an Arduino Nano. 7 Nice for 2 kids to each sit in a room and experiment with "the old days" morse code communication. 8 The LED will light green for outgoing code and red for incoming code (to have better feedback) 9 10 Removed most serial code (except debugging) to enable stand alone operation 11 12 Dec 2014 - TMRh20 - Updated 13 Derived from examples by J. Coliz <maniacbug@ymail.com> 14*/ 15/** 16 * Example for efficient call-response using ack-payloads 17 * 18 * This example continues to make use of all the normal functionality of the radios including 19 * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well. 20 * This allows very fast call-response communication, with the responding radio never having to 21 * switch out of Primary Receiver mode to send back a payload, but having the option to switch to 22 * primary transmitter if wanting to initiate communication instead of respond to a commmunication. 23 */ 24 25#include <SPI.h> 26#include "RF24.h" 27 28/****************** User Config ***************************/ 29/*** Set this radio as radio number 0 or 1 ***/ 30bool radioNumber = 1; 31 32/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ 33RF24 radio(9,10); // use mysensor default pins since I'm used to that 34/**********************************************************/ 35 // Topology 36byte addresses[][6] = {"1Node","2Node"}; // Radio pipe addresses for the 2 nodes to communicate. 37 38// Role management: Set up role. This sketch uses the same software for all the nodes 39// in this system. Doing so greatly simplifies testing. 40typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch 41const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles 42role_e role = role_pong_back; // The role of the current running sketch 43 44#define LONG 2 // value of morse long _ 45#define SHORT 1 // value of morse short . 46#define ACK 3 // value of ACK payload (necessary?) 47#define DELAY 10 // loop delay 48#define TLONG 250 // 250ms or longer is considered long 49#define TLONGE 800 // max long period 50#define TSHORT 170 // 170ms or shorter is considered short 51#define MAXFAIL 10 52 53#define PINBT 2 // digital input push button 54#define PINL1 3 // digital output LED1 55#define PINL2 4 // digital output LED2 56 57byte payload = 0; // A single byte as payload 58byte ackByte = ACK; 59bool btpressed = false; 60unsigned long lastpressed = 0; 61byte fail = 0; 62 63void setup(){ 64 65 66 Serial.begin(115200); 67 Serial.println(F("RF24/examples/GettingStarted_CallResponse")); 68 /* 69 Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); 70 */ 71 72 // Setup and configure radio 73 74 radio.begin(); 75 76 radio.enableAckPayload(); // Allow optional ack payloads 77 radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads 78 79 if(radioNumber){ 80 radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses 81 radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1 82 }else{ 83 radio.openWritingPipe(addresses[0]); 84 radio.openReadingPipe(1,addresses[1]); 85 } 86 radio.startListening(); // Start listening 87 88 radio.writeAckPayload(1,&ackByte,1); // Pre-load an ack-paylod into the FIFO buffer for pipe 1 89 //radio.printDetails(); 90 91 pinMode(PINBT, INPUT_PULLUP); // high == off, but now de don't need an external resistor for the button 92 pinMode(PINL1, OUTPUT); 93 pinMode(PINL2, OUTPUT); 94 95} 96 97void loop(void) { 98 99 /* loop initial/primary function is 100 (1) poll push button 101 (2) check whether msg received 102 If the push button was pushed and we have a result (either short or long) it is sent (role change) 103 */ 104 105 btpressed = !digitalRead(PINBT); // invert because we use internal pullup 106 if (btpressed && lastpressed == 0) { 107 lastpressed = millis(); // button first pressed after last release 108 Serial.print("Button down"); 109 digitalWrite(PINL1, 1); 110 } 111 112 if (!btpressed && lastpressed != 0) { // button release 113 Serial.print("Button release"); 114 digitalWrite(PINL1, 0); 115 if (millis() - lastpressed <= TSHORT) { 116 payload = SHORT; 117 Serial.print("Set payload SHORT"); 118 } else if ((millis() - lastpressed >= TLONG) && (millis() - lastpressed <= TLONGE)) { 119 payload = LONG; 120 Serial.print("Set payload LONG"); 121 } else { 122 payload = 0; 123 } 124 lastpressed = 0; 125 // role = role_ping_out; // we have data now, so we send it 126 } 127 128 129/****************** Ping Out Role ***************************/ 130 //if (role == role_ping_out){ // Radio is in ping mode 131 if (payload > 0) { // we only need to send if we have a payload 132 133 byte gotByte; // Initialize a variable for the incoming response (only for ACK) 134 135 radio.stopListening(); // First, stop listening so we can talk. 136 Serial.print(F("Now sending ")); // Use a simple byte counter as payload 137 Serial.println(payload); 138 139 unsigned long time = millis(); // Record the current millisecond count 140 141 if ( radio.write(&payload,1) ) { // Send payload to the other radio 142 /* if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank 143 Serial.print(F("Got blank response. round-trip delay: ")); 144 Serial.print(millis()-time); 145 Serial.println(F(" milliseconds")); 146 }else{ */ 147 while(radio.available() ){ // If an ack with payload was received 148 radio.read( &gotByte, 1 ); // Read it, and display the response time 149 unsigned long timer = millis(); 150 if (gotByte == ACK) { // only interested in ACK now 151 Serial.print(F("Got ACK response ")); 152 Serial.print(gotByte); 153 Serial.print(F(" round-trip delay: ")); 154 Serial.print(timer - time); 155 Serial.println(F(" milliseconds")); 156 break; // one ACK is enough, now continue listening 157 } 158 } 159 //} 160 payload = 0; // reset payload after sucessfuly sending 161 162 } else { 163 fail++; 164 if (fail >= MAXFAIL) { 165 fail = 0; 166 payload = 0; // give up and start listening 167 } 168 } 169 170 delay(DELAY); // Try again later 171 } 172 173 174/****************** Pong Back Role ***************************/ 175 // if ( role == role_pong_back ) { 176 if (payload == 0) { // nothing to send, so listen 177 radio.startListening(); 178 179 byte pipeNo, gotByte; // Declare variables for the pipe and the byte received 180 while( radio.available(&pipeNo)){ // Read all available payloads 181 digitalWrite(PINL2, 0); // default LED off 182 radio.read( &gotByte, 1 ); 183 // Since this is a call-response. Respond directly with an ack payload. 184 // Ack payloads are much more efficient than switching to transmit mode to respond to a call 185 radio.writeAckPayload(pipeNo,&ackByte, 1 ); // This can be commented out to send empty payloads. 186 Serial.print(F("sent ACK")); 187 188 // handle user output for received byte 189 Serial.println(gotByte); 190 unsigned long ttime = 0; 191 if (gotByte == LONG) ttime = millis() + TLONG; 192 else if (gotByte == SHORT) ttime = millis() + int(TSHORT/3); 193 194 while (millis() < ttime) { 195 digitalWrite(PINL2, 1); 196 } 197 digitalWrite(PINL2, 0); 198 } 199 } 200}
morse transceiver
arduino
Simply upload to Arduino Nano #1 with radioNumber = 0 and then to #2 with radioNumber = 1.
1/* 2 Nov 2017 - morse tranceiver by ppenguin 3 Based on below described. 4 5 Simple morse code transceiver using 2 nodes consisting of NRF24 transceiver, a push button 6 and a RGB led connected to an Arduino Nano. 7 Nice for 2 kids to each sit in a room and experiment with "the old days" morse code communication. 8 The LED will light green for outgoing code and red for incoming code (to have better feedback) 9 10 Removed most serial code (except debugging) to enable stand alone operation 11 12 Dec 2014 - TMRh20 - Updated 13 Derived from examples by J. Coliz <maniacbug@ymail.com> 14*/ 15/** 16 * Example for efficient call-response using ack-payloads 17 * 18 * This example continues to make use of all the normal functionality of the radios including 19 * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well. 20 * This allows very fast call-response communication, with the responding radio never having to 21 * switch out of Primary Receiver mode to send back a payload, but having the option to switch to 22 * primary transmitter if wanting to initiate communication instead of respond to a commmunication. 23 */ 24 25#include <SPI.h> 26#include "RF24.h" 27 28/****************** User Config ***************************/ 29/*** Set this radio as radio number 0 or 1 ***/ 30bool radioNumber = 1; 31 32/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ 33RF24 radio(9,10); // use mysensor default pins since I'm used to that 34/**********************************************************/ 35 // Topology 36byte addresses[][6] = {"1Node","2Node"}; // Radio pipe addresses for the 2 nodes to communicate. 37 38// Role management: Set up role. This sketch uses the same software for all the nodes 39// in this system. Doing so greatly simplifies testing. 40typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch 41const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles 42role_e role = role_pong_back; // The role of the current running sketch 43 44#define LONG 2 // value of morse long _ 45#define SHORT 1 // value of morse short . 46#define ACK 3 // value of ACK payload (necessary?) 47#define DELAY 10 // loop delay 48#define TLONG 250 // 250ms or longer is considered long 49#define TLONGE 800 // max long period 50#define TSHORT 170 // 170ms or shorter is considered short 51#define MAXFAIL 10 52 53#define PINBT 2 // digital input push button 54#define PINL1 3 // digital output LED1 55#define PINL2 4 // digital output LED2 56 57byte payload = 0; // A single byte as payload 58byte ackByte = ACK; 59bool btpressed = false; 60unsigned long lastpressed = 0; 61byte fail = 0; 62 63void setup(){ 64 65 66 Serial.begin(115200); 67 Serial.println(F("RF24/examples/GettingStarted_CallResponse")); 68 /* 69 Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); 70 */ 71 72 // Setup and configure radio 73 74 radio.begin(); 75 76 radio.enableAckPayload(); // Allow optional ack payloads 77 radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads 78 79 if(radioNumber){ 80 radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses 81 radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1 82 }else{ 83 radio.openWritingPipe(addresses[0]); 84 radio.openReadingPipe(1,addresses[1]); 85 } 86 radio.startListening(); // Start listening 87 88 radio.writeAckPayload(1,&ackByte,1); // Pre-load an ack-paylod into the FIFO buffer for pipe 1 89 //radio.printDetails(); 90 91 pinMode(PINBT, INPUT_PULLUP); // high == off, but now de don't need an external resistor for the button 92 pinMode(PINL1, OUTPUT); 93 pinMode(PINL2, OUTPUT); 94 95} 96 97void loop(void) { 98 99 /* loop initial/primary function is 100 (1) poll push button 101 (2) check whether msg received 102 If the push button was pushed and we have a result (either short or long) it is sent (role change) 103 */ 104 105 btpressed = !digitalRead(PINBT); // invert because we use internal pullup 106 if (btpressed && lastpressed == 0) { 107 lastpressed = millis(); // button first pressed after last release 108 Serial.print("Button down"); 109 digitalWrite(PINL1, 1); 110 } 111 112 if (!btpressed && lastpressed != 0) { // button release 113 Serial.print("Button release"); 114 digitalWrite(PINL1, 0); 115 if (millis() - lastpressed <= TSHORT) { 116 payload = SHORT; 117 Serial.print("Set payload SHORT"); 118 } else if ((millis() - lastpressed >= TLONG) && (millis() - lastpressed <= TLONGE)) { 119 payload = LONG; 120 Serial.print("Set payload LONG"); 121 } else { 122 payload = 0; 123 } 124 lastpressed = 0; 125 // role = role_ping_out; // we have data now, so we send it 126 } 127 128 129/****************** Ping Out Role ***************************/ 130 //if (role == role_ping_out){ // Radio is in ping mode 131 if (payload > 0) { // we only need to send if we have a payload 132 133 byte gotByte; // Initialize a variable for the incoming response (only for ACK) 134 135 radio.stopListening(); // First, stop listening so we can talk. 136 Serial.print(F("Now sending ")); // Use a simple byte counter as payload 137 Serial.println(payload); 138 139 unsigned long time = millis(); // Record the current millisecond count 140 141 if ( radio.write(&payload,1) ) { // Send payload to the other radio 142 /* if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank 143 Serial.print(F("Got blank response. round-trip delay: ")); 144 Serial.print(millis()-time); 145 Serial.println(F(" milliseconds")); 146 }else{ */ 147 while(radio.available() ){ // If an ack with payload was received 148 radio.read( &gotByte, 1 ); // Read it, and display the response time 149 unsigned long timer = millis(); 150 if (gotByte == ACK) { // only interested in ACK now 151 Serial.print(F("Got ACK response ")); 152 Serial.print(gotByte); 153 Serial.print(F(" round-trip delay: ")); 154 Serial.print(timer - time); 155 Serial.println(F(" milliseconds")); 156 break; // one ACK is enough, now continue listening 157 } 158 } 159 //} 160 payload = 0; // reset payload after sucessfuly sending 161 162 } else { 163 fail++; 164 if (fail >= MAXFAIL) { 165 fail = 0; 166 payload = 0; // give up and start listening 167 } 168 } 169 170 delay(DELAY); // Try again later 171 } 172 173 174/****************** Pong Back Role ***************************/ 175 // if ( role == role_pong_back ) { 176 if (payload == 0) { // nothing to send, so listen 177 radio.startListening(); 178 179 byte pipeNo, gotByte; // Declare variables for the pipe and the byte received 180 while( radio.available(&pipeNo)){ // Read all available payloads 181 digitalWrite(PINL2, 0); // default LED off 182 radio.read( &gotByte, 1 ); 183 // Since this is a call-response. Respond directly with an ack payload. 184 // Ack payloads are much more efficient than switching to transmit mode to respond to a call 185 radio.writeAckPayload(pipeNo,&ackByte, 1 ); // This can be commented out to send empty payloads. 186 Serial.print(F("sent ACK")); 187 188 // handle user output for received byte 189 Serial.println(gotByte); 190 unsigned long ttime = 0; 191 if (gotByte == LONG) ttime = millis() + TLONG; 192 else if (gotByte == SHORT) ttime = millis() + int(TSHORT/3); 193 194 while (millis() < ttime) { 195 digitalWrite(PINL2, 1); 196 } 197 digitalWrite(PINL2, 0); 198 } 199 } 200}
Downloadable files
morse transceiver
Fritzing bread board schematic for morse node.
morse transceiver
Comments
Only logged in users can leave comments
ppenguin
0 Followers
•1 Projects
1
1
Anonymous user
5 years ago
Thank you for this project! I just finished it and it is a lot of fun. I only changed the rgb led to two separate leds (red and blue). Next I will try do modify the code so one station continuously transmits a message (like a distress beacon) and try to test the range.