Xbee Serial.write and debounce code help

Hi All,

This newbie needs help fine tuning coding for my 1st Arduino/Xbee project.

The idea is that a hand-held unit tells remote stations to activate 2 relays (a light that blinks & a bell)
I have the units talking, I am able to activate both relays thru Xbee.
I was able to come up with a blinking (without delay) for the light.

My main issue is how to turn off the bell relay. Basically as long as the bell button is pressed the bell should ring when the button is released it should stop. I had an if statement to send the "button is released" code to the remote station but all that did was jam-up the Xbee transmission - always saying the button is not pressed for ALL the times it's not - instead of when it just got released from having been just pressed.

My 2nd issue is figuring out the timing for the switch debouncing - I am having a hard time with recognition of the "real" button press.

Thank you.

Code for sender and receiver units below...

SENDER

// SoftwareSerial is used to communicate with the XBee
#include <SoftwareSerial.h>

SoftwareSerial XBee(0,1); // Arduino RX, TX (XBee Dout, Din)
// Declare pin numbers for feedback LEDs 1 thru 4
const int LED1_pin = 12;
const int LED2_pin = 11;
const int LED3_pin = 10;
const int LED4_pin = 9;
bool LED1_state = false;    // false is OFF
bool LED2_state = false;
bool LED3_state = false;
bool LED4_state = false;

// Declare pin numbers for bell and light buttons
const int BTN_Bell = 8;
const int BTN_Light = 7;
int BTN_Light_state = LOW;  // low = off
int BTN_Bell_state = LOW;   // low = off

// Debounce buttons section
long lastBELL_bounceTime = 0;   // last time button was pressed
long lastLIGHT_bounceTime = 0;
long debounceDELAY = 50;



void setup()
{
  pinMode(LED1_pin, OUTPUT);
  pinMode(LED2_pin, OUTPUT);
  pinMode(LED3_pin, OUTPUT);
  pinMode(LED4_pin, OUTPUT);
  // Initialize XBee Software Serial port. Make sure the baud
  // rate matches your XBee setting (9600 is default).
  XBee.begin(9600); 
}


void loop()
{
  // button send portion to remote units
  // on button press turn remote light (relay) on or off
  BTN_Light_state = digitalRead(BTN_Light);
  if ((millis() - lastLIGHT_bounceTime) > debounceDELAY) {
     if (BTN_Light_state == HIGH) {
     XBee.write('L');                           // light btn is pressed
     lastLIGHT_bounceTime = millis();
    }     
  }
  BTN_Bell_state = digitalRead(BTN_Bell);  
  if ((millis() - lastBELL_bounceTime) > debounceDELAY) {
    if (BTN_Bell_state == HIGH) {
        XBee.write('B');                        // bell btn is pressed
        lastBELL_bounceTime = millis();
    }
    else {
      //  XBee.write('O');   commented out for debuging                     // bell btn is released
    }
  }

  // feedback section from remote units - who got the message ?
  // turn corresponding LED on or off to know that remote light is on or off
  if (XBee.available() > 0 ) { 
      char RemoteNum = XBee.read();
      switch (RemoteNum) {
        case '1':                         // If received '1'
          LED1_state = !LED1_state;
          digitalWrite(LED1_pin, LED1_state);
          break;
        case '2':                         // If received '2'
          LED2_state = !LED2_state;
          digitalWrite(LED2_pin, LED2_state);
          break;
        case '3':                         // If received '3'
          LED3_state = !LED3_state;
          digitalWrite(LED3_pin, LED3_state);
          break;
        case '4':                         // If received '4'
          LED4_state = !LED4_state;
          digitalWrite(LED4_pin, LED4_state);
          break;
      }
    }   
}

RECEIVER

// Receive signals from Xbee to trigger relays and send feedback

#include <SoftwareSerial.h>

SoftwareSerial XBee(0,1);
// Declare relay pin numbers to control external bell & light
const int LIGHTrelay_pin = 6;
const int BELLrelay_pin = 5;

// Declare variables to blink the light attached to the relay
int LIGHTrelay_state = HIGH;   // OFF, since relay triggers on LOW
int LIGHTlast_state = LOW;     // start with light off
unsigned long previousMillis = 0;
unsigned long interval = 750;



void setup()
{
  pinMode(LIGHTrelay_pin, OUTPUT);
  pinMode(BELLrelay_pin, OUTPUT);
  digitalWrite(LIGHTrelay_pin, HIGH);  // Set to off position initially
  digitalWrite(BELLrelay_pin, HIGH);   // Set to off position initially
  // Baud rate MUST match XBee settings (as set in XCTU)
  XBee.begin(9600);
}

