Wireless Temperature Sensor

Difficulty Level = 5 [What's this?]

I decided to explore the more advanced features of XBee radios by building a remote temperature sensor. You can get quite a bit of control over an XBee radio without a microcontroller at all. You can configure the radio to send sensor readings at particular intervals when it detects changes on certain input pins. For the details on configuring XBee radios, see the documentation at Digi International.

For this project, I configured the radio at the sensor end to read the analog input of pin 19 every 4 seconds and to send a sensor reading packet. Both the sender and receiver radios should be running the API firmware. Input pin 19 on my sensor radio is configured (parameter D1) with value ‘2′ which means that it will read analog input, and the IO sampling rate (parameter IR) is set to ‘1000′ which sends a sample every 4096ms.

An LM34 temperature sensor outputs a variable voltage depending on the temperature. The mapping is extremely simple: 10mV for every Fahrenheit degree. So, at 72 degrees F, the output is 720mV.

Why did I choose pin 19? I started with pin 20, but I burned it out. The pins can only handle an analog input of up to 1.2V, and I think I may have sent too much into the pin. How? Well, let’s say it involved holding a cold Pepsi can on the circuit to cool off the temperature sensor, and I shorted out a connection with the can. Oops. I’m lucky I didn’t burn out the entire XBee chip.

Remote temperature sensor

Remote temperature sensor

Here is the circuit for the remote sensor:

Schematic for remote sensor circuit

Schematic for remote sensor circuit

For the receiving side, I used an Arduino with an XBee shield and a two digit LED display:

Arduino with XBee shield and LED display

Arduino with XBee shield and LED display

Here’s the Arduino code for reading incoming packets from the XBee and displaying the received analog sample on the LED display. Parsing an XBee packet is quite complex, unfortunately. But after studying the documentation for a while, it isn’t that hard.

#define NUM_DIGITAL_SAMPLES 12
#define NUM_ANALOG_SAMPLES 4

int groundPins[7] = {8, 2, 3, 4, 5, 9, 7};
int digitPins[2] = {11, 10};
int ON = HIGH;
int OFF = LOW;
int number[10][7];
int digit[2];
int TOP = 0;
int UPPER_L = 1;
int LOWER_L = 2;
int BOTTOM = 3;
int LOWER_R = 4;
int UPPER_R = 5;
int MIDDLE = 6;

int index;
int n = 0;

int packet[32];
int digitalSamples[NUM_DIGITAL_SAMPLES];
int analogSamples[NUM_ANALOG_SAMPLES];

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

  for(int i=0;i<7;i++) {
    pinMode(groundPins[i], OUTPUT);
  }
  for(int i=0;i<2;i++) {
    pinMode(digitPins[i], OUTPUT);
  }
  initNumber();

  setDigit(n);
}

void loop() {
  readPacket();
  drawDisplay();
}

void readPacket() {
  if (Serial.available() > 0) {
    int b = Serial.read();
    if (b == 0x7E) {
      packet[0] = b;
      packet[1] = readByte();
      packet[2] = readByte();
      int dataLength = (packet[1] << 8) | packet[2];

      for(int i=1;i<=dataLength;i++) {
        packet[2+i] = readByte();
      }
      int apiID = packet[3];
      packet[3+dataLength] = readByte(); // checksum

      printPacket(dataLength+4);

      if (apiID == 0x92) {
        int analogSampleIndex = 19;
        int digitalChannelMask = (packet[16] << 8) | packet[17];
        if (digitalChannelMask > 0) {
          int d = (packet[19] << 8) | packet[20];
          for(int i=0;i < NUM_DIGITAL_SAMPLES;i++) {
            digitalSamples[i] = ((d >> i) & 1);
          }
          analogSampleIndex = 21;
        }

        int analogChannelMask = packet[18];
        for(int i=0;i<4;i++) {
          if ((analogChannelMask >> i) & 1) {
            analogSamples[i] = (packet[analogSampleIndex] << 8) | packet[analogSampleIndex+1];
            analogSampleIndex += 2;
          } else {
            analogSamples[i] = -1;
          }
        }
      }
    }

    int reading = analogSamples[1];  // pin 19
    // convert reading to millivolts
    float v = ((float)reading/(float)0x3FF)*1200.0;

    // convert to Fahrenheit.  10mv per Fahrenheit degree
    float f = v / 10.0;

    // round to nearest int
    n = (int)(f+0.5);
    setDigit(n);
  }
}

