Help with a barometric sensor: MS5535C

Hello everyone. I'm working on a project that incorporates a Measurement Specialties Barometric Sensor, MS5535C (http://www.meas-spec.com/product/t_product.aspx?id=5029).

There is a similar sensor, the MS5534C, that has some Arduino code which I've based my own sketch off of (http://blog.ulrichard.ch/?p=23). Unfortunately, I'm getting garbage from the outputs of sensor, leading me to believe that I'm putting garbage in. I'm not exactly sure if I'm addressing the MS5535C correctly, and as it's my first time with a sensor of this sort, I'm turning to the forums for help.

The sensor data sheet (http://www.meas-spec.com/downloads/MS5535C.pdf) says:

The MS5535C communicates with microprocessors and other digital systems via a 3-wire synchronous serial interface as shown in Fig. 1.

My sketch looks like this, and it complies, loads and runs without trouble:

/*
  /*
  Reading the pressure from an intersema barometric pressure sensor
 
 
 By Richard Ulrich
 */

#include <Arduino.h>


// The circuit:
// * Intersema MS5534C connected to the following pins:.
static const uint8_t pinBaroSCLK  =   8;
static const uint8_t pinBaroDOUT  =   1; // in  on the arduino
static const uint8_t pinBaroDIN   =   0; // out on the arduino
static const uint8_t pinBaroMCLK  =   9; // the tone function used to generate the 34kHz signal interferes with pin 3 and 11, so it's best to use it directly

unsigned int coefficients[6];
uint32_t temperature;
uint32_t pressure;


void setup()   
{    

  // set the pin directions
  pinMode(pinBaroMCLK, OUTPUT);
  pinMode(pinBaroSCLK, OUTPUT);
  pinMode(pinBaroDIN,  OUTPUT);
  pinMode(pinBaroDOUT, INPUT);

  Serial.begin(9600);

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

}

void loop()                     
{  
  ReadCoefficients();
  for(size_t i=0; i<6; ++i)
  {
    Serial.print("Coefficient ");
    Serial.print(i + 1, DEC);
    Serial.print(" : ");
    Serial.println(coefficients[i], DEC);
  }

  temperature = ReadTemperature();

  pressure = ReadPressure();

  ConvertPressureTemperature(pressure, temperature);

  Serial.print("Pressure: ");
  Serial.println(pressure, DEC);

  Serial.print("Temperature: ");
  Serial.println(temperature, DEC);


  Serial.println(" ");
  delay(2000);
}

/*
 * Interface to Intersema Barometric pressure sensor.
 * For the moment, only the following sensors are supported:
 * MS5534C though manual protocol
 * MS5607B through I2C
 * Others might be added in the future.
 *
 * Created 14 Jan 2010
 * By Richard Ulrich
 * Inspired by the work of Hari Nair
 * 
 * Added support for the MS5607B I2C : 7 Jan 2011
 */

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

void ReadCoefficients(void)
{   
  ResetSensor();
  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);
}

size_t 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();
}

