Arduino Code for the MS5534C Intersema pressure sensor

After receiving personal messages on the arduino forum asking for the code for the Intersema pressure sensor, I paste my code here. It is based on the code from Hari Nair for the open source solar vario that I bought from him.

I use it in my ChopperControl project which is not quite ready for releasing right now. It’s about controlling an RC helicopter from the openmoko freerunner smartphone over a bluetooth link.

I ported the code to the Arduino. Later, I learned about SPI, and asked Hari, if it was possible to interface it with SPI. He told me that it’s not really thought that way, but possible. He sent me a note from Intersema describing that.

In the meantime, Intersema released a sensor with I2C interface which I’m going to order some soon.

Uploading the packed file didn’t work at the moment, so I pasted them below. I will upload the files as soon as I figure out how…

*******************   IntersemaBaro.h :  **********************

/*
* Interface to Intersema Barometric pressure sensor.
* For the moment, only the MS5534C is supported.
* Others might be added in the future, especially the one with I2C.
*
* Created 14 Jan 2010
* By Richard Ulrich
* Inspired by the work of Hari Nair
*/
#ifndef INTERSEMA_BARO_H
#define INTERSEMA_BARO_H

#include <WProgram.h>

class  BaroPressure_MS5534C
{
public:
BaroPressure_MS5534C(uint8_t pinMCLK, uint8_t pinSCLK, uint8_t pinDIN, uint8_t pinDOUT);

void begin();

long getHeightCentiMeters(void)
{
return AcquireAveragedSampleCm(NUM_SAMP_FOR_AVG);
}

long getHeightMeters(void)
{
long AltCm = getHeightCentiMeters();
long AltAvgM  = (AltCm >= 0 ? (AltCm + 50L) / 100L : (AltCm – 50L) / 100L);
return AltAvgM;
}

private:
void ResetSensor();
void ReadCoefficients(void);
size_t ReadCoefficient(unsigned char addr);
void SendCommand(unsigned long cmd, size_t nbits);
unsigned int ReadWord(void);
long AcquireAveragedSampleCm(const size_t nSamples);
long ConvertPressureTemperature(unsigned int pressure, unsigned int temperature);
void TriggerTemperatureSample(void);
void TriggerPressureSample(void);
long PascalToCentimeter(long pressurePa);

enum SensorStates
{
SENSOR_READ_TEMPERATURE
};

static const size_t NUM_SAMP_FOR_AVG = 4;

const uint8_t pinMCLK_; // master clock 32.5 kHz
const uint8_t pinSCLK_; // serial clock
const uint8_t pinDIN_;  // data in  (out on the arduino)
const uint8_t pinDOUT_; // data out (in  on the arduino)

unsigned int coefficients_[6];
SensorStates SensorState_;
size_t       SmpCnt_;
};

#endif

*******************   IntersemaBaro.cpp :  **********************

/*
* Interface to Intersema Barometric pressure sensor.
* For the moment, only the MS5534C is supported.
* Others might be added in the future, especially the one with I2C.
*
* Created 14 Jan 2010
* By Richard Ulrich
* Inspired by the work of Hari Nair
*/

#include “IntersemaBaro.h”
//#include “cppfix.h”

//using namespace Intersema;

/** @brief Constructur initializes the pins, reads the coefficients and reads a first altutude measurement. */
BaroPressure_MS5534C::BaroPressure_MS5534C(uint8_t pinMCLK, uint8_t pinSCLK, uint8_t pinDIN, uint8_t pinDOUT)
: pinMCLK_(pinMCLK), pinSCLK_(pinSCLK), pinDIN_(pinDIN), pinDOUT_(pinDOUT)
{

}

