Go Down

Topic: MS5541 depth sensor communication (Read 53911 times) previous topic - next topic

nipzwick

Edited the library MS5541.cpp file for mega2560 and uno use.

#define mega2560 1 //if using mega2560 assign 1, UNO assign 0


if(mega2560 == 1){
      TCCR2B = (TCCR2B & 0xF8) | 1 ;
      analogWrite(9, 128);

}else{
      TCCR1B = (TCCR1B & 0xF8) | 1 ;
      analogWrite(9, 128);
}


Code: [Select]

#include <SPI.h>
#include "MS5541.h"
#define mega2560 1 //if using mega2560 assign 1, UNO assign 0

MS5541::MS5541() {
SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(9, OUTPUT);
  getCalibrationWord();
}

void MS5541::resetSensor() {
SPI.setDataMode(SPI_MODE0);
SPI.transfer(0x15);
SPI.transfer(0x55);
SPI.transfer(0x40);
}

void MS5541::update() {


if(mega2560 == 1){
TCCR2B = (TCCR2B & 0xF8) | 1 ;
analogWrite(9, 128);

}else{
TCCR1B = (TCCR1B & 0xF8) | 1 ;
analogWrite(9, 128);
}

//Pressure:
resetSensor();
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
 
//Temperature
resetSensor();
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

//calculate temp according to datasheet
dT = D2 - UT1;
if (dT < 0) {
dT2 = dT - (dT/128*dT/128)/2;
}
else {
dT2 = dT - (dT/128*dT/128)/8;
}

TEMP = (200 + dT*(C6+100)/pow(2,11))/10;
TEMPC = (200 + dT2*(C6+100)/pow(2,11))/10;

//calculate pressure according to datasheet
OFF = C2 + ((C4-250)*dT)/pow(2,12) + 10000;
SENS = C1/2 + ((C3+200)*dT)/pow(2,13) + 3000;
P = (SENS * (D1-OFF))/pow(2,11) + 1000;
}

float MS5541::getPressureMBar() {
return P;
}

float MS5541::getPressureBar() {
return P/1000.0;
}


float MS5541::getTemperatureC() {
return TEMP;
}

float MS5541::get2ndTemperatureC() {
return TEMPC;
}

float MS5541::getTemperatureF() {
return (TEMP*1.8)+32.0;
}

float MS5541::get2ndTemperatureF() {
return (TEMPC*1.8)+32.0;
}

void MS5541::getCalibrationWord() {
if(mega2560 == 1){
TCCR2B = (TCCR2B & 0xF8) | 1 ;
analogWrite(9, 128);

}else{
TCCR1B = (TCCR1B & 0xF8) | 1 ;
analogWrite(9, 128);

}

resetSensor();
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

resetSensor();
SPI.transfer(0x1D);
SPI.transfer(0x60);
SPI.setDataMode(SPI_MODE1);
result2 = SPI.transfer(0x00);
result2 = result2 <<8;
inbyte2 = SPI.transfer(0x00);
result2 = result2 | inbyte2;

resetSensor();
SPI.transfer(0x1D);
SPI.transfer(0x90);
SPI.setDataMode(SPI_MODE1);
result3 = SPI.transfer(0x00);
result3 = result3 <<8;
inbyte3 = SPI.transfer(0x00);
result3 = result3 | inbyte3;

resetSensor();
SPI.transfer(0x1D);
SPI.transfer(0xA0);
SPI.setDataMode(SPI_MODE1);
result4 = SPI.transfer(0x00);
result4 = result4 <<8;
inbyte4 = SPI.transfer(0x00);
result4 = result4 | inbyte4;

C1 = result1 >> 3 & 0x1FFF;
C2 = ((result1 & 0x07) << 10) | ((result2 >> 6) & 0x03FF);
C3 = (result3 >> 6) & 0x03FF;
C4 = (result4 >> 7) & 0x07FF;
C5 = ((result2 & 0x003F) << 6) | (result3 & 0x003F);
C6 = result4 & 0x007F;
UT1 = 8*C5 + 10000;
}

IgorP

Hi,

I am using a version of the library that I changed to work with MS5535 sensor.
I am using it with Teensy 3.1 and AdafruitST7735 TFT. The problems I have are not being able to read data from the pressure sensor as soon as I want to use the TFT.

Code: [Select]
#define sclk 13  // SCLK can also use pin 14
#define mosi 11  // MOSI can also use pin 7
#define cs   10  // CS & DC can use pins 2, 6, 9, 10, 15, 20, 21, 22, 23
#define dc   9   //  but certain pairs must NOT be used: 2+10, 6+9, 20+23, 21+22
#define rst  8   // RST can use any pin
#define sdcs 4   // CS for SD card, can use any pin
#define lite 5   // TFT backlite
#define presscs 6 // Pressures sensor cs
#define miso 12 //MISO

#include <MS55xx.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

#if defined(__SAM3X8E__)
   #undef __FlashStringHelper::F(string_literal)
   #define F(string_literal) string_literal
#endif

//Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, mosi, sclk, rst);

//creating the sensor

MS55xx PressSensor;
float airPressure;
float waterPressure=0;

