nRF24L01 + receiving loop

Dear All , i would like to create function that sends data over nRF24 to raspberry pi and if arduino receive answer then counter will be 0. Everything works good but .. if i have turned off program on raspberry , arduino take a loop and program suspends.
I have something wrong with procedure while .. i know. I would like to create comething like timeout, if for examle for 5 sec arduino didn't receive ansewer then it will try to send and reveive data again. Please help. Below my ugly code of sending function ;).

bool sendOverRadio() {
  radio.powerUp();
  uint16_t nodeID = pipes[0] & 0xff;
  char outBuffer[32]="Something to Send";
  char inBuffer[32]= "";
  int SendLoop ;
  int ReceiveLoop ;
  
  
  radio.stopListening();
  
  bool  isSend = false ;
  for (SendLoop = 0 ; SendLoop <= maxSendLoop; SendLoop++) {
    isSend =  radio.write( outBuffer, strlen(outBuffer));
    delay(35);
      if (isSend == true ) {
        Serial.print("sendloop : ");
        Serial.println(SendLoop);
        Serial.println("Send successful !"); 
        radio.startListening();
        
	unsigned long started_waiting_at = millis();
	bool timeout = false;
	while ( ! radio.available() && ! timeout ) {
		delay(10);
		if (millis() - started_waiting_at > 1500 )
			timeout = true;
                }
         if( timeout ){
		//If we waited too long the transmission failed
			Serial.println("Failed, response timed out.\n\r");
                        return false;
			
	}else {
		//If we received the message in time, let's read it and print it
		unsigned long got_time;
		//radio.read( &got_time, sizeof(unsigned long) );
                radio.read( inBuffer, strlen(outBuffer));
                Serial.println(inBuffer);
		Serial.print("Got response : ");
                Serial.println((got_time-started_waiting_at)/ 1000 );
	        return true;
	}
        } 
      else { 
        Serial.println("Send FAILED !");
        }
  }

I had this reply ready to send and it just vanished --- xkkjdjxjjxs!!!!!
Let's see if I can recreate it ...

You have an awful lot of stuff IFs, WHILEs and more IFs all chucked in together which makes it very difficult to see what should be happening or what is actually happening. Try something like this

void loop() {
    curMillis = millis();
    sendMessage();
    checkForReply();
}

void sendMessage() {
     if (messageToSend == true) {
          // code to send message
          sentMessageMillis = curMillis;
          messageToSend = false;
          replyReceived = 'L';  // means listening
    }
}

void checkForReply() {
   if (replyReceived != 'L') {
        return;
    }

    if (curMillis - sentMessageMillis >= timeoutMillis) {
        replyReceived = 'T'; // means timeout
        return;
    }

   // code to see if there is something available
   //    if there is
    //   get it
    replyReceiver = 'R';  // means reply received
}

...R

Hello Robin2 thanks for your fast replay. I have tried something like this .. .but i think that something is wrong ...
I can't get ( Timeout ) message is i turn off Receiver ap.. everytime i have curMillis - sentMessageMillis = 0 ;(
Below my code :wink: Thanks for answer

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 150;    // the debounce time; increase if the output flickers

unsigned long curMillis;  
unsigned long sentMessageMillis;
unsigned long timeoutMillis = 1500 ;

char replyReceived ; 

 
RF24 radio(9,10);
// Example below using pipe5 for writing
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0x7365727631LL };

 
void OnPulse()
{ 
    if ((millis() - lastDebounceTime) > debounceDelay) {
      lastDebounceTime = millis();
      sendMessage();
      checkForReply();
    }
}

void setup() 
{
 // pinMode(ledpin, OUTPUT); 
  attachInterrupt(1, OnPulse, CHANGE);
       
  radio.begin();
 
  radio.enableDynamicPayloads();
  radio.setAutoAck(1);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setChannel(70);
  radio.setRetries(15,15);
  radio.setCRCLength(RF24_CRC_8);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
}

void loop() 
{
 
}


void sendMessage() {

             radio.powerUp();
             uint16_t nodeID = pipes[0] & 0xff;
             char outBuffer[10]="Wyslano!";
             radio.stopListening();
             
             curMillis = millis();
             
             bool messageToSend = radio.write( outBuffer, strlen(outBuffer));
             
             if (messageToSend == true ) {
             sentMessageMillis = curMillis;
             messageToSend = false;
             replyReceived = 'L';  // means listening
             delay(15);
    }
}

void checkForReply() {
   char inBuffer[10];
   if (replyReceived != 'L') {
        return;
    }
    
    curMillis = millis();
    Serial.println(curMillis - sentMessageMillis );
    
    
    if (curMillis - sentMessageMillis >= timeoutMillis) {
        replyReceived = 'T'; // means timeout
        Serial.print("timeout");
        return;
    }

   // code to see if there is something available
    radio.startListening();
    radio.read( inBuffer, strlen(inBuffer));
    replyReceived = 'R';  // means reply received
    radio.stopListening();
    delay(20);
}

