Wireless Pressure Sensor – first results

JeeNode connected to XBee

JeeNode connected to XBee

Here you see my first setup of a JeeNode with pressure sensor connected to a XBee Series 2 module.  And it’s working! With Hyperterminal i captured the raw data coming in on my XStick:

XBee API mode packets with sensor data

XBee API mode packets with sensor data

The ‘experts’ will immediately recognize the first character (tilde, ~) as being the frame header of a XBee packet. The payload on the first line is ‘26311 39767’. All characters before that are XBee API frame related as well as the last character, which is the checksum. When you have a look at the code you can see what the payload is made of.

This is absolutely very cool; it think in total it has cost me an evening to put this all together; something i would have never dared dreaming about a year ago!

But there’s still a lot to do:

There seems to be a timing issue in the code, cause i saw the XBee having a bit of trouble joining the PAN. Maybe give it some more time in the setup routine, or give some more time during powering up the XBee to send a new sample… we’ll see.

I need to write some software on PC-side to test reliability of it all.

How long will the batteries survive? I haven’t got a clue… and how am i going to test this? For example, i can’t switch off my PC now, cause the XStick is powered by it; XStick not powered means no PAN means the XBee will keep on searching for the PAN and will use much much more power…

To make the whole package smaller, i need to stop using the pin headers on the JeeNode and just solder the wires right onto the board.

A big step ahead, but still a lot of questions to be answered…

Here’s the code that is currently running on the JeeNode:

#include <Ports.h>
#include <RF12.h>
#include "PortsBMP085.h"
#include <avr/sleep.h>
#include <NewSoftSerial.h>

NewSoftSerial XBSerial = NewSoftSerial(2, 3);
PortI2C two (2);
BMP085 psensor (two);

int pinXBee=7;                        // to Control XBee on/off
int pinCTS=6;                         // to monitor CTS

static int SampleInterval = 1000;     // 60000;
static int HeartBeatInterval = 10000; // 300000;
static int CTS=0;                     // value of XBee CTS pin

struct {
    int16_t temp;
    int32_t pres;
} payload;

static void lowPower (byte mode) {
    // prepare to go into power down mode
    set_sleep_mode(mode);
    // disable the ADC
    byte prrSave = PRR, adcsraSave = ADCSRA;
    ADCSRA &= ~ bit(ADEN);
    PRR &= ~ bit(PRADC);
    // zzzzz...
    sleep_mode();
    // re-enable the ADC
    PRR = prrSave;
    ADCSRA = adcsraSave;
}

EMPTY_INTERRUPT(WDT_vect); // just wakes us up to resume

static void watchdogInterrupts (uint8_t mode) {
    MCUSR &= ~(1<<WDRF); // only generate interrupts, no reset
    cli();
    WDTCSR |= (1<<WDCE) | (1<<WDE); // start timed sequence
    WDTCSR = bit(WDIE) | mode; // mode is a slightly quirky bit-pattern
    sei();
}

static byte loseSomeTime (word msecs) {
    // only slow down for periods longer than twice the watchdog granularity
    if (msecs >= 32) {
        for (word ticks = msecs / 16; ticks > 0; --ticks) {
            lowPower(SLEEP_MODE_PWR_DOWN); // now completely power down
            // adjust the milli ticks, since we will have missed several
            extern volatile unsigned long timer0_millis;
            timer0_millis += 16L;
        }
        return 1;
    }
    return 0;
}

static MilliTimer SampleTimer;     // Interval for reading a sample from the BMP085
static MilliTimer HeartBeatTimer;  // forced maximum interval (Heartbeat)

static byte periodicSleep (word msecs) {
    // switch to idle mode while waiting for the next event
    lowPower(SLEEP_MODE_IDLE);
    return SampleTimer.poll(msecs);
}

static void Send (const void* ptr, byte len) {

  unsigned long tXB1;    // time XBee was woken up
  unsigned long tXB0;    // time XBee was put to sleep

  Serial.println("Sending payload");
  HeartBeatTimer.set(0);

  CTS = HIGH;
  tXB1=millis();
  // wake up Xbee
  digitalWrite(pinXBee,LOW);

  // wait for CTS to become LOW
  do
  {
    CTS=digitalRead(pinCTS);
  } while (CTS != LOW);

  // wait 2 msec otherwise data will be received all messed up
  delay(2);

  // send dummy data
  XBSerial.print(payload.temp);
  XBSerial.print(" ");
  XBSerial.println(payload.pres);

  Serial.print(payload.temp);
  Serial.print(" ");
  Serial.println(payload.pres);

  // wait again for XBee to finish transmission
  delay(2);

  // switch off XBee
  digitalWrite(pinXBee,HIGH);
}

static int16_t prevTemp;           // save previous temp value
static int32_t prevPres;           // save previous temp value

// this code is called once per second, but not all calls will be reported
int ReadSensor() {

    int16_t temp = psensor.measure(BMP085::TEMP);
    int32_t pres = psensor.measure(BMP085::PRES);

    Serial.print("Readings: ");
    Serial.print(temp);
    Serial.print(' ');
    Serial.print(pres);
    Serial.println(' ');

    int changed = (temp != prevTemp) || (pres != prevPres);
    prevTemp = temp;
    prevPres = pres;

    payload.temp = temp;
    payload.pres = pres;

    changed = 1;            // force sending always during testing
    return changed;

}

void setup() {

  // setup XBee
  pinMode(pinXBee,OUTPUT);
  digitalWrite(pinXBee,LOW);
  pinMode(pinCTS,INPUT);
  digitalWrite(pinCTS,LOW);   // really necessary?
  delay(10);

  XBSerial.begin(9600);
  // give XBee some time to join PAN
  delay(5000);

  // let the world know we're here
  XBSerial.println("n[TempPres]");
  Serial.println("n[TempPres]");

  watchdogInterrupts(0); // 16ms
}

void loop() {
    if (periodicSleep(SampleInterval)) {
      // sensor values changed or heartbeat interval elapsed?
      if (ReadSensor() || (HeartBeatTimer.poll(HeartBeatInterval)))
      {
         Send(&payload, sizeof payload);
       }

    }
}
Tagged , , . Bookmark the permalink.

2 Responses to Wireless Pressure Sensor – first results

  1. Pingback: Wireless Pressure Sensor - small fix

  2. Pingback: JeeNode/ZigBee pressure sensor closed

Leave a Reply

Your email address will not be published. Required fields are marked *