/** @brief initialization function that has to be called in the setup() function. */
void BaroPressure_MS5534C::begin()
{
// set the pin directions
pinMode(pinMCLK_, OUTPUT);
pinMode(pinSCLK_, OUTPUT);
pinMode(pinDIN_,  OUTPUT);
pinMode(pinDOUT_, INPUT);

// generate approx 34kHz square for pinMCLK_
tone(pinMCLK_, 31250);

// configure the sensor
ResetSensor();
ReadCoefficients();

// initialize
long alt = AcquireAveragedSampleCm(NUM_SAMP_FOR_AVG);
TriggerTemperatureSample();
SensorState_ = SENSOR_READ_TEMPERATURE;
}

void BaroPressure_MS5534C::ResetSensor()
{
SendCommand(0x155540, 21); // 1010101010101010 + 00000
}

void BaroPressure_MS5534C::ReadCoefficients(void)
{
unsigned int wa = ReadCoefficient(0x15);
unsigned int wb = ReadCoefficient(0x16);
coefficients_[0] = (unsigned int)((wa >> 1) & (unsigned int)0x7FFF);
coefficients_[4] = (unsigned int)(((wa & 0x1) << 10) | ((wb >> 6) & (unsigned int)0x3FF));
coefficients_[5] = (unsigned int)(wb & 0x3F);

wa = ReadCoefficient(0x19);
wb = ReadCoefficient(0x1A);
coefficients_[3] = (unsigned int)((wa >> 6) & 0x3FF);
coefficients_[1] = (unsigned int)(((wa & 0x3F) << 6) | (wb & 0x3F));
coefficients_[2] = (unsigned int)((wb >> 6) & 0x3FF);

#ifdef DEBUG
//    for(size_t i=0; i<6; ++i)
//        {
//            Serial.print(“Coefficient “);
//            Serial.print(i + 1, DEC);
//            Serial.print(” : “);
//            Serial.println(coefficients_[i], DEC);
//    }
#endif
}

size_t BaroPressure_MS5534C::ReadCoefficient(unsigned char addr)
{
// 111 + 6bit coeff addr + 000 + 1clk(send0)
unsigned long cmd = (unsigned long)0x1C00 | (((unsigned long)addr) << 4);
SendCommand(cmd,13);
return ReadWord();
}

// send command MS bit first
void BaroPressure_MS5534C::SendCommand(unsigned long cmd, size_t nbits)
{
while(nbits–)
{
if(cmd & (unsigned long)(1 << nbits))
digitalWrite(pinDIN_, HIGH);
else
digitalWrite(pinDIN_, LOW);

digitalWrite(pinSCLK_, HIGH);
digitalWrite(pinSCLK_, LOW);
}
}

unsigned int BaroPressure_MS5534C::ReadWord(void)
{
unsigned int w;
unsigned int clk = 16;
w = 0;
while(clk–)
{
digitalWrite(pinSCLK_, HIGH);
digitalWrite(pinSCLK_, LOW);
w |=  (digitalRead(pinDOUT_) << clk);
}
digitalWrite(pinSCLK_, HIGH);
digitalWrite(pinSCLK_, LOW);

return w;
}

long BaroPressure_MS5534C::AcquireAveragedSampleCm(const size_t nSamples)
{
long pressAccum = 0;

for(size_t n = nSamples; n; n–)
{
TriggerTemperatureSample();
while(digitalRead(pinDOUT_))
;
const unsigned int temperature = ReadWord();
TriggerPressureSample();
while(digitalRead(pinDOUT_))
;
const unsigned int pressure = ReadWord(); // read pressure
pressAccum += ConvertPressureTemperature(pressure, temperature);
}
long pressAvg = pressAccum / nSamples;
long AltCm    = PascalToCentimeter(pressAvg * 10);

return AltCm;
}