void setup() {
   pinMode(sdcs, INPUT_PULLUP);  
   Serial.begin(9600);    
   pinMode(presscs, OUTPUT);
   digitalWrite(presscs, HIGH);      
   pinMode(5, OUTPUT);
   digitalWrite(5, HIGH);
   pinMode(23, OUTPUT);
   digitalWrite(23, HIGH);
   
   tft.initR(INITR_BLACKTAB);
   tft.setRotation(tft.getRotation()+1);
   tft.fillScreen(ST7735_BLACK);
   
   PressSensor.setPressureSensorType(5535);
   //start arduino before diving
   //otherwise a 1.0 bar is used as surface pressure
   digitalWrite(presscs, LOW);
   delay(10);
   PressSensor.update();
   digitalWrite(presscs, HIGH);
   airPressure = PressSensor.getPressureBar();
   if (airPressure > 1.2) {
     airPressure = 1.0;
   }
   tft.fillScreen(ST7735_BLACK);
}

void loop() {
 //Before getting the values you need to update the sensor
 digitalWrite(presscs, LOW);
 delay(10);
 PressSensor.update();
 digitalWrite(presscs, HIGH);
 //get pressure
 waterPressure = PressSensor.getPressureBar() - airPressure;
 Serial.print("Deep (meters): ");
 Serial.println(abs(waterPressure)*10.0,1);
 
 tft.setTextSize(2);
 tft.setCursor(0,0);
 tft.setTextColor(ST7735_GREEN);
 tft.println(abs(waterPressure)*10.0,1);
 
 //get 2nd temperature --> see datasheet for details
 Serial.print("Temperatre 2nd (celsius): ");
 //Serial.println(PressSensor.get2ndTemperatureC());
 
 Serial.println();
 
 delay(2000);
}


I added in library another line in both the Update() method and read Coeficients method the line
Code: [Select]

SPI.setDataMode(SPI_MODE0);
to alow AdafruitST7735 to work correctely.

Problem that remain is no correct data from pressure sensor.

Can anyone help?

robtillaart

@IgorP
Can it be that you have not enough power?
Can you measure the voltage?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

IgorP

I think there should be more than enough power. TFT works fine, just data from pressure sensor not correct. I run Teensy from USB and sensor from Teensy 3.3 voltage output.

Was thinking about SCLK signal. SPI clock divider is set in TFT library to 21....don't kniw if that is not too high signal click for sensor..   skould be max 500kHz

IgorP

I think there should be more than enough power. TFT works fine, just data from pressure sensor not correct. I run Teensy from USB and sensor from Teensy 3.3 voltage output.

Was thinking about SCLK signal. SPI clock divider is set in TFT library to 21....don't kniw if that is not too high signal click for sensor..   skould be max 500kHz
Anyway where should I measure power supply? At sensor or??

IgorP

Supply voltage to sensor is 3.2 V

IgorP

I think it is CS problem, seem AdafruitST7735 is somehow preventing me from manualy manipulating CS for the sensor. As soon as I initialize the tft I lost sensor data. Does someone know how to solve this problem?

I attach the library and examples. The MS55xx eksample is MS5541 modified library to work with MS5535 too on Teensy 3.1 board. The example for mentioned problem is MA55xx_underwater_test

IgorP

Adafruit updated thrir library per last standards in SPI communication and now I finaly have a solution iny hands. Will post links to the thread with updated ST7735 library and new version of MS55xx library updated to same standard.

Thanks to all that tried to behelpful!!


abidhaque

Hi,

I'm trying to use an ms5541-cm sensor with an arduino uno. I'm new to the forum, and would really appreciate some help.

I used the code from -

Hi all,
I wrapped up the code and commented it out. To close the case I will post a sketch to read out all calibration words and one which shows how to include the extracted calibration factors into a sketch to avoid reading these constants all the time while using the sensor in whatever application.
MS5541_read_all.pde
Code: [Select]

/*
 MS5541 Pressure Sensor calwords readout
 This program will read your MS5441 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:
 MS5541 sensor attached to pins 10 - 13:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13
 MCLK: pin 9
 CS is not in use, but might be pin 10
 
 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. Thanks!
 */

// 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);
}



PS: Un-voided the resetsensor call as of today, Nov 25 2011.
But the calibration values keep fluctuating, and so do compensated temperature and pressure values.

Calibration word 1 =0
Calibration word 2 =0
Calibration word 3 =0
Calibration word 4 =65535
0
0
0
511
0
127
Temperature raw =0
Pressure raw =65535
Real Temperature in °C=-90.00
Compensated pressure in mbar =38782
2nd order compensated temperature in °C =-90.00
Calibration word 1 =65535
Calibration word 2 =65535
Calibration word 3 =65535
Calibration word 4 =65535
8191
8191
1023
511
4095
127
Temperature raw =0
Pressure raw =0
Real Temperature in °C=-454.00
Compensated pressure in mbar =-1685
2nd order compensated temperature in °C =-453.00

hrishi104

I know its silly question but i am not able to find register address for sensor can you please tell me from where you got this addressed in your code?

/Sensor memory register addresses:
const int PRESSURE = 0x0F;      //MSB pressure
const int PRESSURE_LSB = 0x40;  //LSB of pressure
const int TEMPERATURE = 0x0F;   //MSB temperature
const int TEMPERATURE_LSB = 0x20;  //LSB temperature
const int W1M = 0x1D; // MSB Calibration word 1
const int W1L = 0x50; // LSB Calibration word 1
const int W2M = 0x1D; // MSB Calibration word 2
const int W2L = 0x60; // LSB Calibration word 2
const int W3M = 0x1D; // MSB Calibration word 3
const int W3L = 0x90; // LSB Calibration word 3
const int W4M = 0x1D; // MSB Calibration word 4
const int W4L = 0xA0; // LSB Calibration word 4
const byte RST1 = 0x15; //Reset sequence word 1
const byte RST2 = 0x55; //Reset sequence word 2
const byte RST3 = 0x40; //Reset sequence word 3

Go Up