void loop()
{
  if (XBee.available() > 0) { 
        char Msg = XBee.read();
        switch (Msg) {    
        case 'L':                               // L = light btn was pushed
          LIGHTlast_state = !LIGHTlast_state;   // Toggle the last state (should light be on or off)
          XBee.write('1');                      // Say that remote station 1 got the message
          break;    
        case 'B':                               // B = bell btn was pushed
          digitalWrite(BELLrelay_pin, LOW);     // Relay triggers on low
          break;
        case 'O':                         // O = bell btn was released
          digitalWrite(BELLrelay_pin, HIGH);    // Relay triggers on low
          break;
        }
  }  

  //  Start a blinking routine for the light - if it's meant to be on 
  if ((millis() - previousMillis) > interval) {
             previousMillis = millis();
             if (LIGHTrelay_state == HIGH) {    // Toggle relay status based on blink interval
                LIGHTrelay_state = LOW;
             }    
              else {
                 LIGHTrelay_state = HIGH;
             }
          }
          if (LIGHTlast_state == HIGH) {        
             digitalWrite(LIGHTrelay_pin, LIGHTrelay_state);   // turn it on or off depending on blinking interval
          }
          else { 
             digitalWrite(LIGHTrelay_pin, HIGH);    // if btn was presssed to turn off the light keep it off.
          }
}

My main issue is how to turn off the bell relay. Basically as long as the bell button is pressed the bell should ring when the button is released it should stop.

Basically, you are wrong. When the switch BECOMES pressed, the master should send "Hey, make some noise" (or something that may be easier to parse), and when the switch BECOMES released should send "Hey, shut the f**k up" (or something that may be easier to parse).

SoftwareSerial XBee(0,1);

Why on earth are you doing software serial on the hardware serial pins?

Hi Paul,

Thanks for the input.

I originally had XBee (2,3) but could not get communication between the radios.
When I did some reading on the shields I had purchased for the Nano, the docs I found seemed to suggest that the arduino tx & rx pins were connected to the radio. I assumed I needed to keep them that way.

This is what I bought... https://www.robotshop.com/ca/en/arduino-nano-xbee-board.html

I have also attached the schematics to the Xbee board. I am quite receptive to ideas on improving / fixing my bugs, that's why I posted on this forum.

After posting on the forum, I also tried the code snipet below.
My hope was to check if the previous button state was high and the current state was low, then I would say the button got released - so tell the remote unit to "shut the ..... up" or something easier to parse :slight_smile:
I did not succeed with that either.

void loop()
{
  // button send portion to remote units
  // on button press turn remote light (relay) on or off
  BTN_Light_state = digitalRead(BTN_Light);
  if ((millis() - lastLIGHT_bounceTime) > debounceDELAY) {
     if (BTN_Light_state == HIGH) {
        XBee.write('L');                           // light btn is pressed
        lastLIGHT_bounceTime = millis();
     }     
  }
  BTN_Bell_state = digitalRead(BTN_Bell);  
  if ((millis() - lastBELL_bounceTime) > debounceDELAY) {
    if (BTN_Bell_state == HIGH) {
        XBee.write('B');                        // bell btn is pressed
        lastBELL_bounceTime = millis();
        previousBTN_Bell_state = BTN_Bell_state;
    }
    if ((BTN_Bell_state == LOW) && (previousBTN_Bell_state == HIGH)) {
         XBee.write('O');                       // bell btn is released
    }
  }

schematic-xbee-4nano-board.pdf (22.6 KB)

I assumed I needed to keep them that way.

That might be a valid assumption. The assumption that you needed to create an instance of SoftwareSerial, instead of using Serial, was complete nonsense.

    if (BTN_Bell_state == HIGH) {
        XBee.write('B');                        // bell btn is pressed
        lastBELL_bounceTime = millis();
        previousBTN_Bell_state = BTN_Bell_state;
    }
    if ((BTN_Bell_state == LOW) && (previousBTN_Bell_state == HIGH)) {
         XBee.write('O');                       // bell btn is released
    }

Why does sending 'O' depend on a state change, while sending 'B' does not?

Where does previousBTN_Bell_state get assigned a new value?

Thanks for your help Paul.

I'm kinda new at all this, are you saying that since I am using the "regular" tx & rx pins, i should have removed the xbee serial instance ? so I could (should) replace xbee.write , etc. in my code to just serial....

for your 2nd point, I need to re-work how to achieve this.
I just noticed that my code will only work the 1st time in the loop.

When the button gets pushed for the 1st time, previousBTN_Bell_state will get the high value,
then all the other times that the button is not pushed BTN_Bell_state will be low. SO my 2nd if
will always be true - that's why my Xbee unit goes nuts - it's constantly transmitting an 'O'.

How do I check to see that the button is no longer pushed (having been just released) ??

Paul, I wanted to thank you for putting me on the right track.

I think this works. More testing to be done, but is better than the results I had before.

 BTN_Bell_state = digitalRead(BTN_Bell);  
  if (BTN_Bell_state != previousBTN_Bell_state) {
    if (BTN_Bell_state == HIGH) {
        Serial.write('B');                        // bell btn is pressed
    }
    else {
         Serial.write('O');                       // bell btn is released
    }
    delay(50);
  }
  previousBTN_Bell_state = BTN_Bell_state;