[SOLVED] 2 arduinos in half-duplex mode with 2 set of RF 433MHz modules

Hello everybody I'm trying to get 2 arduinos communicating to each other like half-duplex with the 2 RF set (Tx and Rx) at 433MHz (one set per arduino of course) with the Virtualwire library.

I'm trying to get device start in transmitting mode, send "1" and put itself in receving mode and wait for device 2. As soon as it get "1" from device 2 it comes back in transmitting mode and send 1 again.

Device 2 should do the same starting from receiving mode. all the system should "ping-pong" indifenetely. Problem is they ping-pong just once...I could use some help

Here is my code for device 1

#include 

#define transmit_en_pin 10
#define rxPin 2 
#define trxPin 3

int comMode = 1; //modalità di comunicazione 1=tx, 0=rx

void setup(){
  Serial.begin(9600);
  
  // SETTAGGI DI TRASMISSIONE
  vw_set_tx_pin(trxPin);        //configurazione pin trasmissione
  vw_set_rx_pin(rxPin );    // impostazione pin di riccezione
  //vw_set_ptt_pin(transmit_en_pin);  // settaggio pin enable-transmission
  vw_set_ptt_inverted(true);      // settaggio polarità PUSH-TO-TALK
  vw_setup(2000);
  
  Serial.println("-- START --");
}

void loop(){
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  
  if(comMode == 1){
    vw_rx_stop();
    //TRASMISSIONE
    String str;
    char call[2];
    str=String(1);
    str.toCharArray(call,2);
    Serial.print("Sent: ");Serial.println(call[0]);
    vw_send((uint8_t *)call, 2); // invio del messaggio di lunghezza 2 (necessario per char singoli)
    vw_wait_tx();       // attesa conclusione invio    
    if(vw_tx_active() == false) { 
      comMode = 0;
    }
    
  } else if (comMode==0){
    vw_rx_start();
    if(vw_have_message() == true) {
      // Non - blocking per lettura ricezione
      if (vw_get_message(buf,&buflen)) {  
        Serial.print("Got:  ");Serial.println(char(buf[0])); 
        //if ( int(char(buf[0]) == 49) ){ // è in ASCII
          comMode = 1;
        //}
      }     
    }
  }
}

Here is my code for device 2

#include 

#define transmit_en_pin 10
#define rxPin  12
#define trxPin 13

int comMode = 0; //modalità di comunicazione 1=tx, 0=rx


void setup(){
  Serial.begin(9600);
  
  // SETTAGGI DI TRASMISSIONE
  vw_set_tx_pin(trxPin);        //configurazione pin trasmissione
  vw_set_rx_pin(rxPin );    // impostazione pin di riccezione
  //vw_set_ptt_pin(transmit_en_pin);  // settaggio pin enable-transmission
  vw_set_ptt_inverted(true);      // settaggio polarità PUSH-TO-TALK
  vw_setup(2000);
  
  Serial.println("-- START --");
}

void loop(){
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  
  if(comMode == 1){
    vw_rx_stop();
    //TRASMISSIONE
    String str;
    char call[2];
    str=String(1);
    str.toCharArray(call,2);
    Serial.print("Sent: ");Serial.println(call[0]);
    vw_send((uint8_t *)call, 2); // invio del messaggio di lunghezza 2 (necessario per char singoli)
    vw_wait_tx();       // attesa conclusione invio    
    if(vw_tx_active() == false) { 
      comMode = 0;
    }
    
  } else if (comMode==0){
    vw_rx_start();
    if(vw_have_message() == true) {
      // Non - blocking per lettura ricezione
      if (vw_get_message(buf,&buflen)) {  
        Serial.print("Got:  ");Serial.println(char(buf[0])); 
       // if ( int(char(buf[0]) == 49) ){ // è in ASCII
          comMode = 1;
       // }
      }     
    }
  }
}

thanks in advance Giuseppe

My experience is with the RF12B.

But these guys ACK/NAK each other, so they do handshake S/R.

This site is a treasure trove of info: https://lowpowerlab.com

Ray

Thank you Ray

I will of course consider the RF12B if no solution comes out with the modules I'm currently using (https://www.pjrc.com/teensy/td_libs_VirtualWire.html these modules and library by the way).

I would simply like that the 2 systems send and receive alternatevely, switching mode as long as message is sent or received. It seems easy to say, but after an undefined amount of ping-pong (may be one, two...) the entire system get stuck in receiving mode. Either one of them did not sent or the other did not received...I don't know.

You can use the watchdog timer or software timeout for sending another request, when the slave didn't respond in time.

What do you mean ? something like "if you got stuck for more than X seconds, go on again"?

If that is, unfortunately it can't be applicable for the global application: of course this is just a partial extract of the whole project.

If you don't know how to add features to your project, you should restructure the project before proceeding. Receiving data asynchronously and with a timeout is common practice.

DrDiettrich, I'm learning while I'm doing things, so I apologize if some questions of mine may seem a little below basics. I did not know what a watchdog timer is, but if it is what I wrote I can definitely code it.

Of course I started from simple things like just sending and just receiving and everything went fine. I didn't know about timeout, I 'll try with some delay (10 ms or something) after sending if that is what you mean.

A watchdog timer is a circuit in the microcontroller that runs independent of the main core of the microcontroller. Whenever a program is running properly, the watchdog timer is reset often (we call that petting the dog) and the timer never gets too far down the line. When something stalls or crashes in the main code, then the watchdog timer keeps counting because it is not getting petted (reset) and eventually it will overflow and cause the physical chip to do a reset ... generally just like grounding the reset line which is normally held high by a resistor.

So, the WDT is a safety mechanism that ensures the uC device will continue to run and if not, it is forced to restart. The solution is not perfect, but handles many use cases.

Ray

A WDT can not only reset the controller, it also can generate an interrupt instead.

DrDiettrich: A WDT can not only reset the controller, it also can generate an interrupt instead.

Yes, generally speaking most any 'timer' can generate an interrupt, the WDT being somewhat special in the timer group.

:)

Ray

You don't need the hardware watchdog timer to implement a timeout.

Just follow the basic idea of the "Blink Without Delay" example that comes with the Arduino IDE, making sure that [u]message reception is non-blocking[/u]. If a message is not received within a certain number of milliseconds, declare a timeout.

jremington: You don't need the hardware watchdog timer to implement a timeout.

Just follow the basic idea of the "Blink Without Delay" example that comes with the Arduino IDE, making sure that [u]message reception is non-blocking[/u]. If a message is not received within a certain number of milliseconds, declare a timeout.

Well, in a state-machine where the states are known and the programmer has provided for every possible contention imaginable... then you are correct.

But, the WDT is a BIG hammer and when something happens that the state-machine cannot manage programmatically then it is a great tool to use to force a reset and start with the C-runtime initializing variables, setting up the environment, and restarting the user program.

Even NASA has to sometime reboot spacecraft.

Ray

thanks everybody: I got it working.

First of all I implemented a simple timeout software put here and there in the code, thanks to the vw_tx_active() function of the library. Second I had to stop any receiving process (vw_rx_stop()) once I got the message and only then I could post-process the message. Last I had to delay a little bit the code after I got the message, because of the inner asynchrony of the system. That is not an issue (I hope): in my complete project an user-event will trigger the communication mode swithcing.

here is the code for device 1 - the one starting in transmitting mode:

#include 

#define transmit_en_pin 10
#define rxPin 2 
#define trxPin 3

int comMode = 1; //modalità di comunicazione 1=tx, 0=rx, 2=rx post-proc
int count=0; 
int watchDog = 200; 

unsigned long rxT0;
unsigned long txT0;

void setup(){
 Serial.begin(9600);

 // SETTAGGI DI TRASMISSIONE
 vw_set_tx_pin(trxPin);        //configurazione pin trasmissione
 vw_set_rx_pin(rxPin );    // impostazione pin di riccezione
 //vw_set_ptt_pin(transmit_en_pin);  // settaggio pin enable-transmission
 vw_set_ptt_inverted(true);      // settaggio polarità PUSH-TO-TALK
 vw_setup(2000);

 Serial.println("-- START --");
}