void SendCommand(unsigned long cmd, size_t nbits)
{
  while(nbits--)  
  {
    if(cmd & (unsigned long)(1 << nbits)) 
      digitalWrite(pinBaroDIN, HIGH); 
    else 
      digitalWrite(pinBaroDIN, LOW); 

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

unsigned int ReadWord(void)
{
  unsigned int w;
  unsigned int clk = 16;
  w = 0;
  while(clk--)  
  {
    digitalWrite(pinBaroSCLK, HIGH); 
    digitalWrite(pinBaroSCLK, LOW);             
    w |=  (digitalRead(pinBaroDOUT) << clk);
  }
  digitalWrite(pinBaroSCLK, HIGH); 
  digitalWrite(pinBaroSCLK, LOW);  

  return w;
}

uint32_t ReadTemperature(void)
{
  // 111 + 1001 + 000 + 2clks(send 0)
  ResetSensor();
  SendCommand(0xF20, 12);
  while(digitalRead(pinBaroDOUT));
  const unsigned int temperature = ReadWord();
  return temperature;
}

uint32_t ReadPressure(void)
{
  // 111 + 1010 + 000 + 2clks(send 0)
  ResetSensor();
  SendCommand(0xF40, 12);
  while(digitalRead(pinBaroDOUT));
  const unsigned int pressure = ReadWord(); // read pressure
  return pressure;
}

void ConvertPressureTemperature(uint32_t pressure, uint32_t temperature)
{
  const long UT1  = (coefficients[4] << 3) + 20224;
  const long dT   = 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;
  } 
}

The output that I'm getting from the serial monitor looks like this:

Coefficient 1 : 32767
Coefficient 2 : 4095
Coefficient 3 : 1023
Coefficient 4 : 1023
Coefficient 5 : 2047
Coefficient 6 : 63
Pressure: 8161
Temperature: 16256
 
Coefficient 1 : 32767
Coefficient 2 : 4095
Coefficient 3 : 1023
Coefficient 4 : 1023
Coefficient 5 : 2047
Coefficient 6 : 63
Pressure: 8161
Temperature: 16320
 
Coefficient 1 : 32767
Coefficient 2 : 4095
Coefficient 3 : 1023
Coefficient 4 : 1023
Coefficient 5 : 2047
Coefficient 6 : 63
Pressure: 8161
Temperature: 16256

My suspicion is that I've done something wrong with the baud rate, and I'm getting garbage from the sensor, but I have no way of knowing for sure. Perhaps someone with expertise could weigh in. Thanks in advance! :slight_smile:

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

  • that is 10% off !! that means after 10 bits the device got an errorreading :frowning:

I recognize the code, think it is resolved earlier .. doing some googling ...

Thanks,

According to the data sheet, the sensor will accept clock values between 30 kHz and 35 kHz, and 40/60 and 60/40 duty cycling. This is a tricky topic for goggling. I'm regretting not getting the I2C version of this sensor...

Found the code I was looking for, It is a sensor with similar code - same manufacturer - same hardware ?

You might need to make some vars unsigned long iso long to prevent overflow.

Looks like a great source to help solve my problem. I'll have a go at implementing this tonight and report back with the code that works for me.

Thank you for digging this up!

you are welcome, next time you might help me out :wink:

SHAZAM! The code for the MS5541C works with the MS5535C! I'm just going to tidy up the code a little bit and work on understanding it and I'll post my MS5535C code here:

/*
 MS5535C Pressure Sensor calwords readout
 This program will read your MS5535C or compatible pressure sensor every 5 seconds and show you the calibration words, the calibration factors, 
 the raw values and the compensated values of temperature and pressure.
 Once you read out the calibration factors you can define them in the header of any sketch you write for the sensor.
 
Pins:
 MS5535C sensor attached to pins 10 - 13:
 DIN (MOSI): pin 11
 DOUT (MISO): pin 12
 SCLK: pin 13
 MCLK: pin 9
 
 Created August 2011 by SMStrauch based on application note AN510 from www.intersema.ch (http://www.meas-spec.com/downloads/Using_SPI_Protocol_with_Pressure_Sensor_Modules.pdf), 
 and with help of robtillaart and ulrichard.
 
 Modified February 2012 by spincrisis for the MS5535C.
 */

// include library:
#include <SPI.h>

// generate a MCKL signal pin
const int clock = 9;

void resetsensor() //this function keeps the sketch a little shorter
{
  SPI.setDataMode(SPI_MODE0); 
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
}

void setup() {
  Serial.begin(9600);
  SPI.begin(); //see SPI library details on arduino.cc for details
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT);
  delay(100);
}

void loop() 
{
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite (clock, 128) ; 

  resetsensor();//resets the sensor - caution: afterwards mode = SPI_MODE0!

  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D); //send first byte of command to get calibration word 1
  SPI.transfer(0x50); //send second byte of command to get calibration word 1
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  result1 = SPI.transfer(0x00); //send dummy byte to read first byte of word
  result1 = result1 << 8; //shift returned byte 
  inbyte1 = SPI.transfer(0x00); //send dummy byte to read second byte of word
  result1 = result1 | inbyte1; //combine first and second byte of word
  Serial.print("Calibration word 1 =");
  Serial.println(result1);

  resetsensor();//resets the sensor

  //Calibration word 2; see comments on calibration word 1
  unsigned int result2 = 0;
  byte inbyte2 = 0; 
  SPI.transfer(0x1D);
  SPI.transfer(0x60);
  SPI.setDataMode(SPI_MODE1); 
  result2 = SPI.transfer(0x00);
  result2 = result2 <<8;
  inbyte2 = SPI.transfer(0x00);
  result2 = result2 | inbyte2;
  Serial.print("Calibration word 2 =");
  Serial.println(result2);  

  resetsensor();//resets the sensor

  //Calibration word 3; see comments on calibration word 1
  unsigned int result3 = 0;
  byte inbyte3 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x90); 
  SPI.setDataMode(SPI_MODE1); 
  result3 = SPI.transfer(0x00);
  result3 = result3 <<8;
  inbyte3 = SPI.transfer(0x00);
  result3 = result3 | inbyte3;
  Serial.print("Calibration word 3 =");
  Serial.println(result3);  

  resetsensor();//resets the sensor

  //Calibration word 4; see comments on calibration word 1
  unsigned int result4 = 0;
  byte inbyte4 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0xA0);
  SPI.setDataMode(SPI_MODE1); 
  result4 = SPI.transfer(0x00);
  result4 = result4 <<8;
  inbyte4 = SPI.transfer(0x00);
  result4 = result4 | inbyte4;
  Serial.print("Calibration word 4 =");
  Serial.println(result4);

  //now we do some bitshifting to extract the calibration factors 
  //out of the calibration words; read datasheet AN510 for better understanding
  long c1 = result1 >> 3 & 0x1FFF;
  long c2 = ((result1 & 0x07) << 10) | ((result2 >> 6) & 0x03FF);
  long c3 = (result3 >> 6) & 0x03FF;
  long c4 = (result4 >> 7) & 0x07FF;
  long c5 = ((result2 & 0x003F) << 6) | (result3 & 0x003F);
  long c6 = result4 & 0x007F;

  Serial.println(c1);
  Serial.println(c2);
  Serial.println(c3);
  Serial.println(c4);
  Serial.println(c5);
  Serial.println(c6);

  resetsensor();//resets the sensor

  //Temperature:
  unsigned int tempMSB = 0; //first byte of value
  unsigned int tempLSB = 0; //last byte of value
  unsigned int D2 = 0;
  SPI.transfer(0x0F); //send first byte of command to get temperature value
  SPI.transfer(0x20); //send second byte of command to get temperature value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  tempMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  tempMSB = tempMSB << 8; //shift first byte
  tempLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D2 = tempMSB | tempLSB; //combine first and second byte of value
  Serial.print("Temperature raw =");
  Serial.println(D2); //voilá!

  resetsensor();//resets the sensor

  //Pressure:
  unsigned int presMSB = 0; //first byte of value
  unsigned int presLSB =0; //last byte of value
  unsigned int D1 = 0;
  SPI.transfer(0x0F); //send first byte of command to get pressure value
  SPI.transfer(0x40); //send second byte of command to get pressure value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  presMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  presMSB = presMSB << 8; //shift first byte
  presLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D1 = presMSB | presLSB; //combine first and second byte of value
  Serial.print("Pressure raw =");
  Serial.println(D1);

  //calculation of the real values by means of the calibration factors and the maths
  //in the datasheet. const MUST be long
  const long UT1 = (c5 << 3) + 10000;
  const long dT = D2 - UT1;
  const long TEMP = 200 + ((dT * (c6 + 100)) >> 11);
  const long OFF  = c2 + (((c4 - 250) * dT) >> 12) + 10000;
  const long SENS = (c1/2) + (((c3 + 200) * dT) >> 13) + 3000;
  long PCOMP = (SENS * (D1 - OFF) >> 12) + 1000;
  float TEMPREAL = TEMP/10;
  

  Serial.print("Real Temperature in °C=");
  Serial.println(TEMPREAL);

  Serial.print("Compensated pressure in mbar =");
  Serial.println(PCOMP);

  //2nd order compensation only for T > 0°C
  const long dT2 = dT - ((dT >> 7 * dT >> 7) >> 3);
  const float TEMPCOMP = (200 + (dT2*(c6+100) >>11))/10;
  Serial.print("2nd order compensated temperature in °C =");
  Serial.println(TEMPCOMP);  

  delay(5000);
}

Thank you for pointing me in the right direction.

Welcome,

Hi All!
I am very new and very inexperienced with programming and could really use some help. I can do a little in PIC Basic and have no idea how to read the "C" language. It would be nice not to have to learn another programming language right now. I am trying to get an MS5541 to work in PIC Basic. Does anyone have the program or know where to find the program in PIC Basic? I would really appreciate any and all help I can get. Thank you in advance. Best, Ed

Have you tried a PIC BASIC forum?
Here, we try to help wean people off BASIC.

Thank you and you are right. I was actually pointed here by a PIC forum. It just makes it a little easier if you can understand everything in the language you already know before trying to write in a language you do not know. :wink: