A project I am working on requires temperature data to be sent periodically (about every 5 minutes) from a sensor node to a data logger using an XBee radio. The project requires the sensor to operate using battery power for two weeks. To conserve power, I built a 3.3 V breadboard Arduino with a efficient switching DC to DC voltage regulator and put both the XBee and the ATmega328 to sleep most of the time. This post details how to get an XBee Series 1 radio to hibernate using the ATmega328. For details on using the watchdog timer to keep the Arduino asleep most of the time only waking periodically to perform short tasks like reading and sending data see this post.
First, let’s talk about how to configure the XBee to enter a low-power state. First, the radio itself must be configured. I wanted to use the lowest power sleep state available which is called pin hibernation. There are other low-power states but I won’t detail them here. To configure the XBee radio for pin hibernation the SM and D7 parameters of the chip must be set to 1 and 0, respectively. If you are using a serial program to access the XBee’s command mode then you would enter the commands ATSM1 and ATD70 to achieve this. If you are using XCTU, you just need to find the SM and D7 parameters in the program, set them, then upload the changes. The SM parameter actually sets the pin hibernation mode while the D7 parameter allows you to disable the XBee’s ability to pause sending data to a MCU if the MCU’s serial buffer is full.
Next, let’s talk about how to actually get the XBee to enter hibernation and wake from sleep. Once configured, the XBee will enter hibernation when the DTR pin (pin 9 on the XBee) is brought high (3.3 V). It will wake from hibernation when this pin is brought low (0 V).
I built the following circuit to achieve this:
Pin 9 (Arduino)
|
|
|—-10 kOhm—-Vcc (3.3 V)
|
|
Pin 9 DTR (XBee)
The basic principles of operation are as follows. To put the XBee to sleep, the Arduino’s pin 9 is configured as an input and set high (3.3 V). Then the 10 kOhm pull-up resistor brings the voltage on the XBee’s pin 9 high also. To wake the XBee, the Arduino’s pin 9 is configured as an output and set low (0 V). The ATmega328 can not only source current, it can also sink up to about 40 mA of current which is more than enough to bring the voltage on the XBee’s pin 9 low and wake the XBee from hibernation. Below is an outline of the Arduino code I use. I’ve incorporated this code into a larger routine that uses the watchdog timer to put the ATmega328 to sleep too.
const int XBee_wake = 9; // Arduino pin used to sleep the XBee
void setup(void) {
// nothing special here
}
void loop(void) {
// wake up the XBee
pinMode(XBee_wake, OUTPUT);
digitalWrite(XBee_wake, LOW);
// do whatever I need to do with the XBee
// put the XBee to sleep
pinMode(XBee_wake, INPUT); // put pin in a high impedence state
digitalWrite(XBee_wake, HIGH);
}
That’s all there is to it. Good luck with your project.
Permalink //
hi, may i ask, how do you apply 0v to the pin 9 of arduino? i think my xbee is sleeping since 3.3v is applied.
Permalink //
You would set the pin low using a command like this:
digitalWrite(9,LOW);
Does this help?
Permalink //
Very useful post. My only question is, did you mean to set ATD8 to 0 rather than ATD7? D7 is pin 12 while D8 is pin 9 according to the datasheet. Thanks
Permalink //
No, I wanted to set D7 to 0. This disables CTS flow control. CTS flow control allows the MCU to tell the XBee to stop sending data if its serial buffer is full. Since the XBee will be hibernating, I thought it wise to disable this feature. Perhaps you can get away with not disabling CTS flow control. I tend to be very conservative in my designs. Glad you found the post helpful. I see you liked my low-power Arduino watchdog timer post too.
Permalink //
Hi,
I use XBee shield for working with XBee module from my Arduino Uno. Should I use pin 9 in this case too?
Thanks in advance!
Permalink //
I have no idea. You would have to look at the datasheet/schematic for your XBee shield. There are several varieties out there. It should show the mapping between the XBee pins and the pins on the shield. Sorry for the long delay responding. As a professor this is an incredibly busy time of year.
Permalink //
I’m using the Arduino Pro Mini 3.3v 328. I wired up pin 9 to DTS pin 9 on the xBee with a pull up of 10K. My xBee wasn’t going to sleep and verified that it was still sending data when I set pin 9 HIGH. I put my meter on pin 9 and verified that it was going HIGH. Any ideas on why this thing won’t sleep? Will printing to the serial port actually wake the xBee?
Permalink //
OOPS! I went back and double checked the xBee SM and D7 parameters. They were not set correctly. It is hibernating perfectly now.
Thanks for your article.
Permalink //
Great
Permalink //
In pin hibernation mode, power down current will be <10uA. I didnt find out that. I got 10mA. I connect my multimeter in between arduino 3.3V pin and xbee 3.3V on
Permalink //
Hello Jeff.
Thanks for the great posts like this one.
I was just wondering though:
– What is the advantage of changing the arduino’s Xbee_wake pin from an output to an input VS just having it be an output set to high or low ?
Permalink //
Joshua, As an output, the pin can source or sink current. As an input, the pin has a high input impedance and will not sink current. Basically, when you want the pin to be a passive monitor of a wire, set it as an input. When you want it to be an active participator in a circuit, set it as an output. -Jeff
Permalink //
Hi Jeff,
I want to know why you are using a 10K resister?
Thanks
Permalink //
Wow!!!
Thank you very much!!
Today you are my hero!
xavi from barcelona
Permalink //
Hi Jeff,
I am trying to do Pin Hibernate using Arduino Fio board,
which no luck to set the pin 9
If you have any Idea please let me know.
Permalink //
Thanx ! Sleeping like a baby.
Permalink //
Hello Jeff,
I use a Libelium Sigfox module, and want to configure it to hibernate (deep sleep mode).
The problem is that XCTU dosn’t find it. I have even tried with a Sparkfun Xbee explorer, but no success.
I have also tried with AT commands, but no response.
I have tried many speeds.
Do you have an idea, or a way to look for.
Thanks in advance
Regards
Noury
Permalink //
Sorry, I have no idea. I’ve only ever worked with XBee modules.
Permalink //
Hello Jeff,
Thanks for the great tutorial. I managed to successfully put my arduino to sleep, as well as put the xbee in hibernation mode. My main problem though is when I do put the xbee on SM=1 (and D7=0), I don’t get any data out of the device on my modem (the non sleeping xbee attached to my computer/arduino setup). I have checked again with sleep mode and CTS reverted to defaults and my xbee starts transmitting again. Do you have any idea as to what may cause this?
Thanks in Advance,
Rick M.
Permalink //
XBee series 1 is used in a weather station with a small solar panel and the low power method described here works great. Thanks.
I don’t use the resistor to pull the DTR pin up. I use the Arduino instruction
pinMode(xbeePowerPin, INPUT_PULLUP);
digitalWrite(xbeePowerPin(HIGH);
and it works great. Just enough pulp to set the hibernate pin. Issuing
pinMode(xbeePowerPin, OUTPUT);
digitalWrite(xbeePowerPin, LOW);
will of course wake it up.