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.
Revision 0:06dc60296e6e, committed 2014-07-03
- Comitter:
- onehorse
- Date:
- Thu Jul 03 20:05:55 2014 +0000
- Commit message:
- Initial commit
Changed in this revision
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