Owl Circuits Logo


Personal Weather Station

A weather station based on the Raspberry Pi

5. Interfacing Xbee to the microcontroller

Before we go off and start interfacing to sensors, we want to verify that we can send data between the battery operated remote sensor microcontroller and the receiving device, the raspberry PI.

For this test, we will create a small program in the microcontroller and send this data out through the microcontroller's UART to the XBee end device. The XBee end device will then send it wireless to the XBee coordinator. The data will then come out on the XBee coordinator UART, which is connected via the XBee programming adapter to the Raspberry PI USB port. The entire data path is shown in figure 5.1

Figure 5.1 Microcontroller to base station data path

The objective is to test the following features of the wireless link.

Once we have this basic test working, it will prove that we can reliably send data from a remote battery operated microcontroller back to the Raspberry PI to be processed.

5.1 Creating your first battery powered wireless link

For this test you will need the following:

The code examples here are written for a dsPIC30F3013. In reality you can use any microcontroller that has a built in UART. You will have to adapt the code to your particular microcontroller. Make sure that whatever microcontroller you choose is capable of running off of 3 volts so that it can be powered by 2 AA batteries.

5.2 Hardware

Figure 5.2 is the schematic of our test circuit. You can build it on a breadboard, or alternatively on a prototype PCB board. If you decide to build it on a prototype board, be sure to socket the microcontroller and the XBee module.

Figure 5.2 Schematic of microcontroller & XBee test circuit

5.3 Microcontroller software

We will need a test program in the microcontroller to generate data to send through the XBee end device back to the XBee coordinator to be received by the Raspberry PI.

The test program will perform the following tasks:

The flowchart of the microcontroller test program is shown in figure 5.3:

Figure 5.3 Microcontroller software flow chart

The data we will send is the message "Hello from XBee" along with an incrementing number. The incrementing number is so that we can verify that we can send data more than once. Using an incrementing number also allows us to see if data is repeated, missing or comes out of order.

After initializing the UART, we delay a short time to allow the XBee to join up with the coordinator. Next we push the data into the UART. After waiting for the UART to finish transmitting, we will put the XBee to sleep by asserting the pin SLEEP_RQ on the XBee module.

When you assert SLEEP_RQ , the XBee will finish any pending transmissions, and then go into a low power state. Once in this low power state, the XBee will not respond to any UART data so anything that is sent to the XBee when it is in a low power state will be ignored. The XBee is dead to the world.

Once the XBee is asleep we will put the PIC microcontroller to sleep by calling the standard sleep function: Sleep();

To wake the microcontroller we will use the watchdog timer. The watchdog timer is a counter that counts down from a maximum value. When it reaches zero, it wakes the microcontroller. We can control the rate of the watchdog timer counting down by setting its pre-scaler. In the ds30F3013 microcontroller if we set the microcontroller to run at 2 MHz, and set the watchdog timer pre-scaler to its maximum value, we get a timeout period of about 16 seconds. Sixteen seconds will be plenty of sleep time for our initial testing.

Once the microcontroller wakes up, we will de-assert the SLEEP_RQ pin on the XBee module to wake it from sleep. We will delay a few hundred milliseconds to allow the XBee module time to power up.

Finally we will increment our data counter and send another data message out on the UART to the XBee end device. The program will loop sending out "Hello from XBee" every 16 seconds until it is powered down or the microcontroller is reset.

Don't forget to program the microcontroller you are using with the test program before continuing.

5.4 Perl script for the Raspberry PI

The microcontroller is going to generate the test message "Hello from XBee" and send it through the XBee end device to be received by the XBee coordinator. The XBee coordinator is connected through the programming adapter to the USB port on the Raspberry PI. We now need a program running on the Raspberry PI to receive the UART data from the XBee coordinator.

We will use a Perl script to connect to the serial port on the Raspberry PI and in turn receive the data from the XBee coordinator connected to it.

First we need to install the Perl module Device::SerialPort on the Raspberry PI so that we can access the serial port on the Raspberry PI using our Perl script. At a Raspberry PI terminal prompt, install the Perl module by typing:

sudo apt-get install libdevice-serialport-perl

Next create a text file on the Raspberry Pi called serial.pl that contains the following:

#!/usr/bin/perl use Device::SerialPort qw( :PARAM :STAT 0.07 ); my $port = Device::SerialPort->new("/dev/ttyUSB0"); $port->databits(8); $port->baudrate(9600); $port->parity("none"); $port->stopbits(1); while(1) { my ($count,$byte)=$port->read(1); if ($count != 0){ print "$byte";} }

After we have plugged in the XBee coordinator programming adapter we should see a new USB device show up in /dev on the Raspberry PI. It should look something like /dev/ttyUSB0 . To determine which USB device the XBee coordinator is, we can do :

ls /dev/tty*

to see what devices are normally present. After we plug in the XBee programming adapter to the Raspberry PI USB port. There will be a new device that shows up in /dev. We can do another

ls /dev/tty*

to see what new device appeared. Take note of the path of the new device and update the line of the Perl script that opens the serial port:

my $port = Device::SerialPort->new("/dev/ttyUSB0");

The Perl script opens and configures the serial port and then simply waits in an infinite loop for a character to come in on the serial port and then prints the character to the terminal. Upon starting the Perl script, it will appear hung until a message comes in on the serial port from the XBee coordinator. To stop the Perl script, simply control-c the program.

5.5 Test the wireless link

Now we will test that we can send data from our battery powered microcontroller over the ZigBee wireless link to the Raspberry PI. This test is essential in order to create a reliable wireless link between our remote battery powered sensor unit and the Raspberry PI which will act as our weather station's base station.

First make sure that the Raspberry PI is powered up and that the XBee coordinator is plugged in to the Raspberry PI USB port through the XBee programming adapter. It is important that the XBee coordinator is powered up before the battery powered XBee end device is powered up. This ensures that a coordinator is ready to establish the network when the first XBee end device powers up and searches for a network.

Next we need to power up the battery powered microcontroller with the XBee end device attached. At this point you should have already programed the microcontroller that you are using with the microcontroller test program.

We can now start the Perl script on the Raspberry PI to receive the serial data from the XBee. At a terminal on the Raspberry PI, start the serial test program:


It may take a minute or so before any data is received. The XBee endpoint needs to join the coordinator's network before it can transfer any data. Since the microcontroller test program blindly sends data, it is not unusual for the first messages to be received by the coordinator to be a few counts past the start point.

Remember that the microcontroller test program sends "Hello from Xbee0" shortly after reset and then increments the counter and sends another message about 16 seconds later. If it takes 45 seconds for the XBee end device to find and join the coordinator network, you would see the first message in the Raspberry PI's terminal as:

Hello from Xbee2

This is due to the fact that we overflowed the XBee endpoint's serial buffer since we kept sending serial data even though the XBee was unable to send it out over the wireless link while it was looking for a network to join.

About every 16 seconds a new message should show up in the Raspberry Pi's terminal:

Hello from Xbee2 Hello from Xbee3 Hello from Xbee4

Now we have verified that we can send data from our battery powered microcontroller through the XBee end device over the ZigBee network to be received by the XBee coordinator. The XBee coordinator then outputs the data on its serial port which is connected through the XBee programming adapter to the Raspberry PI where it is received and printed by a Perl script.

Proving the wireless link is an important step in our weather station project. Now we are able to send whatever data we want from a battery powered microcontroller to our base station the Raspberry Pi.

We also proved that we can successfully put both the microcontroller and the XBee endpoint to sleep and wake both of them back up.

5.5.1 A note on power consumption

If we take a moment and hook an ammeter in series with the positive of the battery for our microcontroller and XBee end device circuit we can measure the approximate current consumption. We will see that the entire system takes about 40mA when the XBee is transmitting. The entire system draws about 10mA when inactive (not transmitting) but not asleep. When both the XBee and the microcontroller are asleep, the entire system only draws about 6µA from the battery.

Since we plan to have the microcontroller and XBee endpoint asleep the majority of the time and only wake them for short periods to read sensors and transmit the data, battery life should be reasonable. Ten micro amps is a negligible amount of power to be drawn from a set of AA batteries.

5.6 Troubleshooting tips

Nothing ever works perfectly the first time so here are some tips for the most common issues encountered with our battery powered microcontroller and XBee network.

5.6.1 No messages received

If everything is powered up and no messages are received by the Raspberry Pi, you need to check the following:

To check which USB tty port the programming adapter is using on the Raspberry PI, you should unplug and then re plug in the programming adapter while watching the message file /var/log/messages on the Raspberry Pi. When you plug the programming adapter into the USB port on the Raspberry Pi, a message should appear in /var/log/messages indicating that a new device was plugged in. Use the /dev path reported in /var/log/messages as the USB port in the test Perl script serial.pl. The path should look something like /dev/ttyUSB0.

Another tip is to disable sleep mode by disconnecting the connection between the Sleep_RQ pin on the XBee and the microcontroller. Instead tie the Sleep_RQ pin on the XBee to ground (0) to force the XBee to never go into low power sleep mode. Disabling sleep mode will simplify debugging issues since the XBee will never go to sleep.

It is also important to verify that your XBee end point and coordinator have linked up and created a network. It would be worth re-verifying this using XCTU as in section 4.6. We can also re-connect the coordinator XBee to XCTU and use the terminal in XCTU to see if any messages from our remote battery powered XBee endpoint appear.

When the coordinator XBee is connected to XCTU, it is worth checking that a network has been established. Check the operating PANID of the coordinator and verify that it is non-zero. If the operating PANID is set to zero, this indicates that no network was established. Go back and review the settings for both the coordinator and endpoint to find the incorrect setting.

5.6.2 Garbled messages

