High resolution barometer and altimeter using i2c mode
Dependents: mbed_5637_test Weather_Station_Ofiicial
Fork of ms5611 by
Revision 8:3a9d37268ccd, committed 2014-05-20
- Comitter:
- cstevens
- Date:
- Tue May 20 16:18:00 2014 +0000
- Parent:
- 7:2e8bc98f3dda
- Commit message:
- adjusted for address but calibration not completed
Changed in this revision
diff -r 2e8bc98f3dda -r 3a9d37268ccd ms5561.cpp --- a/ms5561.cpp Tue May 20 16:13:09 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,355 +0,0 @@ -//! -//! @file an520_I2C.c,v -//! -//! Copyright (c) 2009 MEAS Switzerland -//! -//! -//! -//! @brief This C code is for starter reference only. It is written for the -//! MEAS Switzerland MS56xx pressure sensor modules and Atmel Atmega644p -//! microcontroller. -//! -//! @version 1.0 $Id: an520_I2C.c,v 1.0 -//! -//! @todo - -#include "mbed.h" -#include "ms5561.h" - -double P; // compensated pressure value (mB) -double T; // compensated temperature value (degC) -double A; // altitude (ft) -double S; // sea level barometer (mB) - -uint32_t C[8]; //coefficient storage - -//--------------------------------------------------------------------------------------------------------------------------------------// -// Constructor and destructor - -ms5611::ms5611(PinName sda, PinName scl) : _i2c(sda, scl) { - _i2c.frequency(400000); -} - -//******************************************************** -//! @brief send I2C start condition and the address byte -//! -//! @return 0 -//******************************************************** - -int ms5611::m_i2c_start(bool readMode) { - int twst; - _i2c.start(); - if(readMode == true) { - twst = m_i2c_write(MS5611_ADDR_R); - } else { - twst = m_i2c_write(MS5611_ADDR_W); - } - return(twst); -} - -//******************************************************** -//! @brief send I2C stop condition -//! -//! @return none -//******************************************************** - -void ms5611::m_i2c_stop(void) { - _i2c.stop(); -} - -//******************************************************** -//! @brief send I2C stop condition -//! -//! @return remote ack status -//******************************************************** - -unsigned char ms5611::m_i2c_write(unsigned char data) { - int twst = _i2c.write(data); - return(twst); -} - -//******************************************************** -//! @brief read I2C byte with acknowledgment -//! -//! @return read byte -//******************************************************** - -unsigned char ms5611::m_i2c_readAck(void) { - int twst = _i2c.read(1); - return(twst); -} - -//******************************************************** -//! @brief read I2C byte without acknowledgment -//! -//! @return read byte -//******************************************************** - -unsigned char ms5611::m_i2c_readNak(void) { - int twst = _i2c.read(0); - return(twst); -} - -//******************************************************** -//! @brief send command using I2C hardware interface -//! -//! @return none -//******************************************************** - -void ms5611::m_i2c_send(char cmd) { - unsigned char ret; - ret = m_i2c_start(false); - if(!(ret)) { - m_i2c_stop(); - } else { - ret = m_i2c_write(cmd); - m_i2c_stop(); - } -} - -//******************************************************** -//! @brief send reset sequence -//! -//! @return none -//******************************************************** - -void ms5611::cmd_reset() { - m_i2c_send(MS5611_CMD_RESET); - wait_ms(4); - loadCoefs(); -} - -//******************************************************** -//! @brief preform adc conversion -//! -//! @return 24bit result -//******************************************************** - -unsigned long ms5611::cmd_adc(char cmd) { - char cobuf[3]; - cobuf[0] = 0; - cobuf[1] = 0; - cobuf[2] = 0; - unsigned int ret; - unsigned long temp = 0; - m_i2c_send(MS5611_CMD_ADC_CONV + cmd); - switch (cmd & 0x0f) { - case MS5611_CMD_ADC_256 : wait_us(900); break; - case MS5611_CMD_ADC_512 : wait_ms(3); break; - case MS5611_CMD_ADC_1024: wait_ms(4); break; - case MS5611_CMD_ADC_2048: wait_ms(6); break; - case MS5611_CMD_ADC_4096: wait_ms(10); break; - } - m_i2c_send(MS5611_CMD_ADC_READ); - - ret = _i2c.read(MS5611_ADDR_R, cobuf, 3, false); - if(ret) printf("\n*** ms5611 ADC Read Error "); - temp = (cobuf[0] << 16) + (cobuf[1] << 8) + cobuf[2]; - return temp; -} - -//******************************************************** -//! @brief Read calibration coefficients -//! -//! @return coefficient -//******************************************************** - -unsigned int ms5611::cmd_prom(char coef_num) { - char cobuf[2]; - unsigned int ret; - unsigned int rC = 0; - cobuf[0] = 0; - cobuf[1] = 0; - m_i2c_send(MS5611_CMD_PROM_RD + coef_num * 2); // send PROM READ command - ret = _i2c.read(MS5611_ADDR_R, cobuf, 2, false); - if(ret) printf("\n*** ms5611 PROM Read Error "); - rC = cobuf[0] * 256 + cobuf[1]; - return rC; -} - -//******************************************************** -//! @brief calculate the CRC code -//! -//! @return crc code -//******************************************************** - -unsigned char ms5611::crc4(unsigned int n_prom[]) { - unsigned int n_rem; - unsigned int crc_read; - unsigned char n_bit; - n_rem = 0x00; - crc_read = n_prom[7]; - n_prom[7]=(0xFF00 & (n_prom[7])); - for (int cnt = 0; cnt < 16; cnt++) { - if (cnt%2 == 1) { - n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF); - } else { - n_rem ^= (unsigned short) (n_prom[cnt>>1]>>8); - } - for (n_bit = 8; n_bit > 0; n_bit--) { - if (n_rem & (0x8000)) { - n_rem = (n_rem << 1) ^ 0x3000; - } else { - n_rem = (n_rem << 1); - } - } - } - n_rem= (0x000F & (n_rem >> 12)); - n_prom[7]=crc_read; - return (n_rem ^ 0x0); -} - -/* -The CRC code is calculated and written in factory with the LSB byte in the prom n_prom[7] set to 0x00 (see -Coefficient table below). It is thus important to clear those bytes from the calculation buffer before proceeding -with the CRC calculation itself: -n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0 -As a simple test of the CRC code, the following coefficient table could be used: -unsigned int nprom[] = {0x3132,0x3334,0x3536,0x3738,0x3940,0x4142,0x4344,0x4500}; -the resulting calculated CRC should be 0xB. - -DB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -Addr -0 16 bit reserved for manufacturer -1 Coefficient 1 (16 bit unsigned) -2 Coefficient 2 (16 bit unsigned) -3 Coefficient 3 (16 bit unsigned) -4 Coefficient 4 (16 bit unsigned) -5 Coefficient 5 (16 bit unsigned) -6 Coefficient 6 (16 bit unsigned) -7 0 0 0 0 CRC(0x0) -*/ -/* - //Returns 0x0b as per AP520_004 - C[0] = 0x3132; - C[1] = 0x3334; - C[2] = 0x3536; - C[3] = 0x3738; - C[4] = 0x3940; - C[5] = 0x4142; - C[6] = 0x4344; - C[7] = 0x4546; - n_crc = ms.crc4(C); // calculate the CRC - pc.printf("testing CRC: 0x%x\n", n_crc); -*/ - -//******************************************************** -//! @brief load all calibration coefficients -//! -//! @return none -//******************************************************** - -void ms5611::loadCoefs() { - for (int i = 0; i < 8; i++){ - wait_ms(50); - C[i] = cmd_prom(i); - } - unsigned char n_crc = crc4(C); -} - -//******************************************************** -//! @brief calculate temperature and pressure -//! -//! @return none -//******************************************************** - -void ms5611::calcPT() { - int32_t D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5611_CMD_ADC_4096); // read D2 - int32_t D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5611_CMD_ADC_4096); // read D1 - int64_t dT = D2 - ((uint64_t)C[5] << 8); - int64_t OFF = ((uint32_t)C[2] << 17) + ((dT * (C[4]) >> 6)); //was OFF = (C[2] << 17) + dT * C[4] / (1 << 6); - int64_t SENS = ((uint32_t)C[1] << 16) + ((dT * (C[3]) >> 7)); //was SENS = (C[1] << 16) + dT * C[3] / (1 << 7); - //T = (2000 + (((uint64_t)dT * C[6]) / (float)(1 << 23))) / 100; - T=(2000+(dT*C[6])/8388608)/100; - //int32_t TEMP = 2000 + (int64_t)dT * (int64_t)C[6] / (int64_t)(1 << 23); - int32_t TEMP = 2000 + (int64_t)dT * (int64_t)(C[6] >> 23); - if(TEMP < 2000) { // if temperature lower than 20 Celsius - float T1 = (TEMP - 2000) * (TEMP - 2000); - int64_t OFF1 = (61 * T1) / 16; - int64_t SENS1 = (29 * T1) / 16; - - if(TEMP < -1500) { // if temperature lower than -15 Celsius - T1 = (TEMP + 1500) * (TEMP + 1500); - OFF1 += 17 * T1; - SENS1 += 9 * T1 ; - } - OFF -= OFF1; - SENS -= SENS1; - T = (float)TEMP / 100; - } -// int64_t P1 = ((((int64_t)D1 * SENS) >> 21) - OFF) >> 15; - //P = ((((int64_t)D1 * SENS ) >> 21) - OFF) / (double) (1 << 15) / 100.0; - P=(D1*SENS/2097152-OFF)/3276800; -} - -//******************************************************** -//! @brief calculate temperature -//! -//! @return double temperature degC -//******************************************************** - -double ms5611::calcTemp() { - calcPT(); - return(T); -} - -//******************************************************** -//! @brief calculate pressure -//! -//! @return double barometric pressure millibar -//******************************************************** - -double ms5611::calcPressure() { - calcPT(); - return(P); -} - -//******************************************************** -//! @brief get pressure, no calculation -//! -//! @return double barometric pressure millibar -//******************************************************** - -double ms5611::getPressure() { - calcPT(); - return(P); -} - -//******************************************************** -//! @brief get altitude from known sea level barometer, -//! @ no pre-pressure calculation -//! -//! @enter float sea level barometer -//! @return float altitude in feet -//******************************************************** - -float ms5611::getAltitudeFT(float sea_pressure) { - A = (1 - (pow((P / (double)sea_pressure), 0.190284))) * 145366.45; - return((float)A); -} - -//******************************************************** -//! @brief get sea level pressure from known altitude(ft), -//! @ no pre-pressure calculation -//! -//! @enter float known altitude in feet -//! @return float seal level barometer in mb -//******************************************************** - -float ms5611::getSeaLevelBaroFT(float known_alt) { - S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt , 5.2553026) * MB; - return((float)S); -} - -//******************************************************** -//! @brief get sea level pressure from known altitude(m), -//! @ no pre-pressure calculation -//! -//! @enter float known altitude in meters -//! @return float seal level barometer in mb -//******************************************************** - -float ms5611::getSeaLevelBaroM(float known_alt) { - S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt * FTMETERS , 5.2553026) * MB; - return((float)S); -}
diff -r 2e8bc98f3dda -r 3a9d37268ccd ms5561.h --- a/ms5561.h Tue May 20 16:13:09 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -#ifndef MS5561H -#define MS5561_H - -#include "mbed.h" - - -#define SEA_PRESS 1013.25 //default sea level pressure level in mb -#define KNOWNALT 327.0 //default known altitude, 5200 Franklin Dr., 94588 -#define INHG 0.02952998751 //convert mb to in/Hg constant -#define MB 33.8638815 //convert in/Hg to mb constant -#define FTMETERS 0.3048 //convert feet to meters - - -/** Software routines to access the Measurement Specialties' MS5611-01BA03 - * Variometer Module using the I2C bus option. The MS5611 is a 24 bit - * temperature and pressure transducer for high accuracy Barometer and - * Altimeter applications. It also includes compensation coefficients - * stored within the device. - * - * Code adapted from Measurement Specialties: - * "AN520 C-code example for MS56xx, MS57xx (except analog sensor), and - * MS58xx series pressure sensors" - * - * Note: AN520 has not been updated for use with the MS5611. Changes - * were necessary to "calcPT()" in order to correct scaling of - * pressure readings. - * - * Features: - * Altitude resolution to 10cm - * Fast conversion down to 1 ms - * Low power, 1 μA (standby < 0.15 μA) - * QFN package 5.0 x 3.0 x 1.0 mm^3 - * Supply voltage 1.8 to 3.6 V - * Integrated digital pressure sensor (24 bit DeltaSigma ADC) - * Operating range: 10 to 1200 mbar, -40 to +85 °C - * I2C and SPI interface up to 20 MHz - * No external components (Internal oscillator) - * Excellent long term stability - * - * @code - * #include "mbed.h" - * #include "ms5611.h" - * - * ms5611 ms(p9, p10); // i2c pins used - * Serial pc(USBTX, USBRX); // local terminal interface - * - * - * int main (void) { - * pc.baud(921600); // set up USB serial speed - * - * // set up the ms5611 - * pc.printf("\n\nInitializing the MS5611..\n"); - * ms.cmd_reset(); - * pc.printf("Ready\n"); - * - * while(1) { - * double Temp = ms.calcTemp(); //calculate press and temp, then returns current temperature in degC - * double Press = ms.calcPressure(); //calculate press and temp, then returns current pressure in mb - * double GetPress = ms.getPressure(); //returns current pressure in mb. Does no calculations. Ususally done after calcTemp() - * double Altitude = ms.getAltitudeFT(1013.25); //enter pressure at sea level in mb, returns altitude in feet - * double PressSeaLvlFT = ms.getSeaLevelBaroFT(327.2); //enter known altitude in feet, returns sea level pressure in mb - * double PressSeaLvlM = ms.getAltitudeFT(99.73); //enter known altitude in meters, returns seal level pressure in mb - * - * pc.printf("Temp: %.2f degC\n", Temp); - * pc.printf("Barometer: %.1f mB %.3f in/Hg\n", Press, Press * 0.0295301); - * pc.printf("Alt: %.1f ft\n", Altitude); - * pc.printf("Sea_Lvl: %.1f ft %.2f m\n", PressSeaLvlFT, PressSeaLvlM); - * wait(2.0); - * } - * } - * - * @endcode - */ - -//_____ M A C R O S - -#define MS5611_ADDR_W 0xEC // Module address write mode CHANGED FOR 5561 ORIGINAL 0Xee -#define MS5611_ADDR_R 0xED // Module address read modeCHANGED FOR 5561 ORIGINAL 0XeF -#define MS5611_CMD_RESET 0x1E // ADC reset command -#define MS5611_CMD_ADC_READ 0x00 // ADC read command -#define MS5611_CMD_ADC_CONV 0x40 // ADC conversion command -#define MS5611_CMD_ADC_D1 0x00 // ADC D1 conversion -#define MS5611_CMD_ADC_D2 0x10 // ADC D2 conversion -#define MS5611_CMD_ADC_256 0x00 // ADC OSR=256 -#define MS5611_CMD_ADC_512 0x02 // ADC OSR=512 -#define MS5611_CMD_ADC_1024 0x04 // ADC OSR=1024 -#define MS5611_CMD_ADC_2048 0x06 // ADC OSR=2048 -#define MS5611_CMD_ADC_4096 0x08 // ADC OSR=4096 -#define MS5611_CMD_PROM_RD 0xA0 // Prom read command - - /** Create ms5611 controller class - * - * @param ms5611 class - * - */ -class ms5611 { - -public: - /** Create a MS5611 object using the specified I2C object - * - * @param constructor, - the I2C object to communicate with - */ - ms5611(PinName sda, PinName scl); - /** Initialize the MS5611 and set up the coefficients - * First - reset the MS5611 - * Second - load coefficient values from the MS5611 PROM - * Third - calculate coefficient checksum - * This routine only needs to be run once at boot up - * - * @param NONE - */ - void cmd_reset(); - /** Calculate and return compensated temperature - * Returns double temperature in degC - * - * @param NONE - */ - double calcTemp(); - /** Calculate and return compensated barometric pressure - * Returns double pressure in millibars - * - * @param NONE - */ - double calcPressure(); - /** Return compensated barometric pressure - * Returns double pressure in millibars - * DOES NOT RE-CALCULATE FIRST!!! - * Saves time if you calcTemp(); first - * - * @param NONE - */ - double getPressure(); - /** Calculate and returns altitude in feet - * Returns float altitude in feet - * - * @param float known pressure (mB) at sea level - */ - float getAltitudeFT(float sea_pressure); - /** Calculate and returns sea level baro - * Returns float seal level barometer in feet - * - * @param float known altitude in feet - */ - float getSeaLevelBaroFT(float known_alt); - /** Calculate and returns sea level baro - * Returns float seal level barometer in meters - * - * @param float known altitude in meters - */ - float getSeaLevelBaroM(float known_alt); - -private: - int m_i2c_start(bool readMode); - void m_i2c_stop(void); - unsigned char m_i2c_write(unsigned char data); - unsigned char m_i2c_readAck(void); - unsigned char m_i2c_readNak(void); - void m_i2c_send(char cmd); - void loadCoefs(); - unsigned long cmd_adc(char cmd); - unsigned int cmd_prom(char coef_num); - unsigned char crc4(unsigned n_prom[]); - void calcPT(); - unsigned int PTbuffer[8]; // calibration coefficients - -protected: - I2C _i2c; - - -}; -#endif
diff -r 2e8bc98f3dda -r 3a9d37268ccd ms5637.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ms5637.cpp Tue May 20 16:18:00 2014 +0000 @@ -0,0 +1,355 @@ +//! +//! @file an520_I2C.c,v +//! +//! Copyright (c) 2009 MEAS Switzerland +//! +//! +//! +//! @brief This C code is for starter reference only. It is written for the +//! MEAS Switzerland MS56xx pressure sensor modules and Atmel Atmega644p +//! microcontroller. +//! +//! @version 1.0 $Id: an520_I2C.c,v 1.0 +//! +//! @todo + +#include "mbed.h" +#include "ms5637.h" + +double P; // compensated pressure value (mB) +double T; // compensated temperature value (degC) +double A; // altitude (ft) +double S; // sea level barometer (mB) + +uint32_t C[8]; //coefficient storage + +//--------------------------------------------------------------------------------------------------------------------------------------// +// Constructor and destructor + +ms5637::ms5637(PinName sda, PinName scl) : _i2c(sda, scl) { + _i2c.frequency(400000); +} + +//******************************************************** +//! @brief send I2C start condition and the address byte +//! +//! @return 0 +//******************************************************** + +int ms5637::m_i2c_start(bool readMode) { + int twst; + _i2c.start(); + if(readMode == true) { + twst = m_i2c_write(MS5637_ADDR_R); + } else { + twst = m_i2c_write(MS5637_ADDR_W); + } + return(twst); +} + +//******************************************************** +//! @brief send I2C stop condition +//! +//! @return none +//******************************************************** + +void ms5637::m_i2c_stop(void) { + _i2c.stop(); +} + +//******************************************************** +//! @brief send I2C stop condition +//! +//! @return remote ack status +//******************************************************** + +unsigned char ms5637::m_i2c_write(unsigned char data) { + int twst = _i2c.write(data); + return(twst); +} + +//******************************************************** +//! @brief read I2C byte with acknowledgment +//! +//! @return read byte +//******************************************************** + +unsigned char ms5637::m_i2c_readAck(void) { + int twst = _i2c.read(1); + return(twst); +} + +//******************************************************** +//! @brief read I2C byte without acknowledgment +//! +//! @return read byte +//******************************************************** + +unsigned char ms5637::m_i2c_readNak(void) { + int twst = _i2c.read(0); + return(twst); +} + +//******************************************************** +//! @brief send command using I2C hardware interface +//! +//! @return none +//******************************************************** + +void ms5637::m_i2c_send(char cmd) { + unsigned char ret; + ret = m_i2c_start(false); + if(!(ret)) { + m_i2c_stop(); + } else { + ret = m_i2c_write(cmd); + m_i2c_stop(); + } +} + +//******************************************************** +//! @brief send reset sequence +//! +//! @return none +//******************************************************** + +void ms5637::cmd_reset() { + m_i2c_send(MS5637_CMD_RESET); + wait_ms(4); + loadCoefs(); +} + +//******************************************************** +//! @brief preform adc conversion +//! +//! @return 24bit result +//******************************************************** + +unsigned long ms5637::cmd_adc(char cmd) { + char cobuf[3]; + cobuf[0] = 0; + cobuf[1] = 0; + cobuf[2] = 0; + unsigned int ret; + unsigned long temp = 0; + m_i2c_send(MS5637_CMD_ADC_CONV + cmd); + switch (cmd & 0x0f) { + case MS5637_CMD_ADC_256 : wait_us(900); break; + case MS5637_CMD_ADC_512 : wait_ms(3); break; + case MS5637_CMD_ADC_1024: wait_ms(4); break; + case MS5637_CMD_ADC_2048: wait_ms(6); break; + case MS5637_CMD_ADC_4096: wait_ms(10); break; + } + m_i2c_send(MS5637_CMD_ADC_READ); + + ret = _i2c.read(MS5637_ADDR_R, cobuf, 3, false); + if(ret) printf("\n*** ms5637 ADC Read Error "); + temp = (cobuf[0] << 16) + (cobuf[1] << 8) + cobuf[2]; + return temp; +} + +//******************************************************** +//! @brief Read calibration coefficients +//! +//! @return coefficient +//******************************************************** + +unsigned int ms5637::cmd_prom(char coef_num) { + char cobuf[2]; + unsigned int ret; + unsigned int rC = 0; + cobuf[0] = 0; + cobuf[1] = 0; + m_i2c_send(MS5637_CMD_PROM_RD + coef_num * 2); // send PROM READ command + ret = _i2c.read(MS5637_ADDR_R, cobuf, 2, false); + if(ret) printf("\n*** ms5637 PROM Read Error "); + rC = cobuf[0] * 256 + cobuf[1]; + return rC; +} + +//******************************************************** +//! @brief calculate the CRC code +//! +//! @return crc code +//******************************************************** + +unsigned char ms5637::crc4(unsigned int n_prom[]) { + unsigned int n_rem; + unsigned int crc_read; + unsigned char n_bit; + n_rem = 0x00; + crc_read = n_prom[7]; + n_prom[7]=(0xFF00 & (n_prom[7])); + for (int cnt = 0; cnt < 16; cnt++) { + if (cnt%2 == 1) { + n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF); + } else { + n_rem ^= (unsigned short) (n_prom[cnt>>1]>>8); + } + for (n_bit = 8; n_bit > 0; n_bit--) { + if (n_rem & (0x8000)) { + n_rem = (n_rem << 1) ^ 0x3000; + } else { + n_rem = (n_rem << 1); + } + } + } + n_rem= (0x000F & (n_rem >> 12)); + n_prom[7]=crc_read; + return (n_rem ^ 0x0); +} + +/* +The CRC code is calculated and written in factory with the LSB byte in the prom n_prom[7] set to 0x00 (see +Coefficient table below). It is thus important to clear those bytes from the calculation buffer before proceeding +with the CRC calculation itself: +n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0 +As a simple test of the CRC code, the following coefficient table could be used: +unsigned int nprom[] = {0x3132,0x3334,0x3536,0x3738,0x3940,0x4142,0x4344,0x4500}; +the resulting calculated CRC should be 0xB. + +DB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +Addr +0 16 bit reserved for manufacturer +1 Coefficient 1 (16 bit unsigned) +2 Coefficient 2 (16 bit unsigned) +3 Coefficient 3 (16 bit unsigned) +4 Coefficient 4 (16 bit unsigned) +5 Coefficient 5 (16 bit unsigned) +6 Coefficient 6 (16 bit unsigned) +7 0 0 0 0 CRC(0x0) +*/ +/* + //Returns 0x0b as per AP520_004 + C[0] = 0x3132; + C[1] = 0x3334; + C[2] = 0x3536; + C[3] = 0x3738; + C[4] = 0x3940; + C[5] = 0x4142; + C[6] = 0x4344; + C[7] = 0x4546; + n_crc = ms.crc4(C); // calculate the CRC + pc.printf("testing CRC: 0x%x\n", n_crc); +*/ + +//******************************************************** +//! @brief load all calibration coefficients +//! +//! @return none +//******************************************************** + +void ms5637::loadCoefs() { + for (int i = 0; i < 8; i++){ + wait_ms(50); + C[i] = cmd_prom(i); + } + unsigned char n_crc = crc4(C); +} + +//******************************************************** +//! @brief calculate temperature and pressure +//! +//! @return none +//******************************************************** + +void ms5637::calcPT() { + int32_t D2 = cmd_adc(MS5637_CMD_ADC_D2 + MS5637_CMD_ADC_4096); // read D2 + int32_t D1 = cmd_adc(MS5637_CMD_ADC_D1 + MS5637_CMD_ADC_4096); // read D1 + int64_t dT = D2 - ((uint64_t)C[5] << 8); + int64_t OFF = ((uint32_t)C[2] << 17) + ((dT * (C[4]) >> 6)); //was OFF = (C[2] << 17) + dT * C[4] / (1 << 6); + int64_t SENS = ((uint32_t)C[1] << 16) + ((dT * (C[3]) >> 7)); //was SENS = (C[1] << 16) + dT * C[3] / (1 << 7); + //T = (2000 + (((uint64_t)dT * C[6]) / (float)(1 << 23))) / 100; + T=(2000+(dT*C[6])/8388608)/100; + //int32_t TEMP = 2000 + (int64_t)dT * (int64_t)C[6] / (int64_t)(1 << 23); + int32_t TEMP = 2000 + (int64_t)dT * (int64_t)(C[6] >> 23); + if(TEMP < 2000) { // if temperature lower than 20 Celsius + float T1 = (TEMP - 2000) * (TEMP - 2000); + int64_t OFF1 = (61 * T1) / 16; + int64_t SENS1 = (29 * T1) / 16; + + if(TEMP < -1500) { // if temperature lower than -15 Celsius + T1 = (TEMP + 1500) * (TEMP + 1500); + OFF1 += 17 * T1; + SENS1 += 9 * T1 ; + } + OFF -= OFF1; + SENS -= SENS1; + T = (float)TEMP / 100; + } +// int64_t P1 = ((((int64_t)D1 * SENS) >> 21) - OFF) >> 15; + //P = ((((int64_t)D1 * SENS ) >> 21) - OFF) / (double) (1 << 15) / 100.0; + P=(D1*SENS/2097152-OFF)/3276800; +} + +//******************************************************** +//! @brief calculate temperature +//! +//! @return double temperature degC +//******************************************************** + +double ms5637::calcTemp() { + calcPT(); + return(T); +} + +//******************************************************** +//! @brief calculate pressure +//! +//! @return double barometric pressure millibar +//******************************************************** + +double ms5637::calcPressure() { + calcPT(); + return(P); +} + +//******************************************************** +//! @brief get pressure, no calculation +//! +//! @return double barometric pressure millibar +//******************************************************** + +double ms5637::getPressure() { + calcPT(); + return(P); +} + +//******************************************************** +//! @brief get altitude from known sea level barometer, +//! @ no pre-pressure calculation +//! +//! @enter float sea level barometer +//! @return float altitude in feet +//******************************************************** + +float ms5637::getAltitudeFT(float sea_pressure) { + A = (1 - (pow((P / (double)sea_pressure), 0.190284))) * 145366.45; + return((float)A); +} + +//******************************************************** +//! @brief get sea level pressure from known altitude(ft), +//! @ no pre-pressure calculation +//! +//! @enter float known altitude in feet +//! @return float seal level barometer in mb +//******************************************************** + +float ms5637::getSeaLevelBaroFT(float known_alt) { + S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt , 5.2553026) * MB; + return((float)S); +} + +//******************************************************** +//! @brief get sea level pressure from known altitude(m), +//! @ no pre-pressure calculation +//! +//! @enter float known altitude in meters +//! @return float seal level barometer in mb +//******************************************************** + +float ms5637::getSeaLevelBaroM(float known_alt) { + S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt * FTMETERS , 5.2553026) * MB; + return((float)S); +}
diff -r 2e8bc98f3dda -r 3a9d37268ccd ms5637.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ms5637.h Tue May 20 16:18:00 2014 +0000 @@ -0,0 +1,171 @@ +#ifndef MS5637H +#define MS5637_H + +#include "mbed.h" + + +#define SEA_PRESS 1013.25 //default sea level pressure level in mb +#define KNOWNALT 327.0 //default known altitude, 5200 Franklin Dr., 94588 +#define INHG 0.02952998751 //convert mb to in/Hg constant +#define MB 33.8638815 //convert in/Hg to mb constant +#define FTMETERS 0.3048 //convert feet to meters + + +/** Software routines to access the Measurement Specialties' MS5637-01BA03 + * Variometer Module using the I2C bus option. The MS5637 is a 24 bit + * temperature and pressure transducer for high accuracy Barometer and + * Altimeter applications. It also includes compensation coefficients + * stored within the device. + * + * Code adapted from Measurement Specialties: + * "AN520 C-code example for MS56xx, MS57xx (except analog sensor), and + * MS58xx series pressure sensors" + * + * Note: AN520 has not been updated for use with the MS5637. Changes + * were necessary to "calcPT()" in order to correct scaling of + * pressure readings. + * + * Features: + * Altitude resolution to 10cm + * Fast conversion down to 1 ms + * Low power, 1 μA (standby < 0.15 μA) + * QFN package 5.0 x 3.0 x 1.0 mm^3 + * Supply voltage 1.8 to 3.6 V + * Integrated digital pressure sensor (24 bit DeltaSigma ADC) + * Operating range: 10 to 1200 mbar, -40 to +85 °C + * I2C and SPI interface up to 20 MHz + * No external components (Internal oscillator) + * Excellent long term stability + * + * @code + * #include "mbed.h" + * #include "ms5637.h" + * + * ms5637 ms(p9, p10); // i2c pins used + * Serial pc(USBTX, USBRX); // local terminal interface + * + * + * int main (void) { + * pc.baud(921600); // set up USB serial speed + * + * // set up the ms5637 + * pc.printf("\n\nInitializing the MS5637..\n"); + * ms.cmd_reset(); + * pc.printf("Ready\n"); + * + * while(1) { + * double Temp = ms.calcTemp(); //calculate press and temp, then returns current temperature in degC + * double Press = ms.calcPressure(); //calculate press and temp, then returns current pressure in mb + * double GetPress = ms.getPressure(); //returns current pressure in mb. Does no calculations. Ususally done after calcTemp() + * double Altitude = ms.getAltitudeFT(1013.25); //enter pressure at sea level in mb, returns altitude in feet + * double PressSeaLvlFT = ms.getSeaLevelBaroFT(327.2); //enter known altitude in feet, returns sea level pressure in mb + * double PressSeaLvlM = ms.getAltitudeFT(99.73); //enter known altitude in meters, returns seal level pressure in mb + * + * pc.printf("Temp: %.2f degC\n", Temp); + * pc.printf("Barometer: %.1f mB %.3f in/Hg\n", Press, Press * 0.0295301); + * pc.printf("Alt: %.1f ft\n", Altitude); + * pc.printf("Sea_Lvl: %.1f ft %.2f m\n", PressSeaLvlFT, PressSeaLvlM); + * wait(2.0); + * } + * } + * + * @endcode + */ + +//_____ M A C R O S + +#define MS5637_ADDR_W 0xEC // Module address write mode CHANGED FOR 5637 ORIGINAL 0Xee +#define MS5637_ADDR_R 0xED // Module address read modeCHANGED FOR 5637 ORIGINAL 0XeF +#define MS5637_CMD_RESET 0x1E // ADC reset command +#define MS5637_CMD_ADC_READ 0x00 // ADC read command +#define MS5637_CMD_ADC_CONV 0x40 // ADC conversion command +#define MS5637_CMD_ADC_D1 0x00 // ADC D1 conversion +#define MS5637_CMD_ADC_D2 0x10 // ADC D2 conversion +#define MS5637_CMD_ADC_256 0x00 // ADC OSR=256 +#define MS5637_CMD_ADC_512 0x02 // ADC OSR=512 +#define MS5637_CMD_ADC_1024 0x04 // ADC OSR=1024 +#define MS5637_CMD_ADC_2048 0x06 // ADC OSR=2048 +#define MS5637_CMD_ADC_4096 0x08 // ADC OSR=4096 +#define MS5637_CMD_PROM_RD 0xA0 // Prom read command + + /** Create ms5637 controller class + * + * @param ms5637 class + * + */ +class ms5637 { + +public: + /** Create a MS5637 object using the specified I2C object + * + * @param constructor, - the I2C object to communicate with + */ + ms5637(PinName sda, PinName scl); + /** Initialize the MS5637 and set up the coefficients + * First - reset the MS5637 + * Second - load coefficient values from the MS5637 PROM + * Third - calculate coefficient checksum + * This routine only needs to be run once at boot up + * + * @param NONE + */ + void cmd_reset(); + /** Calculate and return compensated temperature + * Returns double temperature in degC + * + * @param NONE + */ + double calcTemp(); + /** Calculate and return compensated barometric pressure + * Returns double pressure in millibars + * + * @param NONE + */ + double calcPressure(); + /** Return compensated barometric pressure + * Returns double pressure in millibars + * DOES NOT RE-CALCULATE FIRST!!! + * Saves time if you calcTemp(); first + * + * @param NONE + */ + double getPressure(); + /** Calculate and returns altitude in feet + * Returns float altitude in feet + * + * @param float known pressure (mB) at sea level + */ + float getAltitudeFT(float sea_pressure); + /** Calculate and returns sea level baro + * Returns float seal level barometer in feet + * + * @param float known altitude in feet + */ + float getSeaLevelBaroFT(float known_alt); + /** Calculate and returns sea level baro + * Returns float seal level barometer in meters + * + * @param float known altitude in meters + */ + float getSeaLevelBaroM(float known_alt); + +private: + int m_i2c_start(bool readMode); + void m_i2c_stop(void); + unsigned char m_i2c_write(unsigned char data); + unsigned char m_i2c_readAck(void); + unsigned char m_i2c_readNak(void); + void m_i2c_send(char cmd); + void loadCoefs(); + unsigned long cmd_adc(char cmd); + unsigned int cmd_prom(char coef_num); + unsigned char crc4(unsigned n_prom[]); + void calcPT(); + unsigned int PTbuffer[8]; // calibration coefficients + +protected: + I2C _i2c; + + +}; +#endif