void loop(){
 uint8_t buf[VW_MAX_MESSAGE_LEN];
 uint8_t buflen = VW_MAX_MESSAGE_LEN;

 if(comMode == 1){
 count++;
 vw_rx_stop();
 txT0=millis();
 //TRASMISSIONE
 String str;
 char call[2];
 str=String(1);
 str.toCharArray(call,2);
 Serial.println(count);
 Serial.print("Sent: ");Serial.println(call[0]);
 for (int i=0; i<1; i++){
 vw_send((uint8_t *)call, 2); // invio del messaggio di lunghezza 2 (necessario per char singoli)
 }
 vw_wait_tx();       // attesa conclusione invio    
 delay(10);
 if(vw_tx_active() == false) { 
 comMode = 0;
 }

 } else if (comMode==0){
 vw_rx_start();
 rxT0=millis();
 if (vw_get_message(buf,&buflen)) {  // Non - blocking per lettura ricezione
 comMode=2;
 } else if(vw_wait_rx_max(watchDog) == false){
 Serial.print("Got:  ");Serial.println("Nothing");
 comMode = 1;
 }

 } else if (comMode==2){
 vw_rx_stop();
 Serial.print("Got:  ");Serial.println(char(buf[0])); 
 if ( int(char(buf[0]) == 49)){ // è in ASCII
 delay(100); // solo per test, da modificare se serve
 comMode = 1;
 }else if(vw_wait_rx_max(watchDog) == false){
 Serial.print("Got:  ");Serial.println("Nothing");
 comMode = 1;
 }
 }
}

here is the code for device 2 - the one starting in receiving mode:

#include 

#define transmit_en_pin 10
#define rxPin  12
#define trxPin 13

int comMode = 0; //modalità di comunicazione 1=tx, 0=rx, 2=rx post-proc
int count=0; 
int watchDog = 200; 

unsigned long rxT0;
unsigned long txT0;

void setup(){
    Serial.begin(9600);

    // SETTAGGI DI TRASMISSIONE
    vw_set_tx_pin(trxPin);        //configurazione pin trasmissione
    vw_set_rx_pin(rxPin );    // impostazione pin di riccezione
    //vw_set_ptt_pin(transmit_en_pin);  // settaggio pin enable-transmission
    vw_set_ptt_inverted(true);      // settaggio polarità PUSH-TO-TALK
    vw_setup(2000);

    Serial.println("-- START --");
}

void loop(){
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if(comMode == 1){
        count++;
        vw_rx_stop();
        txT0=millis();
        //TRASMISSIONE
        String str;
        char call[2];
        str=String(1);
        str.toCharArray(call,2);
        Serial.println(count);
        Serial.print("Sent: ");Serial.println(call[0]);
        for (int i=0; i<1; i++){
            vw_send((uint8_t *)call, 2); // invio del messaggio di lunghezza 2 (necessario per char singoli)
        }
        vw_wait_tx();       // attesa conclusione invio    
        delay(10);
        if(vw_tx_active() == false) { 
            comMode = 0;
        }

    } else if (comMode==0){
        vw_rx_start();
        rxT0=millis();
        if (vw_get_message(buf,&buflen)) {  // Non - blocking per lettura ricezione
            comMode=2;
        } else if(vw_wait_rx_max(watchDog) == false){
            Serial.print("Got:  ");Serial.println("Nothing");
            comMode = 1;
        }

    } else if (comMode==2){
        vw_rx_stop();
        Serial.print("Got:  ");Serial.println(char(buf[0])); 
        if ( int(char(buf[0]) == 49)){ // è in ASCII
            delay(100); // solo per test, da modificare se serve
            comMode = 1;
        }else if(vw_wait_rx_max(watchDog) == false){
            Serial.print("Got:  ");Serial.println("Nothing");
            comMode = 1;
        }
    }
}

piepolitb: thanks everybody: I got it working.

Congratulations. Wait 6 months and do it again from scratch.... you'll be surprised that your approach will likely be different. But, you got through this one and that's important.

Ray