Sometimes you may see garbled messages received instead of "Hello from XBee" The most common cause of garbled messages is an incorrect baud rate setting in the sending microcontroller. The default baud rate for the XBee UART is 9600,8,N,1. Most microcontrollers require you to set each of these parameters in different registers and 9600,8,N,1 may not be the default setting in the microcontroller.

The baud rate of most microcontrollers is dependent on the operating frequency of the microcontroller's system clock. Make sure to read the documentation for the microcontroller to figure out how to correctly set the baud rate on the microcontroller to 9600. It usually requires computing a baud rate generator number based on an equation that factors in the operating frequency of the microcontroller.

The baud rate generator value on the microcontroller may also have a small percentage of error due to the rounding off of the value from the baud rate generator equation. If the data received by the XBee is only partially garbled, try adjusting the baud rate generator number in the microcontroller up or down a small amount. If the baud rate count is 243 for example, try using 244 or 242.

5.6.3 Missing messages & partial messages

If the first few messages from the XBee are missing there is an explanation for that.

Hello from Xbee2 Hello from Xbee3 Hello from Xbee4

In this case although our program starts with the message "Hello from Xbee0" and then increments the number at the end of the message, the first message we receive is "Hello from Xbee2". This indicates that we missed the first two messages. The reason behind this is due to the fact it takes a few seconds to a minuet for the XBee end device to join the coordinator's network. When the microcontroller and XBee first power up, the microcontroller starts to send messages right away, every 16 seconds. The XBee end device will ignore these messages until it has joined a network.

If we reset the microcontroller, without powering down the XBee or microcontroller it will then correctly send the first message as "Hello from Xbee0". We will address this power up issue when we build the first remote sensor. In the case of a partial message such as:

Hello from Xb Hello fr Hello from X

The cause is usually tracked down to the microcontroller going to sleep before all of the message is pushed out through the microcontroller's UART to the XBee end device.

Most microcontrollers will buffer the UART data and then return control to the software while the hardware finishes sending the data out through the UART. If the next instruction in software is the sleep command, some microcontrollers will immediately go to sleep, hence the partial message, while others will finish the UART transmission before going to sleep.

The best solution is to check in software that the microcontroller's UART has finished its transmission before calling the microcontroller's sleep function. Most microcontrollers have either a bit that indicates the UART transmit buffer is empty or a bit that indicates a UART transmission is still underway. Make sure both of these are clear before putting the XBee or microcontroller to sleep.

5.7 Switching the coordinator to API mode

Previously, we had configured our XBees to operate in AT or transparent mode. AT or transparent mode works fine when you have a single end device talking to a coordinator. Any data received by the coordinator is assumed to come from the single end device on your network. AT mode is also simple. Any data that goes into the serial port on the end device comes out exactly the same on the serial port of the coordinator.

However, if we have a network that contains more than one end device we would not know which end device sent the data to the coordinator. In our weather station implementation, we plan to have multiple end devices with different sensors attached all talking to the coordinator that acts as the base station. We need a way of determining where the data came from in order to properly interpret the remote sensor data.

The solution is to convert the coordinator from AT mode to API mode. API mode is similar to AT mode with the exception that the received data is wrapped in a data packet that contains the address of the sender.

Switching between AT and API mode only affects the format of the data coming out on the UART of the XBee module. It in no way affects the inter network communication between XBees. It is possible to have a mix of AT and API mode devices within a XBee network. Figure 5.4 shows the actual data received by the XBee coordinator in both AT and API mode.

Figure 5.4: Data received by coordinator in AT and API modes.

The weather stations sensors can remain in AT mode as they only need to communicate directly to the coordinator. However, we will re-program the coordinator to API mode so that we can see which sensor is sending data by decoding the sensor's address in the API data packet.

To switch the coordinator to API mode, we need to download new firmware to the XBee coordinator device. Connect your XBee coordinator through the programming adapter to your computer. Start XCTU and allow the device to be discovered by XCTU. Select update firmware and choose "XB24-ZB ZigBee Coordinator API" and the newest version. Make sure to leave "Force module to maintain its current configuration" checked as shown in figure 5.5. This will update the firmware to API mode but leave all of your current settings, such as PAN ID intact.

Figure 5.5: Updating coordinator firmware to API mode.

After switching the coordinator to API mode, we will want to re-test using our battery powered microcontroller as in section 5.5. We can use the same test setup as in section 5.5. We can use the same end device that we programmed earlier and the same microcontroller program that sends the message "Hello from XBee".

Since we are using the new coordinator which is now in API mode, we will need a modified Perl script on the Raspberry Pi. The new Perl script will receive data in API mode and decode the packet to print not only the message "Hello from XBee" , but also print the packet header including the address of the sending XBee end device.

To test the setup in API mode, follow the exact same steps as in section 5.5, except substitute the Perl script serial.pl with serialAPI.pl on the Raspberry Pi.

© Copyright 2013-2018 OwlCircuits.com
Page last updated: April 3, 2016..

Home | Contact | Privacy Policy