void drawDisplay() {
  for(int g=0;g<7;g++) {
    digitalWrite(groundPins[g], LOW);
    for(int i=0;i<2;i++) {
      if (digit[i] < 0) {
        continue;
      }
      digitalWrite(digitPins[i], number[digit[i]][g]);
    }
    delay(0);  // for some reason, this is required even if the value is 0
    digitalWrite(groundPins[g], HIGH);
  }
}

void setDigit(int n) {
  n = n % 100;
  digit[0] = n % 10;
  digit[1] = (n / 10) % 10;
  if ((digit[1] == 0) && (n < 10)) {
    digit[1] = -1;
  }
}

void initNumber() {
  number[0][0] = ON;
  number[0][1] = ON;
  number[0][2] = ON;
  number[0][3] = ON;
  number[0][4] = ON;
  number[0][5] = ON;
  number[0][6] = OFF;

  number[1][0] = OFF;
  number[1][1] = OFF;
  number[1][2] = OFF;
  number[1][3] = OFF;
  number[1][4] = ON;
  number[1][5] = ON;
  number[1][6] = OFF;

  number[2][0] = ON;
  number[2][1] = OFF;
  number[2][2] = ON;
  number[2][3] = ON;
  number[2][4] = OFF;
  number[2][5] = ON;
  number[2][6] = ON;

  number[3][0] = ON;
  number[3][1] = OFF;
  number[3][2] = OFF;
  number[3][3] = ON;
  number[3][4] = ON;
  number[3][5] = ON;
  number[3][6] = ON;

  number[4][0] = OFF;
  number[4][1] = ON;
  number[4][2] = OFF;
  number[4][3] = OFF;
  number[4][4] = ON;
  number[4][5] = ON;
  number[4][6] = ON;

  number[5][0] = ON;
  number[5][1] = ON;
  number[5][2] = OFF;
  number[5][3] = ON;
  number[5][4] = ON;
  number[5][5] = OFF;
  number[5][6] = ON;

  number[6][0] = ON;
  number[6][1] = ON;
  number[6][2] = ON;
  number[6][3] = ON;
  number[6][4] = ON;
  number[6][5] = OFF;
  number[6][6] = ON;

  number[7][0] = ON;
  number[7][1] = OFF;
  number[7][2] = OFF;
  number[7][3] = OFF;
  number[7][4] = ON;
  number[7][5] = ON;
  number[7][6] = OFF;

  number[8][0] = ON;
  number[8][1] = ON;
  number[8][2] = ON;
  number[8][3] = ON;
  number[8][4] = ON;
  number[8][5] = ON;
  number[8][6] = ON;

  number[9][0] = ON;
  number[9][1] = ON;
  number[9][2] = OFF;
  number[9][3] = ON;
  number[9][4] = ON;
  number[9][5] = ON;
  number[9][6] = ON;
}
void printPacket(int l) {
  for(int i=0;i < l;i++) {
    if (packet[i] < 0xF) {
      // print leading zero for single digit values
      Serial.print(0);
    }
    Serial.print(packet[i], HEX);
    Serial.print(" ");
  }
  Serial.println("");
} 

int readByte() {
    while (true) {
      if (Serial.available() > 0) {
      return Serial.read();
    }
  }
}

Here’s how I wired the back of the LED display. The code displays each digit separately to save Arduino pins but toggles between the digits so fast you can’t see any flicker.

Back of LED display.  The pin positions are designed to fit the XBee shield.

Back of LED display. The pin positions are designed to fit the XBee shield.

Here’s how it looks in the dark!

In the dark!

In the dark!


Digg! Digg this!

Published by Michael, on November 1st, 2009 at 12:50 pm. Filed under: Arduino, Level 5, XBee. | 25 Comments |





25 Responses to “Wireless Temperature Sensor”

  1. Thats nice! I need to get a Xbee sometime :P

    Comment by Stigern on November 21, 2009 at 5:52 AM



  2. Tytower did one with the cheaper modules but an arduino under the transmitter which allows for multiple sensors including digital. All up cheaper than an XBee and a range of 3 miles.
    http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1256188633

    Comment by arnoldF on November 22, 2009 at 1:32 AM



  3. @arnoldF: I read that thread, where did you read he is getting 3 miles range?

    Comment by JD on November 22, 2009 at 10:23 AM



  4. I PM’d hm and that was his estimate .I’m building one now hence my interest in yours. I’ve tested the transmitter to about 600meters atm.What distance in the clear does yours cover thanks?

    Comment by arnoldF on November 22, 2009 at 2:16 PM



  5. I have the XBee Pro radios with published range of up to 1 mile. I only did a range test once and got about 1/4 mile (outdoors). In practice, the range is much less than published, especially if you do not have a directional antenna.. I even talked to an engineer at Digi about it.

    Comment by Michael on November 22, 2009 at 3:04 PM



  6. [...] wireless temperature sensor project uses an XBee, breakout board, and simple power supply to transmit temperature data to an [...]

    Pingback by XBee Wireless Temperature Sensor « The Shadow on November 25, 2009 at 9:02 AM



  7. [...] wireless temperature sensor project uses an XBee, breakout board, and simple power supply to transmit temperature data to an [...]

    Pingback by XBee Wireless Temperature Sensor | SquareCows on November 25, 2009 at 2:41 PM



  8. Hey-
    Awesome post, being able to use the Xbee with a standalone sensor is great. Looking at the schematic, it seems like pins 1 & 2 of the LM34 are both connected to ground. Is this accurate or is the lM34 actually connected to Vcc?

    Comment by Eric on November 25, 2009 at 8:26 PM



  9. Eric,
    OMG, you are right — definitely an error in my schematic. The LM34 won’t work too well with pins 1&2 connected to GND, eh?

    Comment by Michael on November 25, 2009 at 8:47 PM



  10. Eric,
    Schematic updated to reflect reality and sound electrical concepts.

    Comment by Michael on November 25, 2009 at 8:58 PM



  11. I understand that this is for learning about the XBee but if someone reading this wants to simply have remote wireless sensors around their house they should look at a JeeNode which is based on a ATmega328 and wireless and much cheaper.

    Comment by David on November 26, 2009 at 7:29 AM



  12. [...] wireless temperature sensor project uses an XBee, breakout board, and simple power supply to transmit temperature data to an [...]

    Pingback by XBee Wireless Temperature Sensor | china online business,e business,e-commerce consultant on November 26, 2009 at 7:49 PM



  13. [...] XBee Temperature Sensor Project Documentatin and Schematic nootropicdesign.com [...]

    Pingback by Arduino XBee Wireless Temperature Sensor - Microcontroller Project Circuit on December 2, 2009 at 2:08 PM



  14. I’m new to Xbee and Arduino, I’ve build a couple tutorial projects so far. I want to try this project and I have a couple of questions:
    How should the Xbees be configured?
    What is the power supply voltage on the transmitter board?
    I see that pin 1 on the LM34 is connected to the positive side of the power supply. If the p/s voltage varies will it impact the temperature reading?

    –Scott

    Comment by Scott216 on January 6, 2010 at 9:15 PM



  15. Scott216:
    Configure the XBee radios to communicate with one another (set the addresses correctly) and use the API firmware. One radio will need to be running the coordinator firmware. The only other thing to do is set one of the analog pins to sample analog values. I set parameter D1 to value ‘2′. And I set parameter IR to ‘1000′ to set the sampling rate to once every 4096ms. That’s the only config needed. The source voltage for the transmitter is 5V. The LM34 requires 5V. The 3.3V voltage regulator steps the voltage down for the XBee which requires 3.3V. I don’t know the answer to your last question about variation in VCC. I suppose if it varies it could affect the analog output of the LM34. So you should use a regulated power source for VCC. Perhaps add a 5V voltage regulator to your transmitter.

    Comment by Michael on January 7, 2010 at 8:24 AM



  16. I’m trying to get this working. I took your code and removed the parts that drive the LCD display. You can see it here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264655063

    I hooked up a temp sensor to pin 19, just like you did. I think the Xbees are configured correctly, but I wasn’t sure about what API mode I should be using. I don’t think I changed it, so it’s probably the default AP=0.

    The packets that I’m getting look like:
    7E 00 0A 83 00 01 20 00 01 04 00 03 FF 54
    7E 00 0A 83 00 01 1F 00 01 04 00 03 FF 55

    I went to the Xbee product manual (pg 58-63) to try and decipher these. I’m stuck on the 4th byte which is 83 for me. I think this is the API Identifier, but I don’t see 0×83 listed in the Xbee manual.

    I’m using Series 1 Xbee. The voltage going into pin 19 on the transmitter is about 1.8 volts. When I do a Serial.println(reading); I get zero.

    –Scott

    Comment by Scott216 on January 28, 2010 at 11:41 AM



  17. Michael could you please explain API configuration step by step . It is hampering my project which is very similar to what you have done here .

    Comment by Chen123 on February 4, 2010 at 2:55 PM



  18. Hi, i’m new in Xbee fields .
    I wonder if in the receiving side , i use a xbee connect to the PC , how can we receive the data in clear form , such as “72 degrees F” ?
    Cause in X-CTU , i think we just receive data as a packet with HEX numbers
    Can you help me? Please!

    Comment by cdf on May 12, 2010 at 10:18 PM



  19. If you are using the normal “transparent” mode (that is, not API mode), then it’s just like a normal serial connection. You can send strings just as you normally would over a serial connection. Just read the XBee documentation.

    Comment by Michael on May 12, 2010 at 10:31 PM



  20. THANKS Michael! I have been learning volumes reading your code. You referred me here from the Adafruit formus.

    Comment by Volkemon on May 30, 2010 at 2:16 PM



  21. Hi nootropic design,

    The pin assignments on your circuit drawing indicates that you used a XBee 802.15.4 module. I recently purchased 8 XBee ZB modules, and I am aware of the differences in pin assignments between these modules and the 802.15.4 ones. What deviations from your project would I need to make in order to build wireless temperature sensors out of the ZB modules?

    Best regards,
    L

    Comment by ljeung on July 9, 2010 at 3:53 PM



  22. ljeung: I am not familiar with the modules that you own, so I can’t tell you how to wire them. Have you studied the datasheet for the modules you own?

    Comment by Michael on July 9, 2010 at 5:02 PM



  23. Hi Michael,

    Yes, I’ve studied the datasheet and also the manual for my modules. In particular, I’ve studied their pin assignments (on page 13 of the ZB module’s manual at http://ftp1.digi.com/support/documentation/90000976_F.pdf) and compared them to the ones on 802.15.4 modules (see page 7 of 802.15.4 module’s manual at http://ftp1.digi.com/support/documentation/90000982_B.pdf.)

    L

    Comment by ljeung on July 9, 2010 at 7:28 PM



  24. ljeung: ok, I think you will find that you don’t have to make any changes, right? The pin assignments are the same for the pins used in the project. VCC, GND, and analog input 1.

    Comment by Michael on July 9, 2010 at 8:11 PM



  25. Okay, thanks, Michael.

    L

    Comment by ljeung on July 9, 2010 at 10:27 PM



Leave a Reply