XBee radios can transmit IO samples to other XBees autonomously using change-detection or periodic sampling.   A sample can also be requested from a ‘local’ XBee (eg. an Arduino connected via TX/RX or a Java application connected via FTDI) using AT or API-mode commands, but there is no single AT or API-mode command to force a local XBee to transmit an IO sample.

Here are two techniques I have used to force an XBee to transmit an IO sample.  Jump down to the Conclusion if you just want a quick how-to.

The Problem

Transmitting IO samples from an XBee is easy:

  1. Setup periodic sampling using the ATIR command.
  2. With change detection enabled (ATIC), toggle an IO pin (configured as input) via button press or sensor output.

Either method will cause the local XBee to transmit (or broadcast, depending on the destination address) an IO sample packet.  How can this same transmission be accomplished in software when there is no direct command?

What Not to Do

Here are some approaches that  don’t work:

  • The ATIS command will sample IO, but returns the results locally and does not transmit them.
  • The ATIS result cannot be transmitted via API mode, since the packet type would be a ZB_RX_RESPONSE, not a ZB_IO_SAMPLE_RESPONSE (unless you can change the type of packet the receiver is expecting).
  • Toggling an output pin via API mode (similar to ATD0=4, ATD0=5, ATD0=4) does not transmit a sample packet when change detection is enabled.   I suspect change detection must only work for input pins.

Solution 1: Common IO

This solution only works if the XBee and the uC share an IO line, in which case a sample packet can be transmitted this way:

  1. Configure the uC pin as an output and drive it low (or high)
  2. Configure the XBee pin as an input.
  3. Enable change detection for the XBee pin.
  4. From the uC, drive the output high (or low).
  5. Disable change detection.
  6. Reconfigure the IO pins (if necessary).

Here is an excerpt of an Arduino sketch of how I do this using the  xbee-arduino library.  The objective is to transmit an IO sample in which D0=1 to a remote XBee. The XBee’s D0 pin is tied to the Arduino’s D2 pin.   The code is adapted from a working example, with the application-specific (ie. the boring parts) omitted, so it may need some tweaking:

#include <XBee.h>

XBee xbee;

void enableChangeDetection(boolean enable) {
  uint8_t command[] = {'I', 'C'};
  uint8_t value = enable ? 1 : 0;  /* enable for D0 */
  AtCommandRequest request = AtCommandRequest(command, &value, 1);
  xbee.send(request);
}

/*
 * this is only necessary if you haven't already programmed the XBee to set D0 as an input
 */
void enableXBeeInput() {
  uint8_t command[] = {'D', '0'};
  uint8_t value = 3 /* input */
  AtCommandRequest request = AtCommandRequest(command, &value, 1);
  xbee.send(request);
}

void setup() {
  xbee.begin(9600);
  enableChangeDetection(false);
  enableXBeeInput();
  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);
}

void transmitSample() {
  enableChangeDetection(true);
  digitalWrite(2, HIGH);
  delay(500);  /* give the XBee some time to respond */
  enableChangeDetection(false);
  digitalWrite(2, LOW);
}

void loop() {
  /* call transmitSample() when ready */
}

Solution 2: Temporary Periodic Sampling

This solution is probably more practical that the common-IO solution, as it is an all-software solution.  In this method, periodic sampling is enabled just long enough to transmit the required IO sample.   The basic procedure is:

  1. Set IO pins as desired (in this case, D0=1)
  2. Enable periodic sampling
  3. Wait for one period to pass
  4. Disable periodic sampling

Here is an example in Java, using the xbee-api, in which D0=1 is transmitted in an IO sample.  Again, this code is adapted from a working example and may need additional code and/or adjusting depending on the application.

void enablePeriodicSampling(Boolean enable) {
  if (enable) {
    int[] rate = {0x01, 0xF4}; /* 500ms in hex, split into two bytes */
    AtCommand sampleRate = new AtCommand("IR", rate);
    xbee.sendSynchronous(sampleRate);
  } else {
    AtCommand sampleRate = new AtCommand("IR", 0);
    xbee.sendSynchronous(sampleRate);
  }
}

void transmitSample() {
  /* setup your IO pins however you like.  in this case, D0=1 */
  AtCommand high = new AtCommand("D0", 5);
  xbee.sendSynchronous(high):

  enablePeriodicSampling(true);
  Thread.sleep(600);
  enablePeriodicSampling(false);
}

Note that periodic sampling needs to be enabled for at least as long as the XBee’s sample rate.  Here, it is enabled for 100ms longer than the sample rate.  This may need to be fine-tuned depending on processor speeds, baud rates, etc.

Conclusion


Programatically forcing a local XBee to transmit an IO sample packet is not as simple as a built-in AT command, but can be accomplished easily by temporarily enabling periodic sampling using the ATIR command.  The most basic procedure is:

  1. Setup XBee IO using ATDx (or via external sensors)
  2. Enable periodic sampling using ATIR=01F4 (T=500ms – other values may work)
  3. Wait at least 1T for the sample to be sent (600ms to be safe)
  4. Disable periodic sampling using ATIR=0
Tagged with →  
Share →