long BaroPressure_MS5534C::ConvertPressureTemperature(unsigned int pressure, unsigned int temperature)
{
const long UT1  = (coefficients_[4] << 3) + 20224;
const long dT   = (long)temperature  – UT1;
const long TEMP = 200 + ((dT * (coefficients_[5] + 50)) >> 10);
const long OFF  = (coefficients_[1] <<2) + (((coefficients_[3] -512) * dT) >> 12);
const long SENS = coefficients_[0]  + ((coefficients_[2] * dT) >> 10)  + 24576;
const long X    = ((SENS* ((long)pressure  – 7168)) >> 14) – OFF;
pressure    = ((X * 10) >> 5) + 2500;
temperature = TEMP;

long T2 = 0, P2 = 0;
if(TEMP < 200)
{
T2 = (11 * (coefficients_[5] + 24) * (200 – TEMP) * (200 – TEMP)) >> 20;
P2 = (3 * T2 * (pressure – 3500)) >> 14;
pressure    = pressure – P2;
temperature = temperature – T2;
}

return pressure;
}

void BaroPressure_MS5534C::TriggerTemperatureSample(void)
{
// 111 + 1001 + 000 + 2clks(send 0)
ResetSensor();
SendCommand(0xF20, 12);
}

void BaroPressure_MS5534C::TriggerPressureSample(void)
{
// 111 + 1010 + 000 + 2clks(send 0)
ResetSensor();
SendCommand(0xF40, 12);
}

long BaroPressure_MS5534C::PascalToCentimeter(long pressurePa)
{
// Lookup table converting pressure in Pa to altitude in cm.
// Each LUT entry is the altitude in cm corresponding to an implicit
// pressure value, calculated as [PA_INIT – 1024*index] in Pa.
// The table is calculated for a nominal sea-level pressure  = 101325 Pa.
static const size_t PZLUT_ENTRIES = 77;
static const size_t PA_INIT       = 104908;
static const size_t PA_DELTA      = 1024;

static const long lookupTable[PZLUT_ENTRIES] = {
-29408, -21087, -12700,  -4244,   4279,
12874,  21541,  30281,  39095,  47986,
56953,  66000,  75126,  84335,  93628,
103006, 112472, 122026, 131672, 141410,
151244, 161174, 171204, 181335, 191570,
201911, 212361, 222922, 233597, 244388,
255300, 266334, 277494, 288782, 300204,
311761, 323457, 335297, 347285, 359424,
371719, 384174, 396795, 409586, 422552,
435700, 449033, 462560, 476285, 490216,
504360, 518724, 533316, 548144, 563216,
578543, 594134, 609999, 626149, 642595,
659352, 676431, 693847, 711615, 729752,
748275, 767202, 786555, 806356, 826627,
847395, 868688, 890537, 912974, 936037,
959766, 984206};

if(pressurePa > PA_INIT)
return lookupTable[0];
else
{
const long inx = (PA_INIT – pressurePa) >> 10;
if(inx >= PZLUT_ENTRIES – 1)
return lookupTable[PZLUT_ENTRIES – 1];
else
{
const long pa1 = PA_INIT – (inx << 10);
const long z1 = lookupTable[inx];
const long z2 = lookupTable[inx+1];
return (z1 + (((pa1 – pressurePa) * (z2 – z1)) >> 10));
}
}
}

3 Replies to “Arduino Code for the MS5534C Intersema pressure sensor”

  1. Dear Sir,
    I am a student at a German High School and we bought for a project the pressure sensor MS5534C. I would like to use an Arduino Uno. Is the coding on your website ok for the arduino?
    It does not work for me. Maybe you can send me your source code as txt.
    My Error:

    exit status 1
    expected ‘)’ before ‘pinMCLK’

    at line 20

    Thanks a lot.
    Kind regards

    1. Sorry for the late reply.
      I didn’t use this code in a very long time.
      Yes it is for Arduino, but for an ancient version. I don’t use Arduino that much these days, but I can remember that the main include file changed. It is probably no longer WProgram.
      Anyway, I copied the code into an Arduino IDE, and it compiled.
      Can you send me your files, so I can have a look at it?

Leave a Reply

Your email address will not be published. Required fields are marked *