getting false ackPayload back from receiver of nRF24L01+ ! help !

hello,
i am working on my final sketch of a small project which is:
i have a small RC car on which i installed a hall effect switch on the wheel so i can calculate the speed of the car, and i have 4 RED LEDs which will work like the knight rider effect connected to a shift register and the shift register to arduino, and another 4 Blue LEDs that simply go on or off on command and connected directly to arduino and of a module nRF24L01+ connected to arduino.
On the controller side, i have a module nRF24L01+ connected to arduino, 2 pushbuttons, 2 LEDs, and a crystal LCD. The LCD will give me the speed of the car and will print On or OFF when i click the push buttons. These push buttons will lights up the 4 red LEDs on the car or the blue LEDs.
i tested the hardware side, all works great, now when i uploaded the sketch i managed to make most of the things work, 2 small problems :
1 - i am not getting an ackPayload which has the speed value from the car on the controller side, Now i get a value but the value which should be 1 or 2 digits example 8 KM/H, instead i get 8254 KM/H, so i get 3 more digits after 1 seconds or around that which are not shown on the Serial Monitor, it first starts 0 KM/H or 1 digit and after 1 sec or around that i get 3 more digits !
here is a video which i uploaded that shows the problem - YouTube

2 - when i turn the red LEDs off, they have a small delay until the for loop() in my codes finished (that's how i explained it so far :/)

3 - the speed starts at 0 but when i stop throttle, it doesn't go back to 0, instead it gives me 2 or 3

i have spent hours tested and experimented with the codes but i couldn't figure out what is going wrong :confused: so i need some help please

here are the codes and thanks for everyone in advance :

Transmitter, Controller side

/*December 9, 2015
RC car speedometer and display screen, Controller sketch, mainly considered a Transmitter 
-------------------------------------- By Firas Helou -------------------------------------

RF Module used : nRF24L01+

*/

//the RF24 for the RF Module Library
#include  <SPI.h>
#include <RF24.h>
#include <LiquidCrystal.h> //LCD Library

int msgTX[3]; //Message to be transmitted, can contain up to 3 array elements, 3 bytes
int ackMessage[1]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

//Defining radio object for the RF24 function
RF24 radio(9,10);

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

//INDICATOR LEDs of the controller
const byte Red_LED = 2; //Top LEDs ON/OFF indicator
const byte Blue_LED = 4; //Bottom LEDs ON/OFF indicator

//PUSH BUTTONS
const byte RedLEDs_Button = 6; //Push Button that turns the Top red LEDs on
const byte BlueLEDs_Button = 7; //Push Button that turns the Bottom blue LEDs on

boolean lastRedLED = LOW;
boolean currentRedLED = HIGH;
boolean RedLEDOn = false;

boolean lastBlueLED = LOW;
boolean currentBlueLED = HIGH;
boolean BlueLEDOn = false;

boolean valRedLEDButton = 0;  
boolean valBlueLEDButton = 0;

//SPEED value
unsigned long Speed = 0;

//LCD PINS
const byte LCD_RS = 3;
const byte LCD_Enable = 5;
const byte LCD_D4 = 8;
const byte LCD_D5 = A0;
const byte LCD_D6 = A1;
const byte LCD_D7 = A2;

//Defining LCD pins 
LiquidCrystal lcd(LCD_RS, LCD_Enable, LCD_D4, LCD_D5, LCD_D6, LCD_D7); //defining the LCD pins

//LCD letter O
byte letter_O[8] = { 
 0b01110,
 0b10001,
 0b10001,
 0b10001,
 0b10001,
 0b10001,
 0b01110,
 0b00000
};

//LCD letter N
byte letter_N[8] = {
 0b10001,
 0b10001,
 0b11001,
 0b10101,
 0b10011,
 0b10001,
 0b10001,
 0b00000
};

//LCD letter F
byte letter_F[8] = {
 0b11111,
 0b10000,
 0b10000,
 0b11110,
 0b10000,
 0b10000,
 0b10000,
 0b00000
};

//LCD empty
byte empty[8] = {
 0b00000,
 0b00000,
 0b00000,
 0b00000,
 0b00000,
 0b00000,
 0b00000,
 0b00000
};


//VOID SETUP()
void setup()
{
    Serial.begin(9600);
    lcd.createChar(0,letter_O); // define our characters into the sketch as variables
    lcd.createChar(1,letter_N);
    lcd.createChar(2,letter_F);
    lcd.createChar(3,empty);
    // set up the LCD's number of columns and rows: 
    lcd.begin(16, 2);
    
    lcd.setCursor(3, 0);
    lcd.print("KM/H:");
    
    pinMode( RedLEDs_Button, INPUT_PULLUP ); //RedLeds Button
    pinMode( BlueLEDs_Button, INPUT_PULLUP ); //BlueLeds Button
    pinMode( Red_LED, OUTPUT ); //Red Led indicator Top LEDs
    pinMode( Blue_LED, OUTPUT ); //Blue Led indicator Bottom LEDs
    
    
    //radio start
    radio.begin();  
    radio.setDataRate(dataRate); //Giving the data rate speed
    radio.enableAckPayload(); //enables receiving data from receiver side
  
}

//DEBOUNCING FUNCTION
boolean debounce(boolean last, int button)
{
    boolean current = digitalRead(button);
    if(last != current)
    {
      delay(5);
      current = digitalRead(button);
    }
    return current;
}

//MAIN LOOP FUNCTION
void loop()
{
  
    LCD_Display_Function();
    getPushButtonStates(); 
    DataTransmission();
    AcknowledgmentDATA();
    
    Serial.println(ackMessage[0]);
  
}

//FUNCTION that takes care of the Push Buttons
void getPushButtonStates()
{
    currentRedLED = debounce(lastRedLED, RedLEDs_Button);
    currentBlueLED = debounce(lastBlueLED, BlueLEDs_Button);
    
    //For the BLUE LEDs button
    if(lastRedLED == HIGH && currentRedLED == LOW){
      
      RedLEDOn = !RedLEDOn;
      //valRedLEDButton = 1;
      
    }
    
      
    lastRedLED = currentRedLED;
    digitalWrite(Red_LED, RedLEDOn);  
    
    //For the RED LEDs button
    if(lastBlueLED == HIGH && currentBlueLED == LOW)
    {
    
        BlueLEDOn = !BlueLEDOn;
        valBlueLEDButton = !valBlueLEDButton;
        
    }
      
    lastBlueLED = currentBlueLED;
    digitalWrite(Blue_LED, BlueLEDOn);
  
  
}

//Function that takes care of the LCD display
void LCD_Display_Function()
{
    lcd.setCursor(0, 1);
    lcd.print("T-L:");
    
    //For the Red LED
    if(RedLEDOn == HIGH)
    {
      //TopLed = "ON ";
      lcd.setCursor(4, 1);
      lcd.write(3);
      lcd.setCursor(5, 1);
      lcd.write((byte)0);
      lcd.setCursor(6,1);
      lcd.write(1);
      
    }else if(RedLEDOn == LOW){
      
      //TopLed = "OFF";
      lcd.setCursor(4, 1);
      //lcd.print(TopLed);
      lcd.write((byte)0);
      lcd.setCursor(5,1);
      lcd.write(2);
      lcd.setCursor(6,1);
      lcd.write(2);
      
    }
    
    //For the Blue LED
    lcd.setCursor(9, 1);
    lcd.print("B-L:");
    if(BlueLEDOn == HIGH)
    {
      //BottomLed = "ON";
      lcd.setCursor(13, 1);
      lcd.write(3);
      lcd.setCursor(14, 1);
      
      lcd.write((byte)0);
      lcd.setCursor(15,1);
      lcd.write(1);
      
    }else if(BlueLEDOn == LOW){
      
      lcd.setCursor(13, 1);
      lcd.write((byte)0);
      lcd.setCursor(14,1);
      lcd.write(2);
      lcd.setCursor(15,1);
      lcd.write(2);
      
    }
    
    //Prints the Speed Value on the LCD
    lcd.setCursor(10, 0);
    lcd.print(Speed);
  
}

//DATA Transmission Function
void DataTransmission(){
  
    if(RedLEDOn == HIGH) {
      
        radio.openWritingPipe(pipe); //Opens Pipe 0 for Writing
        valRedLEDButton = 1;
        msgTX[0] = valRedLEDButton;
    
    }else{
    
        radio.openWritingPipe(pipe); //Opens Pipe 0 for Writing
        valRedLEDButton = 0;
        msgTX[0] = valRedLEDButton; 
    
    }
    
    if(BlueLEDOn == HIGH){
      
        radio.openWritingPipe(pipe);
        valBlueLEDButton = 1;
        msgTX[1] = valBlueLEDButton;
    
    }else{
        
        radio.openWritingPipe(pipe);
        valBlueLEDButton = 0;
        msgTX[1] = valBlueLEDButton;
    
    
    }
    
    radio.write(msgTX, sizeof(msgTX)); //Sends the Data
  
}

//DATA Receiving from the Receiver part, Acknowledgment Data
void AcknowledgmentDATA(){
    
    if ( radio.isAckPayloadAvailable() ){
 radio.read(ackMessage, sizeof(ackMessage));

 ackMessage[0] = Speed ;
        //delay(5);

   }else{
       Serial.println("No connection is made");
   }
  
}

and this is the Receiver, Car side in the first comment

Receiver

/*December 9, 2015
RC car speedometer and display screen, Car sketch, mainly considered a Receiver 
-------------------------------------- By Firas Helou -------------------------------------

RF Module used : nRF24L01+

*/

//the RF24 for the RF Module Library
#include  <SPI.h>
#include <RF24.h>

int msgRX[3]; //Message to be transmitted, can contain up to 3 array elements, 3 bytes
int ackMessage[1]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

//Defining radio object for the RF24 function
RF24 radio(9,10);

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

//Hall Effect Sensor Pin
byte Hall_Effect_Pin = 2;

//Defining the Shift Register Data and patterns
byte latchPin = 4;
byte clockPin = 5;
byte dataPin = 6;

byte serialbit;
byte pickabit;
byte intensitybyte;
byte dwellReps;  // fewer dwellReps == faster
byte line;

byte leds = B00000000;

byte frame [9][8] = {
                      {0b00000001,0,0,0,0,0,0,0},
                      {0b00000001,0b00000010,0,0,0,0,0,0},
                      {0b00000001,0b00000010,0b00000011,0,0,0,0,0},
                      {0,0b00000001,0b00000010,0b00000011,0,0,0,0},
                      {0,0,0b00000001,0b00000010,0,0,0,0},
                      {0,0,0,0b00000011,0,0,0,0},
                      {0,0,0b00000011,0b00000010,0,0,0,0},
                      {0,0b00000011,0b000000010,0b00000001,0,0,0,0},
                      {0b00000010,0b00000001,0,0,0,0,0,0}
                      
                      
                    };

byte intensity [20] = {0b00111110,0b00111100,0b00111100,0b00111100,
                       0b00111000,0b00111000,0b00111000,0b00111000,
                       0b00111000,0b00110000,0b00100000,0b00100000,
                       0b00100000,0b00100000,0b00100000,0b00100000,
                       0b00100000,0b00100000,0b00100000,0b00100000
                     };

//SPEEDOMETER Data Definition
//we multiplied the radius 15mm by 100 and the Pi 3.1416 value by 10000 for more precision
const unsigned long wheel_perimeter = 1500UL * 2UL * 31416UL; // = 94,248,000, radius * 2 * pi, 'UL' to force the constant into an unsigned long constant

unsigned long Speed = 0;
unsigned long PrevSpeed = 0;
//unsigned long distance = 0;

volatile byte hall_rising = 0; // interrupt flag
volatile unsigned long irqMicros;

unsigned long startMicros;
unsigned long differenceTimeMicros;

unsigned long hallEffectCount = 0;
//unsigned long distance = 0;

//Top Red LEDs state
boolean valRedLEDButton = false;  
//Bottom Blue LEDs state
boolean valBlueLEDButton = false;

byte BlueLED1 = 3;
byte BlueLED2 = 7;
byte BlueLED3 = 8;
byte BlueLED4 = A0;

void wheel_IRQ()
{
  //IRQ Function for the interrupt
  irqMicros = micros();
  hall_rising = 1;
  hallEffectCount++;
}

//VOID SETUP()
void setup()
{
    Serial.begin(9600);
    pinMode( Hall_Effect_Pin, INPUT );  
  
    pinMode( BlueLED1, OUTPUT ); //RedLeds Button
    pinMode( BlueLED2, OUTPUT ); //BlueLeds Button
    pinMode( BlueLED3, OUTPUT ); //Red Led indicator Top LEDs
    pinMode( BlueLED4, OUTPUT ); //Blue Led indicator Bottom LEDs
    
    pinMode( latchPin, OUTPUT );
    pinMode( clockPin, OUTPUT );
    pinMode( dataPin, OUTPUT );
    
    //radio start
    radio.begin();
    radio.setDataRate(RF24_250KBPS);
    radio.enableAckPayload();
    radio.openReadingPipe(1,pipe); 
    radio.startListening(); 
    
    //0 for pin 2 or in out case we called it Hall_Effect_Pin and we define any pin we need
    attachInterrupt( 0, wheel_IRQ, FALLING ); // pin 2 looks for LOW to HIGH change
    
  
}

//void Main loop()
void loop(){

    calculateSPEED();
    ReceiveAndAckData();
    //LED_Function();
    Serial.println(Speed);
    //Serial.println(valRedLEDButton);
    
}

//SPEEDOMETER Function
void calculateSPEED(){
  
    while(hall_rising == 1){
      differenceTimeMicros = irqMicros - startMicros;
      startMicros = irqMicros;
      hall_rising = 0;
    }
    
    //distance = (wheel_perimeter * hallEffectCount)/1000000000; //distance in meters
    if( differenceTimeMicros != 0 ){
        Speed =  wheel_perimeter / differenceTimeMicros; //speed = distance / time
        Speed = (Speed*3600)/1000000; // this converts the speed from mm/s to Km/h
        
    
    }else{
      
        Speed = 0;
        hallEffectCount = 0;
        
    }
    
    PrevSpeed = Speed;
    
}

//Receive Data function
void ReceiveAndAckData(){
    
    ackMessage[0] = Speed;
    //Serial.println(Speed);
    radio.writeAckPayload(1, ackMessage, sizeof(ackMessage));
    
    while (radio.available()){  
       
       radio.read(msgRX, sizeof(msgRX));    
       
       if(msgRX[0] == 1){
         
           valRedLEDButton = true;
           
       }else if(msgRX[0] == 0){
         
           valRedLEDButton = false;
           
       }
       
       if(msgRX[1] == 1){
         
           valBlueLEDButton = true;
           
       }else if(msgRX[1] == 0){
         
           valBlueLEDButton = false;
           
       }
       
       LED_Function();
       //delay(10);
    }
  
}

//Function that takes care of the Top Red LEDs with shift register
void LED_Function(){
    
    if(valRedLEDButton == true){
      //Serial.println(valRedLEDButton);
      for(line=0; line<9; line++){
        
        for(dwellReps=0; dwellReps<45; dwellReps++)
        // fewer dwellReps == faster  
        {
          
          for(intensitybyte=0; intensitybyte<20; intensitybyte++)
          {
            for (pickabit=0; pickabit<8; pickabit++)
            {
              serialbit = bitRead(intensity[intensitybyte],frame[line][pickabit]);
              digitalWrite(dataPin,serialbit);
              clockit();
            }
            
            latchit();
          
          } // end of third for loop
        } // end of second for loop
      } // end of first for loop
    
    }
    else{
    
        digitalWrite(latchPin, LOW);
        shiftOut(dataPin, clockPin, LSBFIRST, leds);
        digitalWrite(latchPin, HIGH);
      
    }
    /*Serial.print("valRedLEDButton ");
    Serial.println(valRedLEDButton);
    Serial.print("valBlueLEDButton ");
    Serial.println(valBlueLEDButton);
    */
    
    if(valBlueLEDButton == true){
    
      digitalWrite(BlueLED1, HIGH);
      digitalWrite(BlueLED2, HIGH);
      digitalWrite(BlueLED3, HIGH);
      digitalWrite(BlueLED4, HIGH);
      
    }else{
      
      digitalWrite(BlueLED1, LOW);
      digitalWrite(BlueLED2, LOW);
      digitalWrite(BlueLED3, LOW);
      digitalWrite(BlueLED4, LOW);
      
    }
  
}

void clockit ()
{
  digitalWrite(clockPin,HIGH);
  digitalWrite(clockPin,LOW); 
}  

void latchit ()
{
  digitalWrite(latchPin,HIGH);  // make a function
  digitalWrite(latchPin,LOW);   // make a function  
}

This debounce function blocks execution for 5 ms every time the button changes state.

//DEBOUNCING FUNCTION
boolean debounce(boolean last, int button)
{
    boolean current = digitalRead(button);
    if(last != current)
    {
      delay(5);
      current = digitalRead(button);
    }
    return current;
}

It also assumes that the button will be at rest in 5 ms which is generally not guaranteed.

I have a button library that returns one of 5 possible button states while tracking pin states.
state : meaning
-1 : button is unstable
0 : button state unchanged, is not pressed
1 : button state changed, is now pressed
2 : button state changed, is now released
3 : button state unchanged, is pressed

The debounce code watches the pin to stop bouncing for a time longer than test-bounces for the buttons used. I have seen an article where crap buttons were said to bounce almost 20 ms! I watch the bounce grounding jumpers on the USB connector housing and watch for no change for 2 ms and that works, the contacts may bounce back and forth much longer but the changes come less than 2 ms apart when it does so 2 ms same pin state is a stable read to my code.
I have one sketch that I use just to time bounces, the majority are less than 1 ms long but some are bit more. I time them in microseconds, the code can see a bounce down to about 12 usecs short.

If you're going to put a delay(5) in, it's not like you're using those 80000 cpu cycles for anything so why not watch the pin instead of look the other way the whole time?

GoForSmoke:
This debounce function blocks execution for 5 ms every time the button changes state.

It also assumes that the button will be at rest in 5 ms which is generally not guaranteed.

I have a button library that returns one of 5 possible button states while tracking pin states.
state : meaning
-1 : button is unstable
0 : button state unchanged, is not pressed
1 : button state changed, is now pressed
2 : button state changed, is now released
3 : button state unchanged, is pressed

The debounce code watches the pin to stop bouncing for a time longer than test-bounces for the buttons used. I have seen an article where crap buttons were said to bounce almost 20 ms! I watch the bounce grounding jumpers on the USB connector housing and watch for no change for 2 ms and that works, the contacts may bounce back and forth much longer but the changes come less than 2 ms apart when it does so 2 ms same pin state is a stable read to my code.
I have one sketch that I use just to time bounces, the majority are less than 1 ms long but some are bit more. I time them in microseconds, the code can see a bounce down to about 12 usecs short.

If you're going to put a delay(5) in, it's not like you're using those 80000 cpu cycles for anything so why not watch the pin instead of look the other way the whole time?

well since i learned it from Jeremy Blum, i save it and kept using it,
so what do you mean i must make it less than 5 ms or what exactly ? :confused:

Blum's okay but that button debouncer has limited use, the only saving grace is that the button can't be changing state often enough to be a major pain.

// ASSUMPTION-BASED DEBOUNCING FUNCTION MADE NON-BLOCKING
boolean debounce(boolean last, int button)
{
  static byte tStart = 0, tWait = 0; // yes, single byte time variables to count 5 ms difference.

  if ( tWait == 0 )
  {
    boolean current = digitalRead(button);

    if (last != current)
    {
      tWait = 5; // set up the timer
      tStart = (byte)( millis() & 255 );
    }

    return last;
  }
  else
  {
    if ((byte)( millis() & 255 ) - tStart < tWait ) // run the timer
    {
      return last; // time is not up, return the last known state
    }
    else
    { 
      current = digitalRead(button);
      tWait = 0; // wait for next button change
    }
  }

  return current;
}

firashelou:
well since i learned it from Jeremy Blum, i save it and kept using it,
so what do you mean i must make it less than 5 ms or what exactly ? :confused:

Probably nothing worse than learning to write limiting code. You might start thinking that a delay(1) cannot make a timing problem and find out that called often enough it will dominate what otherwise would be very very fast code.

I have a program that watches 4 buttons, counts repetitions of loop() and blinks led13. With those it runs loop() an average of over 57000 times per second. I add delay(1) to that loop() and it runs 980 times per second.
What happens is that the small number of cycles the buttons and led use is completely overbalaced by the 16000 cycles that delay(1) wastes.

Lesson is to not use blocking code. Every new way you have to get around blocking is a trick for your bag. Being lazy is a good way to end up mediocre or less.

firashelou:
Receiver

In the Receiver code the lines with radio.writeAckPayload() all seem to be commented out - is that the cause of the problem?

If not please post the correct code.

...R

GoForSmoke:
Probably nothing worse than learning to write limiting code. You might start thinking that a delay(1) cannot make a timing problem and find out that called often enough it will dominate what otherwise would be very very fast code.

I have a program that watches 4 buttons, counts repetitions of loop() and blinks led13. With those it runs loop() an average of over 57000 times per second. I add delay(1) to that loop() and it runs 980 times per second.
What happens is that the small number of cycles the buttons and led use is completely overbalaced by the 16000 cycles that delay(1) wastes.

Lesson is to not use blocking code. Every new way you have to get around blocking is a trick for your bag. Being lazy is a good way to end up mediocre or less.

thanks a lot for your info GoForSmoke, so what is the solution in this case ? using a time delay like the hall effect ?
like this for example ?

//DEBOUNCING FUNCTION
boolean debounce(boolean last, int button)
{
    unsigned long previousTime;
    unsigned long currentTime = millis();
    const unsigned long gap = 5;
    boolean current = digitalRead(button);
    if(last != current)
    {
      if(currentTime - previousTime == gap){
      //delay(1);
        current = digitalRead(button);
      }
    }
    return current;
}

Robin2:
In the Receiver code the lines with radio.writeAckPayload() all seem to be commented out - is that the cause of the problem?

If not please post the correct code.

...R

oops, no it's not the problem in the IDE i have it right, i must have commented it by mistake, i corrected it now

i get data now but like you see in the video after couple of throttle, the 3 more digits pops up, that what i couldn't tell what is it !

Debugging wireless stuff can be very tedious. You need to make the very simplest program you can that just sends a message and receives an ack payload and displays it to the Serial Monitor.

I have a working program, but I need to make a few changes before posting it here. Hopefully I will get that done later today.

...R

Robin2:
Debugging wireless stuff can be very tedious. You need to make the very simplest program you can that just sends a message and receives an ack payload and displays it to the Serial Monitor.

I have a working program, but I need to make a few changes before posting it here. Hopefully I will get that done later today.

...R

thanks Robin yes i did that i simply tried to get the value and serial.printed for example ackMessage[0] = value1; Serial.println(value1);

will be good to check it, you really make great sketches, it's not easy as well but seems perfect to me, about the last sketch you shared i think you choose channel to lock right ?
then you check if a connection happened and data received, this can be helpful on an RC car to apply the brakes if the connection was lost

The pair of programs below have just been working for me - one on a Mega and one on an Uno.

Note that a small modification is needed in the file RF24.cpp in the RF24 library. Towards the end of the write() function there are two lines (they are lines 499 and 500 in my copy).

 // Power down
  powerDown();

The second of these needs to be commented out so that there is no call to the powerDown() function.

Without that change I found that the code would not work with an interval between write()s greater than about 10 millisecs.

Master

// TrackControl - the master or the transmitter

// http://maniacbug.github.io/RF24/classRF24.html
 //~ - CONNECTIONS: nRF24L01 Modules See:
 //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
 //~ 1 - GND
 //~ 2 - VCC 3.3V !!! NOT 5V
 //~ 3 - CE to Arduino pin 9
 //~ 4 - CSN to Arduino pin 10
 //~ 5 - SCK to Arduino pin 13
 //~ 6 - MOSI to Arduino pin 11
 //~ 7 - MISO to Arduino pin 12
 //~ 8 - UNUSED

#include <SPI.h>
//~ #include <nRF24L01.h>
//~ #include <RF24.h>
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/nRF24L01mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.cpp"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24_config_mod.h"


#define CE_PIN   9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type
// These are the IDs of each of the slaves
const uint64_t deviceID[] = {0xE8E8F0F0E1LL, 0xE8E8F0F0E2LL};
byte numSlaves = 2;

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

int dataToSend[2];

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;
int txVal = 0;
int ackMessg[4];
byte ackMessgLen = 2;


void setup() {

 Serial.begin(9600);
 Serial.println("Track Control Starting");
 radio.begin();
 radio.setDataRate( RF24_250KBPS );
 radio.enableAckPayload();
 radio.setRetries(3,5); // delay, count
}

//====================

void loop() {

 currentMillis = millis();
 if (currentMillis - prevMillis >= txIntervalMillis) {
 for (byte n = 0; n < numSlaves; n++) {
 radio.openWritingPipe(deviceID[n]); // calls each slave in turn
 dataToSend[0] = txVal; // this gets incremented so you can see that new data is being sent
 txVal += 1;
 dataToSend[1] = txVal;
 txVal += 1;
 bool rslt;
 unsigned long start = micros();
 rslt = radio.write( dataToSend, sizeof(dataToSend) );
 unsigned long end = micros();
 Serial.print("Write Micros ");
 Serial.print(end - start);
 Serial.print(" RSLT ");
 Serial.println(rslt);
 Serial.print("\nData Sent ");
 Serial.print(dataToSend[0]);
 Serial.print(" To ");
 Serial.println(n);
 if ( radio.isAckPayloadAvailable() ) {
 radio.read(ackMessg,ackMessgLen);
 Serial.print("Acknowledge received: ");
 Serial.println(ackMessg[0]);
 }
 }
 prevMillis = millis();
 }
}

Slave

// HandController - the slave or the receiver

// http://maniacbug.github.io/RF24/classRF24.html
 //~ - CONNECTIONS: nRF24L01 Modules See:
 //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
 //~ 1 - GND
 //~ 2 - VCC 3.3V !!! NOT 5V
 //~ 3 - CE to Arduino pin 9
 //~ 4 - CSN to Arduino pin 10
 //~ 5 - SCK to Arduino pin 13
 //~ 6 - MOSI to Arduino pin 11
 //~ 7 - MISO to Arduino pin 12
 //~ 8 - UNUSED

#include <SPI.h>
//~ #include <nRF24L01.h>
//~ #include <RF24.h>
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/nRF24L01mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.cpp"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24_config_mod.h"

#define CE_PIN   9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type

const uint64_t   deviceID = 0xE8E8F0F0E1LL; // Define the ID for this slave
//~ const uint64_t   deviceID = 0xE8E8F0F0E2LL; 
int valChange = 1; 

RF24 radio(CE_PIN, CSN_PIN);

int dataReceived[2];  
int ackData[2] = {12,0};
byte ackLen = 2;

void setup() {
 
 Serial.begin(9600);
 delay(1000);
 Serial.println("Hand Controller Starting");
 radio.begin();
 radio.setDataRate( RF24_250KBPS );
 radio.openReadingPipe(1,deviceID);
 radio.enableAckPayload();
 radio.writeAckPayload(1, ackData, ackLen);
 radio.startListening();
}

void loop() {
 
 if ( radio.available() ) {
 bool done = false;
 done = radio.read( dataReceived, sizeof(dataReceived) );
 Serial.print("Data0 ");
 Serial.print(dataReceived[0]);
 Serial.print(" Data1 ");      
 Serial.println(dataReceived[1]);
 radio.writeAckPayload(1, ackData, ackLen);
 ackData[0] += valChange; // this just increments so you can see that new data is being sent
 }
}

Hope this is not too confusing.

...R
You would not believe how much time it takes to "undo" changes that I had made a piece at a time so that this example would work with a near-to-original library

firashelou:
thanks a lot for your info GoForSmoke, so what is the solution in this case ? using a time delay like the hall effect ?
like this for example ?

//DEBOUNCING FUNCTION

boolean debounce(boolean last, int button)
{
    unsigned long previousTime;
    unsigned long currentTime = millis();
    const unsigned long gap = 5;
    boolean current = digitalRead(button);
    if(last != current)
    {
      if(currentTime - previousTime == gap){
      //delay(1);
        current = digitalRead(button);
      }
    }
    return current;
}

That won't work. As soon as last != current the time will not be up. Next time it runs last will be == current so the time check will not run until the pin state changes.

currentTime - previousTime == gap, if it doesn't catch the exact time == gap it will keep running.
That is why we use (now - start >= timeout) or (now - start < timeout), it works even if a bit late or early.

That's why I arranged that last example the way I did. It runs different depending on what has happened and is happening. When it is doing time checks the state of the button is no matter. I only unblocked the delay(), I didn't do a total debounce function fix, it still works on assumption.

The debounce function you started with is really a button state checker. Note if the pin state has not changed, it does nothing but return the pin state. If the state changes, the code stops for delay(5) then reads the pin and returns that.
What I did was to make it return the last known state until the 5 ms is up and let the rest of the sketch and more you may want to add later have those cycles to make their tasks go instead of wasting them doing nothing.

Robin2:
The pair of programs below have just been working for me - one on a Mega and one on an Uno.

Note that a small modification is needed in the file RF24.cpp in the RF24 library. Towards the end of the write() function there are two lines (they are lines 499 and 500 in my copy).

 // Power down

powerDown();



The second of these needs to be commented out so that there is no call to the powerDown() function.

Without that change I found that the code would not work with an interval between write()s greater than about 10 millisecs.

Master


// TrackControl - the master or the transmitter

// RF24: RF24 Class Reference
//~ - CONNECTIONS: nRF24L01 Modules See:
//~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
//~ 1 - GND
//~ 2 - VCC 3.3V !!! NOT 5V
//~ 3 - CE to Arduino pin 9
//~ 4 - CSN to Arduino pin 10
//~ 5 - SCK to Arduino pin 13
//~ 6 - MOSI to Arduino pin 11
//~ 7 - MISO to Arduino pin 12
//~ 8 - UNUSED

#include <SPI.h>
//~ #include <nRF24L01.h>
//~ #include <RF24.h>
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/nRF24L01mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.cpp"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24_config_mod.h"

#define CE_PIN  9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type
// These are the IDs of each of the slaves
const uint64_t deviceID[] = {0xE8E8F0F0E1LL, 0xE8E8F0F0E2LL};
byte numSlaves = 2;

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

int dataToSend[2];

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000;
int txVal = 0;
int ackMessg[4];
byte ackMessgLen = 2;

void setup() {

Serial.begin(9600);
Serial.println("Track Control Starting");
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.enableAckPayload();
radio.setRetries(3,5); // delay, count
}

//====================

void loop() {

currentMillis = millis();
if (currentMillis - prevMillis >= txIntervalMillis) {
for (byte n = 0; n < numSlaves; n++) {
radio.openWritingPipe(deviceID[n]); // calls each slave in turn
dataToSend[0] = txVal; // this gets incremented so you can see that new data is being sent
txVal += 1;
dataToSend[1] = txVal;
txVal += 1;
bool rslt;
unsigned long start = micros();
rslt = radio.write( dataToSend, sizeof(dataToSend) );
unsigned long end = micros();
Serial.print("Write Micros ");
Serial.print(end - start);
Serial.print(" RSLT ");
Serial.println(rslt);
Serial.print("\nData Sent ");
Serial.print(dataToSend[0]);
Serial.print(" To ");
Serial.println(n);
if ( radio.isAckPayloadAvailable() ) {
radio.read(ackMessg,ackMessgLen);
Serial.print("Acknowledge received: ");
Serial.println(ackMessg[0]);
}
}
prevMillis = millis();
}
}




Slave


// HandController - the slave or the receiver

// RF24: RF24 Class Reference
//~ - CONNECTIONS: nRF24L01 Modules See:
//~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
//~ 1 - GND
//~ 2 - VCC 3.3V !!! NOT 5V
//~ 3 - CE to Arduino pin 9
//~ 4 - CSN to Arduino pin 10
//~ 5 - SCK to Arduino pin 13
//~ 6 - MOSI to Arduino pin 11
//~ 7 - MISO to Arduino pin 12
//~ 8 - UNUSED

#include <SPI.h>
//~ #include <nRF24L01.h>
//~ #include <RF24.h>
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/nRF24L01mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.h"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24mod.cpp"
#include "/mnt/sdb1/SGT-Docs/ModelRailways/NRF24Control/BasicWorkingVersionForum/RF24_config_mod.h"

#define CE_PIN  9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type

const uint64_t  deviceID = 0xE8E8F0F0E1LL; // Define the ID for this slave
//~ const uint64_t  deviceID = 0xE8E8F0F0E2LL;
int valChange = 1;

RF24 radio(CE_PIN, CSN_PIN);

int dataReceived[2]; 
int ackData[2] = {12,0};
byte ackLen = 2;

void setup() {

Serial.begin(9600);
delay(1000);
Serial.println("Hand Controller Starting");
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.openReadingPipe(1,deviceID);
radio.enableAckPayload();
radio.writeAckPayload(1, ackData, ackLen);
radio.startListening();
}

void loop() {

if ( radio.available() ) {
bool done = false;
done = radio.read( dataReceived, sizeof(dataReceived) );
Serial.print("Data0 ");
Serial.print(dataReceived[0]);
Serial.print(" Data1 ");     
Serial.println(dataReceived[1]);
radio.writeAckPayload(1, ackData, ackLen);
ackData[0] += valChange; // this just increments so you can see that new data is being sent
}
}




Hope this is not too confusing.

...R
*You would not believe how much time it takes to "undo" changes that I had made a piece at a time so that this example would work with a near-to-original library*

thank you Robin, so i must change the RF24 lines you told me, so that my example would work too ?

about your sketches, so i save these ones instead of the others you shared last time ?

GoForSmoke:
That won't work. As soon as last != current the time will not be up. Next time it runs last will be == current so the time check will not run until the pin state changes.

currentTime - previousTime == gap, if it doesn't catch the exact time == gap it will keep running.
That is why we use (now - start >= timeout) or (now - start < timeout), it works even if a bit late or early.

That's why I arranged that last example the way I did. It runs different depending on what has happened and is happening. When it is doing time checks the state of the button is no matter. I only unblocked the delay(), I didn't do a total debounce function fix, it still works on assumption.

The debounce function you started with is really a button state checker. Note if the pin state has not changed, it does nothing but return the pin state. If the state changes, the code stops for delay(5) then reads the pin and returns that.
What I did was to make it return the last known state until the 5 ms is up and let the rest of the sketch and more you may want to add later have those cycles to make their tasks go instead of wasting them doing nothing.

i corrected the == to >= and i tried it and it worked
i did not understand which part exactly won't work ?

the problems that are happening overall now are:

1 - when i start the LCD, it gives SPEED : ---- 0KM/H, when i push the throttle it goes up from 0 to 13KM/H, the first digit stays in the same position but the KM/H goes up 1 column to keep space for the second digit starting from 10 + . But when i release the throttle and the wheels stop turning, the SPEED get down but never to 0 ! it's always 2 or 3 or 4, and it has a 0 as a second digit ! I need please to know what should be done here ? i have searched in the field of the LCD library and read the documentation to see if it has some function to clear a column but so far did not find anything, instead it has the functions to clear the LCD or returns home for first text :confused:

2 - when i click the red pushbutton, the RED LEDs starts to go back and forth making the knight rider pattern but when i click the red push button again to turn these LEDs off, the LEDs doesn't go off immediately, it keeps running back and forth until the for loop finishes out then the LEDs goes off ! these is affecting the Blue LEDs too if the RED are running and i turned them off, the blue can't turn on or off until the RED turns off, so i can't find away to do it ! can you please give me some clue or guidance for this :confused:

The way that Blum has the debounce() function,

if there is no pin state change since last check it returns the pin state but if there is a change :

it stops the sketch for 5 ms assumed to let the button settle. And the function only returns after then with the pin state.

when I unblocked it, I changed how it works. Now it returns the last pin state during those 5 ms every time it is called until the 5 ms are up. In that time, this function may run hundreds of times and not read (did I get that part done?) let alone return the possibly changing pin state (contact bounce) but the last stable state instead. Then when time is up, assume the pin is stable and read it as the state.
Even after the initial pin state change is detected, this routine keeps getting exited and re-entered as long as something like loop() calls it. It cannot do this if the time check only runs when the pin state changes as you have coded. The time check depends on pin state change but that only happens once and the time check needs to happen for 5 ms. Putting the time check inside of the pin state check is a mistake once the function can exit after state change (the outside if) before the timer is done and the function run again and again.
I separate the pin state change check (last != current) from the timer by using the tWait value. If the timer is running it needs tWait > 0, so tWait == 0 triggers on pin state changes and that sets up the timer which runs instead of the pin state check. One is not inside the other, one or the other runs exclusively and each ends by starting the other with watch for button press running most.

firashelou:
about your sketches, so i save these ones instead of the others you shared last time ?

Yes. I think these will be less confusing.

...R

Robin2:
Yes. I think these will be less confusing.

...R

ok thanks again Robin, will keep the old versions too

GoForSmoke:
The way that Blum has the debounce() function,

if there is no pin state change since last check it returns the pin state but if there is a change :

it stops the sketch for 5 ms assumed to let the button settle. And the function only returns after then with the pin state.

when I unblocked it, I changed how it works. Now it returns the last pin state during those 5 ms every time it is called until the 5 ms are up. In that time, this function may run hundreds of times and not read (did I get that part done?) let alone return the possibly changing pin state (contact bounce) but the last stable state instead. Then when time is up, assume the pin is stable and read it as the state.
Even after the initial pin state change is detected, this routine keeps getting exited and re-entered as long as something like loop() calls it. It cannot do this if the time check only runs when the pin state changes as you have coded. The time check depends on pin state change but that only happens once and the time check needs to happen for 5 ms. Putting the time check inside of the pin state check is a mistake once the function can exit after state change (the outside if) before the timer is done and the function run again and again.
I separate the pin state change check (last != current) from the timer by using the tWait value. If the timer is running it needs tWait > 0, so tWait == 0 triggers on pin state changes and that sets up the timer which runs instead of the pin state check. One is not inside the other, one or the other runs exclusively and each ends by starting the other with watch for button press running most.

excuse me but i am still having a bit of hard time to really understand this, the language you are using is a bit hard :confused:
but about tWait i though it is an arduino function but it's not, what is it exactly ?
and about the if you mean i must put it outside the (last != current ) ?
i was making some exercising so i used the time notion instead of delay to make LEDs go HIGH one by one but when i added the if statement of the time, just the first LED goes on and the others stays off nevertheless Serial debugging gave me numbers as they are supposed to be from the for loops i still trying to figure out what's wrong, but i can't see the problem ! maybe this might help me understand the one you are trying to explain in my main sketches, so far this is not working, because just the first LED is lighting up and stops at D2 why i spent hours trying stuff and i read adafruit tutorials on multitasking and nothing :frowning: ! FRUSTRATING IT IS !

//RED LEDs
byte Pin2 = 2;
byte Pin3 = 3;
byte Pin4 = 4;
byte Pin5 = 5;

//GREEN LEDs
byte Pin6 = 6;
byte Pin7 = 7;
byte Pin8 = 8;
byte Pin9 = 9;

//YELLOW LEDs
byte Pin10 = 10;
byte Pin11 = 11;
byte Pin12 = 12;
byte Pin13 = 13;

//LED Arrays
byte redLEDArray[4] = { Pin2, Pin3, Pin4, Pin5 };
byte blueLEDArray[4] = { Pin6, Pin7, Pin8, Pin9 };
byte yellowLEDArray[4] = { Pin10, Pin11, Pin12, Pin13 };

//Time Variables
unsigned long previousTime = 0;
unsigned long currentTime;
const long gap = 500;

void setup(){
    
    Serial.begin(9600);
    for( int i=2; i<14; i++ ){
      
      pinMode(i, OUTPUT);
      
    }

}

void loop(){

    currentTime = millis();
    for ( int REDpin=0; REDpin<4; REDpin++ ){
    
      
      if( currentTime - previousTime >= gap ){
          previousTime = currentTime;
          digitalWrite(redLEDArray[REDpin], HIGH);
          //delay(100);
          
          
      }
      Serial.println(redLEDArray[REDpin]);
      
      /*if( REDpin == 3 ){
          
          for( int BLUEpin=0; BLUEpin<4; BLUEpin++ ){
    
            digitalWrite(blueLEDArray[BLUEpin], HIGH);
            
          }
      }*/
      
      
    }

}