MCP9700

Soil temperature is one of the things the Garduino monitors.  Unfortunately, soil is a harsh environment and replacing a $1.50 TMP36 everything time one stopped working was becoming a bit of a drag, so I looked for something cheaper.  The MCP9700 is a temperature sensor available from Mouser.com for $0.34, and at that price, I feel a little more free to experiment with waterproofing these sensors.

These devices are pretty nice to work with, since they can take a supply voltage of 2.1 to 5.5V and the output pin will be at .5V at 0° C and rise 0.01V for every rise in 1°C.  This document  describes how to compensate for 2nd order effects to increase accuracy further.

It is critical to put a capacitor between the Vout pin in ground (about 2nF), because without it, there is a 27kHz wave that appears on the output.  In my tests, Vout oscillated 0.0575 Volt P-P, which represents a variation of 5.75 °C from reading to reading.  With the capacitor between Vout and GND, the variation between readings drops to about 0.5°C.

The code for reading the temperature of these devices is pretty straightforward:

float readMCP9700(int pin,float offset)
{
  analogReference(INTERNAL);
  for (int n=0;n<5;n++)
    analogRead(pin);

  int adc=analogRead(pin);
  float tSensor=((adc*(1.1/1024.0))-0.5+offset)*100;
  float error=244e-6*(125-tSensor)*(tSensor - -40.0) + 2E-12*(tSensor - -40.0)-2.0;
  float temp=tSensor-error;

  return temp;
}

In my application, I have some ADC calls done against the 5V analogReference, and the analogReads for the MCP9700 are done against the internal 1.1V reference.  According to the ATMega328 datasheet, when switching between references, you should throw out the reading immediately after the switch, because it will be inaccurate.  In this function, I throw out  5 readings after setting the analogReference, just to give it extra time to settle down, and then I take the real measurement.  The 2nd order error is calculated as described in the accuracy compensation document mentioned above.

I also pass in an offset to allow me to adjust each individual sensor against a know temperature.  In my case, I really didn’t have a know temperature reading I thought was any more accurate than anything else I had, so I setup 4 MCP9700s and let them read the same temperature.  I averaged these readings, and I pass in the offset for each individual MCP9700 from that average, so, if nothing else, the temperatures read between these 4 devices will be consistent.  The offsets were on the order of 0.01V.

Advertisements

MAX44009

One of the questions I wanted to answer with my Garduino was how much light is lost through the plastic covering of the Greenhouse.  What I have found is it is very difficult to find a light sensor that has the dynamic range from darkness to full sun, but I finally stumbled on the MAX44009, which has a range from 0.045 to 180,000 Lux.  The downside of this device is no one is making a breakout board for it, so I was on my own.

Homemade breakout board for the MAX44009

Yes, this beautiful homemade PCB does work.  I made it by the laser toner transfer method, but my home printer, a Brother HL-4040CN did not work; the toner did not stick to the copper board no matter how long I put the iron on it.  I ended up creating a PDF file with Gerber2PDF and printing the image on some HP printers at work.  Unfortunately,  in my rush to not be caught screwing around with something that wasn’t work related, I forgot to make a mirror image of the PCB, so everything is backwards on the PCB.  Even with the HP toner, the toner transfer was not very good, but, considering the fact that the MAX44009 chip is 2mm x 2mm and the pads for the 6 pins are 0.36mm x 0.48 mm, the toner transfer was accurate enough to work.  Adding to the fact that this was the first time I used my hot air re-work station to do something constructive, you could have knocked me off my chair with a feather when the final assembly actually returned valid data.

It wasn’t a complete Eureka moment, though, because while the data sheet says the I2C address can be selected (with the AD pin) to be 148 or 150, that does not seem to be true.  I found this important utility, I2CScanner which runs through every I2C address, and shows which addresses a device is responding to.  This really saved me, because it showed that the real address of the MAX44009 was 203 (I forgot to note the address when AD is low, so I’ll document that when I make the improved version of the PCB).  Once I had the right address, interfacing with the MAX44009 is very straightforward, since it uses the I2C Wire Arduino  library:

#define MAX_ADDR 203

float getLux()
{
int luxHigh=readI2CAddr(0x03);
int luxLow=readI2CAddr(0x04);
int exponent=(luxHigh&0xf0)>>4;
int mant=(luxHigh&0x0f)<<4|luxLow;
return (float)(pow(2,exponent)*mant)*0.045;

}

int readI2CAddr(int addr)
{

Wire.beginTransmission(MAX_ADDR);
Wire.write(addr);
Wire.endTransmission();

Wire.requestFrom(MAX_ADDR,1);

int n=0;
for(n=0;n<25;n++)
{
if(Wire.available())
break;

delay(100);
}

if (n==25)
return 0;
else
return Wire.read();
}

I was expecting to have to handled the situation where I would have to programatically change the sensitivity of the device so that I would have to set longer integration times in low light conditions, and shorter ones in bright conditions, but the device handles that all by itself.  The device can be configured in a manual mode so that the user has control of exactly what integration time will be used for each reading, but in my case, the automatic setting behaved the way I wished.

I’ve created an Eagle library that contains the land pattern for the MAX44009.

I really like the I2C bus, but its major disadvantage is the max length which is reportedly pretty short.  I currently have the MAX44009 sitting off of about 2.5 M of 6 conductor satin cable, connected to the same 3.3V bi-directional voltage translator circuit my BMP085 is connected to, and it is working well.  I expect when I have to connect another MAX44009 to measure the light loss from inside the Greenhouse, though, the length will become a problem.  I will be researching some I2C bus lengthing techniques and will report on them in the future.

The waterproof enclosure for the MAX44009 consists of a plastic food container with a clear plastic cover, and the bottom cut out for ventilation.

 

This is the PDF for the Break Out Board that I used for the Toner Transfer method to create the PCB.

BMP085

The BMP085 is a I2C Barometric Pressure/Temperature sensor available from both Sparkfun and eBay.  The Sparkfun breakout board is very expensive, about $20, but they have excellent instructions on how to use it.  You can get the BMP085 chip on eBay for about $4 and the breakout board for about $6 for 3, but you have to be able to solder SMD to use them.

BMP085 breakout board soldered into my weather station interface board

Sparkfun has an excellent tutorial whose code I pretty much just used verbatim in my application. The only thing I changed were the bmp085Read and bmp085ReadInt functions, since as written, they will retry forever for the bmp085 to respond.  Since my device is outside, and attached to an I2C bus that is about 2.5 M long (for the Max44009 light sensor), sometimes I get a failure in reading the responses from the BMP085.  I just changed the lines that read


  while(!Wire.available())
    ;

To read:


  int n=0;
  for(n=0;n<25;n++)
  {
    if(Wire.available())
      break;

    delay(100);
  }

  if (n==25)
  {
    return 0;
  }

This way if my BMP085 malfunctions, the whole system doesn’t hang.  The other code adjustment was to put in the altitude compensation in the calculations:

#define ALT 142.0

float getPressure()
{
  long pa=bmp085GetPressure(bmp085ReadUP());

  float press=((float)pa/pow((1-ALT/44330),5.255))/100.0;
  return press;
}

Before I put in the compensation for altitude, my pressure was always too low.  Once I compensated for my 142 M altitude, the results from this device are spot on.  I’m very happy with the accuracy of this chip.

The other trick to using this device is the fact that it is a 3.3V device, and you can’t simply connect it up to a 5V I2C Arduino connection and hope for it to have a long life.  This document gives a very detailed discussion on setting up a bi-directional voltage level translator for the I2C bus.  The highlighted part of the schematic below shows the voltage level translator (the transistors are a couple of SN7000 MOSFETs):

Bi-Directional voltage translator for the I2C bus.