You can't call sendMessage() from an Interrupt Service Routine. ISRs muct be really really short. In your case it could probably set a variable called (say) readyToSend to true and then loop() would call sendMessage() which would only do anything if readyToSend == true.

Why are you using an interrupt at all?

I haven't studied any other parts of your code.

...R

Thanks for tip ;] i would like to use ISR to count pulses from kWh meter and sleeep for next interrupt. I would like to wake up radio for example only once per 10 pulses.

i would like to use ISR to count pulses from kWh meter and sleeep for next interrupt. I would like to wake up radio for example only once per 10 pulses.

In that case the ISR just adds 1 to a variable each time and sendMessage() (called from loop) only works when the count is 10 (or more) and when it sees a count of 10 it sets the counter back to 0.

I presume the kWh pulses don't happen all that fast.

...R

Dear Collegues please help me to find out what is wrong with my code with sleep mode :wink: i Would like to enter into sleep mode after sending message but it works only for 4-6 pulses after that program suspends :frowning:

#include <avr/sleep.h>
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
const long scaleConst = 1156.300 * 1000 ; // internalRef * 1023 * 1000;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 90;    // the debounce time; increase if the output flickers
int rpk = 1; 
int nodeID = 1; // Pierwsze urz?dzenie ;)
int msg[1] = {1};
int rec[1] = {5};
 
RF24 radio(9,10);
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0x7365727631LL };

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.enableDynamicPayloads();
  radio.setAutoAck(1);
  radio.enableAckPayload();
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setChannel(70);
  radio.setRetries(15,15);
  radio.setCRCLength(RF24_CRC_8);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  
  /* Setup the interrupt pin */
   attachInterrupt(1, OnPulse, FALLING);
  
  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode
}

void loop()
{
  //-------------------------------------------------------------
  // 1) Enter sleep mode
  //-------------------------------------------------------------
  cbi(ADCSRA,ADEN);    // switch Analog to Digital converter OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();

  // The arduino is now sleeping...
  
  //-------------------------------------------------------------
  // 2) Program will resume from here on interrupt
  //-------------------------------------------------------------
  sleep_disable();
  sbi(ADCSRA,ADEN);    // switch Analog to Digitalconverter ON
  
   
  delay(10);
}

void OnPulse()
{ 

  Serial.println("Pulse");
  delay(200);  
  rpk++;
  sendOverRadio(); 
  
}

bool sendOverRadio() {  
  char outBuffer[32]=""; 
  radio.powerUp();
  
  if (rpk >= 1000)
  rpk=1;
  
  delay(20);
  
  sprintf(outBuffer,"% 2X",nodeID);
  strcat(outBuffer,",");  
  
  char char_rpkLast[5];
  String string_rpkLast;
  string_rpkLast=String(rpk);
  string_rpkLast.toCharArray(char_rpkLast,5);
  strcat(outBuffer,char_rpkLast);
  
  strcat(outBuffer,","); 
  
  int vcc = readVccMv();
  char char_vcc[4];
  sprintf(char_vcc,"%d",vcc);
  strcat(outBuffer,char_vcc);
 
      radio.stopListening();
      delay(10);
      radio.write( outBuffer, strlen(outBuffer));
    //  delay(20);
      outBuffer[strlen(outBuffer)]=0;
        while(! radio.isAckPayloadAvailable())
        {
           radio.read(rec,sizeof(rec));
           if (rec[0] != 0) {
              Serial.print("ACK Payload : ");
              Serial.println(rec[0]);
              Serial.println(rec[1]);
              rec[0]=0;
              rec[1]=0; 
              return true ;
           }
            else {
         //    rpk++;
             Serial.println("No Ack in the AIR :(");
             return false;        
        }  
   
    }   
    radio.powerDown();     
}

int readVccMv() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif 

  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH 
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;
   
  result = scaleConst / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return int(result);
 
}
  /* Setup the interrupt pin */
   attachInterrupt(1, OnPulse, FALLING);

Well, it's perfectly obvious why you are enabling the interrupt pin, and what is going to be done when the pin goes LOW. Not!

void OnPulse()
{ 

  Serial.println("Pulse");
  delay(200);

The first two things that the interrupt service routine does are things that do not belong in interrupt service routines. The delay() function is waiting for the clock to tick a whole bunch of times. Notice the deafening silence, because the clock doesn't tick while your interrupt service routine is running.

There is REALLY nothing that your ISR needs to do. Every bit of the code in the ISR belongs in loop().

PaulS tahnk you , after your post i understand more ;] i did some changes and now it works.
Thanks a lot :wink: