Saturday, January 17, 2009

Indoor Outdoor Temp Display

OK, it's time to move on with the remote sensor network description. Now for the Indoor-Outdoor Temp display, which is right now sitting faithfully beside my desk:


This uses a local DS18B20 Onewire temp sensor and the following standard components:


The first four items all came as kits which were assembled in less than 20 minutes. The big advantage of this approach is I am then just gluing together stuff others have built rather than having to build everything from scratch. The Adafruit XBee adapter, for instance, automatically adjusts the voltage down to 3.3 VDC (with the conditioning capacitors) and brings all the connections out neatly rather than having to hunt on the Xbee's pins. Slick.

Here is another hard to interpret schematic (click for full size):
And here it all is installed in a project box I bought from Jameco a while back:



The circuit is built using wire wrap, which is a lightly "olde timey" way to do a circuit board. I rather like it because it is more permanent than a breadboard, but not nearly as much hassle as making a printed circuit board.


Now, what is that switch for? It actually doesn't control the power, but rather is hooked to digital pin 6 on the iDuino. When the switch is tripped, it sends out the "h" command over the Xbee which turns on LED2 on my remote unit. All this really demonstrates is the ability to send simple I/O back to the remote sensor from the indoor display. Not very practical, but remember that this is all just a prototype for something that does real work remotely!

The source code is shown below. The interesting thing is that this uses both the hard serial port on the Arduino and the Lady Ada AFSerial library (click here for more info ) to create a second soft serial port off of pins 2 & 3 on the iDuino. The interesting thing about this is that I found I could NOT use the Arduino software serial library (found here). While I have been able to use this oibrary to send info to the SerialLCD display, it will not receive serial properly - if there is a call to the hardware serial port, then the Arduino software serial port no longer works. The funny thing is the AFSerial library from Laday Ada works perfectly - just like another hardware serial port. No idea why.

Again, a lot of this code is concerned with running the DS18B20 Onewire temperature sensor.

/* Indoor display for Indoor Outdoor thermometer
copyright Chris Armour */

#include 

#define TEMP_PIN  5

AFSoftSerial mySerial =  AFSoftSerial(3,2);
void OneWireReset(int Pin);
void OneWireOutByte(int Pin, byte d);
byte OneWireInByte(int Pin);

int i = 0;
int incomingNumber[4];
int incomingByte = 0;
char outMinusBit = '+';
int outTempDig1 = 0;
int outTempDig2 = 0;
int ButtonPin = 6;
int LEDPin = 12;
int switchState = 0;
long previousMillis = 0;        
long interval = 3000;           

void setup() {
  Serial.begin(9600);
  digitalWrite(TEMP_PIN, LOW);
  pinMode(TEMP_PIN, INPUT);      // sets the digital pin as input (logic 1)
  mySerial.begin(9600);
  pinMode(ButtonPin, INPUT);
  pinMode(LEDPin, OUTPUT);
}

void loop() {

// ======= The following is all code to control the OneWire sensor ==========//
  int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, MinusBit;
  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec

  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0xbe);

  LowByte = OneWireInByte(TEMP_PIN);
  HighByte = OneWireInByte(TEMP_PIN);
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions

//=========> End of the OneWire code MinusBit is the +/- & Whole is the temp ====/
//if (millis() - previousMillis > interval){
//  previousMillis = millis();
 if (Serial.available() > 0) {
//Read the first four characters when serial is received from the Xbee
   for (int i=0; i <= 4; i ++){
 // read the incoming byte:
 incomingByte = Serial.read();
        incomingNumber[i] = incomingByte - 48;
         }
         Serial.flush();
         //Discard the rest
     }
    
    if (incomingNumber[0] == 1) // Test if the first bit in indicates a positive or negative temp.
              {
                outMinusBit = '-';
              }
            else if (incomingNumber[0] == 0)
            {
              outMinusBit = '+';
            }
            outTempDig1 = incomingNumber[2]; //Assign the first digit of the temp
            outTempDig2 = incomingNumber[3]; //Assign the 2nd digit of the temp

  //Clear the LCD screen
  delay(1);
  Serial.print(254, BYTE);
  delay(1);
  Serial.print(1, BYTE); 
  delay(1);

//Print out the inside temp
  Serial.print("Inside Temp: ");
   if (SignBit) // If its negative
  {
    MinusBit = 1; 
    Serial.print("-");
  }
  else
  {
    MinusBit = 0;
    Serial.print("+");
  }
  
delay(1);
Serial.print(Whole);
//Print out the outside temp
Serial.print("    ");
Serial.print("Outside Temp: ");
Serial.print(outMinusBit);
Serial.print(outTempDig1);
//Only print the 2nd digit if there is a positive value
if (outTempDig2 >= 0){
    Serial.print(outTempDig2);
  }
  else {
    Serial.print(" ");
  }
//take a break
delay(2000);
  mySerial.print(103, BYTE);
//}

  switchState = digitalRead(ButtonPin);
delay(100);
if (switchState == 1){
  digitalWrite(LEDPin, HIGH);
  mySerial.print(104, BYTE);
}
else {
  digitalWrite(LEDPin, LOW);
  mySerial.print(108, BYTE);
}
} 

//=============OneWire functions below==============//

void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
     digitalWrite(Pin, LOW);
     pinMode(Pin, OUTPUT); // bring low for 500 us
     delayMicroseconds(500);
     pinMode(Pin, INPUT);
     delayMicroseconds(500);
}

void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
   byte n;

   for(n=8; n!=0; n--)
   {
      if ((d & 0x01) == 1)  // test least sig bit
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(5);
         pinMode(Pin, INPUT);
         delayMicroseconds(60);
      }
      else
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(60);
         pinMode(Pin, INPUT);
      }

      d=d>>1; // now the next bit is in the least sig bit position.
   }
   
}

byte OneWireInByte(int Pin) // read byte, least sig byte first
{
    byte d, n, b;

    for (n=0; n<8 br="" n="">    {
        digitalWrite(Pin, LOW);
        pinMode(Pin, OUTPUT);
        delayMicroseconds(5);
        pinMode(Pin, INPUT);
        delayMicroseconds(5);
        b = digitalRead(Pin);
        delayMicroseconds(50);
        d = (d >> 1) | (b<<7 and="" b="" bit="" br="" d="" in="" insert="" most="" position="" right="" shift="" sig="" to="">    }
    return(d);
}

4 comments:

  1. hey torchris -
    this seems to be right in line with what I'm trying to do. I'm not seeing where you talk about your remote Xbee that brings in the outside temperature. Probably right there but I'm missing it. thanks

    ReplyDelete
  2. It looks like program lines 61 - 70 handle the xbee input.

    gm...

    ReplyDelete
  3. @gary
    thanks, lines 61-70 do look like the XBee input. But I'm interested in the outside temp sending XBee. How is the remote XBee configured with a temp sensor?

    ReplyDelete
  4. Sorry for never answering here, but I honestly didn't think anyone read this stuff. I was just writing this as a project log!

    The remote is described in complete detail in my January 12th bost. It's the thing in the plastic food container! :-)

    ReplyDelete