Thursday, March 26, 2015

New Raspberry Pi GPIO Pinout Diagram

Since I have been using model B+ and model 2 a lot lately, I wanted an updated GPIO pinout diagram. Also, since I used WiringPi, the diagram had to include that numbering scheme. None of the diagrams I found satisfied me, so I made my own. I used the output from the WiringPi command gpio readall and did some formatting in excel to produce the following diagram. I hope you find it useful.


Sunday, March 8, 2015

Using the MPL115A2 to read Temperature and Barometric Pressure

This post is a continuation of the series on my weather station system.

My weather station uses the MPL115A2, available from Adafruit.  It is an inexpensive sensor for measuring temperature and barometric pressure.  It is only moderately accurate - the MPL3115A2, which only slightly more expensive, would probably have been a better choice.  Both sensors are interfaced using an I2C bus and are fairly simple to use.

In order to compute the correct pressure, several coefficient values must be read from the device first.  These coefficients are unique to each device and provide the calibration necessary to arrive at an accurate reading.  Since they don't change, they only need to be read once.

After reading the coefficients, the data capture and conversion are started by writing a zero to register address 0x12.  The program must then pause briefly to allow the conversion to complete.  The results are stored in the device registers and are read with the standard I2C commands.  The temperature value is taken directly from the register values, with some simple adjustments to get it to degrees Celsius.  The pressure is then computed by a formula that applies the coefficients read earlier as well as the temperature.  The value is in kilo Pascals.  For use by an American like myself, these are finally converted to degrees Fahrenheit and inches of Mercury.

Below is an example, in C, of the code similar to what I use.

/*
    example to test mpl115a2 (temp/baro sensor) on i2c
 ted.b.hale@gmail.com
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>


int main(int argc, char *argv[])
{
 int i, n, fd;
 // command string to get coefficients
 unsigned char coef_request[3] = {3, 4, 8};
 // command string to request conversion
 unsigned char conv_request[3] = {0, 0x12, 0};
 // variables for the final results
 float baro, celsius, farenheit;
 
 // variables to hold the integer values of coefficients
 int16_t a0coeff;
 int16_t b1coeff;
 int16_t b2coeff;
 int16_t c12coeff;
 // variables to hold the floating point coefficients
 float a0;
 float b1;
 float b2;
 float c12;
 // some intermediate values
 int pressure, temp;
 float pressureComp;
 
 // open a file descriptor to the device on the I2C bus
 fd = wiringPiI2CSetup(0x60);  // 0x60 is bus address of mpl115a2
 if (fd==-1)
 {
  printf("wiringPiI2CSetup failed\n");
  return 0;
 }

 // get the coefficients.  This only needs to be done once.
 // Note on C language: the << and >> operators perform bit shifting
 a0coeff = (( (uint16_t) wiringPiI2CReadReg8(fd,4) << 8) | wiringPiI2CReadReg8(fd,5));
 b1coeff = (( (uint16_t) wiringPiI2CReadReg8(fd,6) << 8) | wiringPiI2CReadReg8(fd,7));
 b2coeff = (( (uint16_t) wiringPiI2CReadReg8(fd,8) << 8) | wiringPiI2CReadReg8(fd,9));
 c12coeff = (( (uint16_t) (wiringPiI2CReadReg8(fd,10) << 8) | wiringPiI2CReadReg8(fd,11))) >> 2;
 printf("%d   %d   %d   %d\n",a0coeff,b1coeff,b2coeff,c12coeff);
 // convert coefficients to floating point
 a0 = (float)a0coeff / 8;
 b1 = (float)b1coeff / 8192;
 b2 = (float)b2coeff / 16384;
 c12 = (float)c12coeff;
 c12 /= 4194304.0;
 printf("%f   %f   %f   %f\n\n",a0,b1,b2,c12);
 
 // start conversion and wait a tiny bit
 wiringPiI2CWriteReg8(fd,0x12,0);
 delay(5);
 
 // get the results by reading the device registers
 pressure = (( (uint16_t) wiringPiI2CReadReg8(fd,0) << 8) | wiringPiI2CReadReg8(fd,1)) >> 6;
 temp = (( (uint16_t) wiringPiI2CReadReg8(fd,2) << 8) | wiringPiI2CReadReg8(fd,3)) >> 6;

 // compute temperature compensation for pressure
 pressureComp = a0 + (b1 + c12 * temp ) * pressure + b2 * temp;

 // get the pressure in kiloPascals
 baro = ((65.0F / 1023.0F) * pressureComp) + 50.0F;        // kPa
 // get the temperature in celsius degrees
 celsius = ((float) temp - 498.0F) / -5.35F +25.0F;        // C

 // convert kilo-Pascals to inches of mercury
 baro = baro * 0.295299830714;
 // convert Celsius to Farenheit
 farenheit = (celsius * 1.8) + 32.0;

 //show the results
 printf("%f    %f\n\n",baro,farenheit);
 
 return 0;
}

The device comes with a 6x1 header which allows it to be mounted simply on a circuit board.  I mounted it directly on the interface board that I built for the weather station.  This is in a weatherproof enclosure, but that should have negligible effect on the reading of  pressure since the enclosure is not completely air-tight.  This will, however, affect temperature reading.  Therefore, while I do record the temperature value, it is not the primary source for temperature that my weather station uses.  For that I use the AM2315 sensor, which is described in my previous post.