Basic program to read temperature and pressure data from BMP-180 altimeter, convert the temperature into Centigrade and Fahrenheit, and average pressure for highest precision. Use pressure to obtain altitude in meters and feet. Display all to four 4-digit eight-segment bubble displays.

Dependencies:   mbed

Dependents:   GloboMet

Files at this revision

API Documentation at this revision

Comitter:
onehorse
Date:
Thu Jul 03 20:05:55 2014 +0000
Commit message:
Initial commit

Changed in this revision

BMP180.h Show annotated file Show diff for this revision Revisions of this file
HT16K33.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 06dc60296e6e BMP180.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BMP180.h	Thu Jul 03 20:05:55 2014 +0000
@@ -0,0 +1,155 @@
+#ifndef BMP180_H
+#define BMP180_H
+ 
+#include "mbed.h"
+
+#define BMP180_ADDRESS          0x77<<1 // I2C address of BMP180, eight bit address on mbed
+#define BMP180_WHO_AM_I         0xD0    // WHO_AM_I id of BMP180, should return 0x55
+#define BMP180_RESET            0xE0
+#define BMP180_CONTROL          0xF4
+#define BMP180_OUT_MSB          0xF6
+#define BMP180_OUT_LSB          0xF7
+#define BMP180_OUT_XLSB         0xF8
+
+// Set initial input parameters
+
+enum OSS {  // BMP-085 sampling rate
+  OSS_0 = 0,  // 4.5 ms conversion time
+  OSS_1,      // 7.5
+  OSS_2,      // 13.5
+  OSS_3       // 25.5
+};
+
+uint8_t OSS = OSS_3;           // maximum pressure resolution
+
+//Set up I2C, (SDA,SCL)
+I2C i2c(I2C_SDA, I2C_SCL);
+    
+// These are constants used to calculate the temperature and pressure from the BMP-180 sensor
+int16_t ac1, ac2, ac3, b1, b2, mb, mc, md, b5;  
+uint16_t ac4, ac5, ac6;
+
+class BMP180 {
+ 
+    protected:
+ 
+    public:
+  //===================================================================================================================
+//====== Set of useful function to access pressure and temperature data
+//===================================================================================================================
+
+    void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
+{
+   char data_write[2];
+   data_write[0] = subAddress;
+   data_write[1] = data;
+   i2c.write(address, data_write, 2, 0);
+}
+
+    char readByte(uint8_t address, uint8_t subAddress)
+{
+    char data[1]; // `data` will store the register data     
+    char data_write[1];
+    data_write[0] = subAddress;
+    i2c.write(address, data_write, 1, 1); // no stop
+    i2c.read(address, data, 1, 0); 
+    return data[0]; 
+}
+
+    void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
+{     
+    char data[14];
+    char data_write[1];
+    data_write[0] = subAddress;
+    i2c.write(address, data_write, 1, 1); // no stop
+    i2c.read(address, data, count, 0); 
+    for(int ii = 0; ii < count; ii++) {
+     dest[ii] = data[ii];
+    }
+} 
+ 
+
+// Stores all of the BMP180's calibration values into global variables
+// Calibration values are required to calculate temp and pressure
+// This function should be called at the beginning of the program
+// These BMP-180 functions were adapted from Jim Lindblom of SparkFun Electronics
+void BMP180Calibration()
+{
+  ac1 = readByte(BMP180_ADDRESS, 0xAA) << 8 | readByte(BMP180_ADDRESS, 0xAB);
+  ac2 = readByte(BMP180_ADDRESS, 0xAC) << 8 | readByte(BMP180_ADDRESS, 0xAD);
+  ac3 = readByte(BMP180_ADDRESS, 0xAE) << 8 | readByte(BMP180_ADDRESS, 0xAF);
+  ac4 = readByte(BMP180_ADDRESS, 0xB0) << 8 | readByte(BMP180_ADDRESS, 0xB1);
+  ac5 = readByte(BMP180_ADDRESS, 0xB2) << 8 | readByte(BMP180_ADDRESS, 0xB3);
+  ac6 = readByte(BMP180_ADDRESS, 0xB4) << 8 | readByte(BMP180_ADDRESS, 0xB5);
+  b1  = readByte(BMP180_ADDRESS, 0xB6) << 8 | readByte(BMP180_ADDRESS, 0xB7);
+  b2  = readByte(BMP180_ADDRESS, 0xB8) << 8 | readByte(BMP180_ADDRESS, 0xB9);
+  mb  = readByte(BMP180_ADDRESS, 0xBA) << 8 | readByte(BMP180_ADDRESS, 0xBB);
+  mc  = readByte(BMP180_ADDRESS, 0xBC) << 8 | readByte(BMP180_ADDRESS, 0xBD);
+  md  = readByte(BMP180_ADDRESS, 0xBE) << 8 | readByte(BMP180_ADDRESS, 0xBF);
+}
+
+  // Temperature returned will be in units of 0.1 deg C
+  int16_t BMP180GetTemperature()
+  {
+  int16_t ut = 0;
+  writeByte(BMP180_ADDRESS, 0xF4, 0x2E); // start temperature measurement
+  wait(0.005);
+  uint8_t rawData[2] = {0, 0};
+  readBytes(BMP180_ADDRESS, 0xF6, 2, &rawData[0]); // read raw temperature measurement
+  ut = (((int16_t) rawData[0] << 8) | rawData[1]);
+ 
+ long x1, x2;
+  
+  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
+  x2 = ((long)mc << 11)/(x1 + md);
+  b5 = x1 + x2;
+
+  return  ((b5 + 8)>>4);  
+}
+
+// Calculate pressure read calibration values  
+// b5 is also required so BMP180GetTemperature() must be called first.
+// Value returned will be pressure in units of Pa.
+long BMP180GetPressure()
+{
+  long up = 0;
+  writeByte(BMP180_ADDRESS, 0xF4, 0x34 | OSS << 6); // Configure pressure measurement for highest resolution
+  wait((5.0f + 8.0f*3.0f)/1000.0f); // delay 5 ms at lowest resolution, 29 ms at highest
+  uint8_t rawData[3] = {0, 0, 0};
+  readBytes(BMP180_ADDRESS, 0xF6, 3, &rawData[0]); // read raw pressure measurement of 19 bits
+  up = (((long) rawData[0] << 16) | ((long)rawData[1] << 8) | rawData[2]) >> (8 - OSS);
+
+  long x1, x2, x3, b3, b6, p;
+  unsigned long b4, b7;
+  
+  b6 = b5 - 4000;
+  // Calculate B3
+  x1 = (b2 * (b6 * b6)>>12)>>11;
+  x2 = (ac2 * b6)>>11;
+  x3 = x1 + x2;
+  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
+  
+  // Calculate B4
+  x1 = (ac3 * b6)>>13;
+  x2 = (b1 * ((b6 * b6)>>12))>>16;
+  x3 = ((x1 + x2) + 2)>>2;
+  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
+  
+  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
+  if (b7 < 0x80000000)
+    p = (b7<<1)/b4;
+  else
+    p = (b7/b4)<<1;
+    
+  x1 = (p>>8) * (p>>8);
+  x1 = (x1 * 3038)>>16;
+  x2 = (-7357 * p)>>16;
+  p += (x1 + x2 + 3791)>>4;
+  
+  return p;
+}      
+
+ 
+ 
+  };
+#endif
\ No newline at end of file
diff -r 000000000000 -r 06dc60296e6e HT16K33.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HT16K33.h	Thu Jul 03 20:05:55 2014 +0000
@@ -0,0 +1,266 @@
+#ifndef HT16K33_H
+#define HT16K33_H
+ 
+#include "mbed.h"
+
+#define HT16K33_ADDRESS         0x70<<1  // shift to the left one for mbed
+#define HT16K33_ON              0x21  // Commands
+#define HT16K33_STANDBY         0x20
+#define HT16K33_DISPLAYON       0x81
+#define HT16K33_DISPLAYOFF      0x80
+#define HT16K33_BLINKON         0x85 // Blink is off (00), 2 Hz (01), 1 Hz (10), or 0.5 Hz (11) for bits (21) 
+#define HT16K33_BLINKOFF        0x81
+#define HT16K33_DIM             0xE0 | 0x08  // Set brihtness from 1/16 (0x00) to 16/16 (0xFF)
+
+// Arrangement for display 1 (4 digit bubble display)
+// 
+//               a = A0
+//             _________
+//            |         |
+//   f = A2   |  g = A4 | b = A1
+//            |_________|
+//            |         |
+//   e = A5   |         | c = A6
+//            |_________|
+//               d = A3        DP = A7
+
+
+static const char numberTable[] =
+{
+  0x6F, // 0 = 0
+  0x42, // 1 = 1, etc
+  0x3B, // 2
+  0x5B, // 3
+  0x56, // 4
+  0x5D, // 5
+  0x7D, // 6
+  0x43, // 7
+  0x7F, // 8
+  0x57, // 9
+  0x80, // decimal point
+  0x00, // blank
+  0x10, // minus sign
+};
+
+#define display1 1
+#define display2 2
+#define display3 3
+#define display4 4
+
+class HT16K33 {
+ 
+    protected:
+ 
+    public: 
+ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//++ Useful Functions++
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+void writeInteger(uint8_t dsply, int data)
+{
+  char string[10] = "";                             // define character array to hold the digits
+  itoa(data, string);                               // get ascii character string representation of the integer to be displayed
+  uint8_t length = strlen(string);                  // get the length of the string; number of digits in integer
+  uint8_t blanks = 4 - length;                      // how many blanks do we have?
+
+  if (length > 4) return;                           // if length greater than 4 digits we can't display on a four-digit display!
+
+  for (uint8_t digit = 0; digit < blanks; digit++)  // scroll through each digit to determine what to write to the display
+  {
+      writeDigit(dsply, digit + 1, 11, 0);          // clear digit wherever there are blanks
+  }
+
+  for (uint8_t digit = 0; digit < 4; digit++)       // scroll through each digit to determine what to write to the display
+  {
+      char ch = string[digit];                      // get the ascii character of the next string segment
+
+      if (ch == '-') {
+      writeDigit(dsply, digit + 1 + blanks, 12, 0); // check if negative sign needed
+      } 
+      else {                                        // character must be a digit
+      ch -= '0';                                    // convert it to an integer
+      writeDigit(dsply, digit + 1 + blanks, ch, 0); // write it to the display; right justify the integer
+      } 
+  }
+}
+
+void writeFloat(uint8_t dsply, float data, uint8_t dp)
+{
+  char string[10] = "";  // define character array to hold the digits
+  int datanew = 0;
+  
+  switch (dp)
+  {
+    case 0:
+    datanew = (int )(1.0f*data);
+    break;
+ 
+    case 1:
+    datanew = (int )(10.0f*data);
+    break;
+
+    case 2:
+    datanew = (int )(100.0f*data);
+    break;
+ 
+    case 3:
+    datanew = (int )(1000.0f*data);
+    break;
+   }
+   
+  
+  itoa(datanew, string);                                    // get ascii character string representation of the integer to be displayed
+  uint8_t length = strlen(string);                          // get the length of the string; number of digits in integer
+  uint8_t blanks = 4 - length;                              // how many blanks do we have?
+
+  if (length > 4) return;                                   // if length greater than 4 digits we can't display on a four-digit display!
+
+// scroll through each digit to determine what to write to the display
+for (uint8_t digit = 0; digit < blanks; digit++)            // first the blanks
+  {
+          if( (digit + 1) == (4 - dp) ) {                   // handle special case where blank coincides with decimal point
+            writeDigit(dsply, digit + 1, 0, 0x80);          // add leading zero before decimal place
+          }
+          else {
+            writeDigit(dsply, digit + 1, 11, 0x00);         // otherwise clear digit wherever there are blanks
+          }
+  }
+
+  for (uint8_t digit = 0; digit < 4; digit++)               // now the characters to determine what to write to the display
+  {
+      char ch = string[digit];                              // get the ascii character of the next string segment
+
+      if (ch == '-') {
+        if((digit + 1 + blanks) == (4 - dp) ) {
+          writeDigit(dsply, digit + 1 + blanks,  0, 0x80);  // check if negative sign needed, add a decimal point
+          writeDigit(dsply, digit + 0 + blanks, 12, 0x00);  // add a leading zero
+        }
+        else {
+          writeDigit(dsply, digit + 1 + blanks, 12, 0x00);  // check if negative sign needed, no decimal point
+        }
+        }
+      else  {                                               // character must be a digit
+        ch -= '0';                                          // convert it to an integer
+        if((digit + 1 + blanks) == (4 - dp) ) {
+          writeDigit(dsply, digit + 1 + blanks, ch, 0x80);  // write it to the display with decimal point; right justify the integer
+        } 
+        else {
+          writeDigit(dsply, digit + 1 + blanks, ch, 0x00);  // write it to the display; right justify the integer
+        } 
+     }
+  }
+}
+  
+
+void writeDigit(uint8_t dsply, uint8_t digit, uint8_t data, uint8_t dp) 
+{
+if(dsply == 1) {
+  digit = (digit - 1)*2 + 0; 
+} 
+if(dsply == 2) {
+  digit = (digit - 1)*2 + 8 ;
+}
+if(dsply == 3) {
+  digit = (digit - 1)*2 + 1;
+}
+if(dsply == 4) {
+  digit = (digit - 1)*2 + 9;
+}
+writeByte(HT16K33_ADDRESS, digit, numberTable[data] | dp);
+}
+
+
+void clearDsplay(int dsply) 
+{
+  for(int i = 0; i < 8; i++)  {
+  writeDigit(dsply, i, 11, 0);  // Clear display, 11 is blank in the numberTable above
+  }
+}
+
+
+void initHT16K33()
+{
+  writeCommand(HT16K33_ADDRESS, HT16K33_ON);         // Turn on system oscillator
+  writeCommand(HT16K33_ADDRESS, HT16K33_DISPLAYON);  // Display on
+  writeCommand(HT16K33_ADDRESS, HT16K33_DIM);        // Set brightness
+
+}
+
+
+void blinkHT16K33(int time) 
+{
+  writeCommand(HT16K33_ADDRESS, HT16K33_BLINKON);  // Turn on blink
+  wait(time);
+  writeCommand(HT16K33_ADDRESS, HT16K33_BLINKOFF);  // Turn on blink
+}
+
+
+ /* itoa:  convert n to characters in s */
+ void itoa(int n, char s[])
+ {
+     int i, sign;
+ 
+     if ((sign = n) < 0)  /* record sign */
+         n = -n;          /* make n positive */
+     i = 0;
+     do {       /* generate digits in reverse order */
+         s[i++] = n % 10 + '0';   /* get next digit */
+     } while ((n /= 10) > 0);     /* delete it */
+     if (sign < 0)
+         s[i++] = '-';
+     s[i] = '\0';
+     reverse(s);
+ } 
+ 
+ /* reverse:  reverse string s in place */
+ void reverse(char s[])
+ {
+     int i, j;
+     char c;
+ 
+     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
+         c = s[i];
+         s[i] = s[j];
+         s[j] = c;
+     }
+ }
+
+  // Wire.h read and write protocols
+  void writeCommand(uint8_t address, uint8_t command)
+  {
+   char data_write[1];
+   data_write[0] = command;
+   i2c.write(address, data_write, 1, 0);
+}
+
+   void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
+{
+   char data_write[2];
+   data_write[0] = subAddress;
+   data_write[1] = data;
+   i2c.write(address, data_write, 2, 0);
+}
+
+    char readByte(uint8_t address, uint8_t subAddress)
+{
+    char data[1]; // `data` will store the register data     
+    char data_write[1];
+    data_write[0] = subAddress;
+    i2c.write(address, data_write, 1, 1); // no stop
+    i2c.read(address, data, 1, 0); 
+    return data[0]; 
+}
+
+    void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
+{     
+    char data[14];
+    char data_write[1];
+    data_write[0] = subAddress;
+    i2c.write(address, data_write, 1, 1); // no stop
+    i2c.read(address, data, count, 0); 
+    for(int ii = 0; ii < count; ii++) {
+     dest[ii] = data[ii];
+    }
+} 
+ };
+#endif
\ No newline at end of file
diff -r 000000000000 -r 06dc60296e6e main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Jul 03 20:05:55 2014 +0000
@@ -0,0 +1,91 @@
+#include "mbed.h"
+#include "BMP180.h"
+#include "HT16K33.h"
+ 
+#define BMP180_ADDRESS 0x77<<1
+
+uint32_t delt_t, count, tempcount;
+float temperature, pressure, temppress, altitude;
+
+DigitalOut myled(LED1);
+ 
+BMP180 bmp180; // initialize BMP-180 altimeter
+
+HT16K33 led; // initialize bubble display
+
+Timer t;
+
+Serial pc(USBTX, USBRX); // tx, rx
+ 
+int main() {
+ 
+   t.start();
+   
+   led.initHT16K33();          // initialize bubble display
+   led.clearDsplay(display1);  // clear bubble display1
+   led.clearDsplay(display2);  // clear bubble display2
+   led.clearDsplay(display3);  // clear bubble display1
+   led.clearDsplay(display4);  // clear bubble display2
+
+  // Read the WHO_AM_I register of the BMP-180, this is a good test of communication
+    uint8_t c = bmp180.readByte(BMP180_ADDRESS, BMP180_WHO_AM_I);   
+    if(c == 0x55) {
+ 
+    pc.printf("BMP-180 is 0x%x\n\r", c);
+    pc.printf("BMP-180 should be 0x55\n\r");
+    pc.printf("BMP-180 online...\n\r");
+   
+    bmp180.BMP180Calibration();
+    pc.printf("BMP-180 calibration complete...\n\r");
+   }
+   else 
+   {
+    pc.printf("BMP-180 is 0x%x\n\r", c);
+    pc.printf("BMP-180 should be 0x55\n\r");
+    while(1); // idle here forever
+   }
+   
+    /////////////////////////////////////////////////
+    // main
+    /////////////////////////////////////////////////
+ 
+    while (1) {
+
+    // Average over the display duty cycle to get the best pressure and altitude resolution
+    // The sample read time is on the order of 30 ms at the highest resolution using OSS = 3
+    // Averaging over the display duty cycle is equivalent to averaging about 500/30 ~ 16 times
+    // per display output. If this is too much averaging, one can always reduce the display duty cycle
+    
+    temperature = (float)bmp180.BMP180GetTemperature()/10.0f;  // Get temperature from BMP-180 in degrees C
+    temppress += (float)bmp180.BMP180GetPressure();            // Get pressure from BMP-180 in Pa
+    tempcount++;
+
+    // Serial print and/or display at 0.5 s rate independent of data rates
+    delt_t = t.read_ms() - count;
+    if (delt_t > 500) { // update LCD once per half-second independent of read rate
+
+    myled=!myled;
+   
+    pressure = temppress/tempcount;  // use average pressure for reading to get ultra-high resolution
+    temperature = temperature*9.0f/5.0f + 32.0f;                          // convert to Fahrenheit
+    altitude = 44330.0f*( 1.0f - pow((pressure/101325.0f), (1.0f/5.255f))); // Calculate altitude in meters
+   
+    led.writeFloat(display1, temperature, 1);             // display temperature in degrees Fahrenheit to bubble display
+    led.writeFloat(display2, pressure/1000, 2);           // display pressure in mPa to bubble display
+    led.writeFloat(display3, altitude, 1);                // display altitude in meters to bubble display
+    led.writeFloat(display4, altitude*3.281f, 1);          // display altitude in feet to bubble display
+
+    pc.printf("Temperature is  %.1f C\n\r", temperature); 
+    pc.printf("Pressure is  %.3f mPa\n\r", pressure/1000.0f); 
+    pc.printf("Altitude is  %.1f m\n\r", altitude);
+    pc.printf("Altitude is  %.1f ft\n\r", altitude*3.2810f); 
+    pc.printf("\n\r");
+  
+                
+    count = t.read_ms();  
+    temppress = 0;
+    tempcount = 0;
+    }
+    }
+}
+ 
diff -r 000000000000 -r 06dc60296e6e mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Jul 03 20:05:55 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/04dd9b1680ae
\ No newline at end of file