Go Down

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

godo

#15
Aug 25, 2011, 07:37 pm Last Edit: Aug 25, 2011, 08:45 pm by godo Reason: 1
.... and just because it was to much to put it in one post:


MS5541_demo.pde
Code: [Select]

/*
MS5541 Pressure Sensor demonstration sketch
To obtain the calibration factors run the read-calwords-sketch before.

Circuit:
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 librariy:
#include <SPI.h>

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

//include the calibration factors according to your individual sensor; they MUST be long for internal calculation of the compensated values
//intersema.ch provides a file with expected values
const long c1 = 2723;
const long c2 = 4648;
const long c3 = 388;
const long c4 = 224;
const long c5 = 2309;
const long c6 = 54;

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();
 SPI.setBitOrder(MSBFIRST);
 SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
 pinMode(clock, OUTPUT); //sets clockpin on output
}

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

 void resetsensor(); //resets the sensor, be aware SPI remains in Mode 0 afterwards!

 //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á!

 void 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 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;
 //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("Real Temperature [°C]=");
 Serial.println(TEMPREAL);

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

 Serial.print("2nd order compensated temperature [°C] =");
 Serial.println(TEMPCOMP);  

 delay(5000);
}



Any comments are welcome, and please tell me about your applications with the sensor.

robtillaart

¡Bien hecho ;)

Might include the link to the datasheet in the code
Rob Tillaart

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

godo


godo

#18
Oct 12, 2011, 03:37 pm Last Edit: Jan 26, 2012, 03:03 pm by godo Reason: 1
Hi folks,
and on it goes: I have a new riddle to solve!
Since my project requires quite some memory I decided to upgrade and made myself a neat little Sanguino clone board. It works nicely, I downloaded and installed awesome stuff from here http://avr-developers.com/corefiles/index.html and some Sanguino board data I do not remember from where. It runs both with the Ardu-Duino 644P and Sanguino board settings (but that's probably obvious).
Then I tested sketches I already used on my 2009 as this one... no wait, it is far to long. It is the AnalogLogger example from the SdFat-library which I adapted and added a DS18B20. Unfortunately I only figured out the code formally and adapted it without deep understanding. But it runs like a charm logging 4 analog inputs and digital temperature via SPI onto a µSD-Card. So far so good.
Now comes the riddle: I also adapted the code I displayed in this post but it won't work. There aren't even osci-spikes on the SCK line which I clearly saw running the SdFat-based code. So to me it looks like the sketch doesn't access the SPI-Bus at all, even though I adjusted the PINs to the right ones on the 644 (SS 4, MOSI 5, MISO 6, SCK 7). So - more of a general understanding question - where exactly does the SdFat library access the information about the PIN configuration? And where do I have to give the SPI library that information (I copied and included ArduinoPins.h from the SdFat diractory, but it didn't help)?
Can anybody tell me more about the compiling process, I mean, by selecting a specific board, do I already direct the compiler to a specific file in which the PIN configuration is given or do the respective libraries do that independently of the board I chose; it seems to me a valuable general info and a good point to look for the problem.
Thanks in advance, any comment is apreciated, greetings from Patagonia
Seb

PS: Problem solved with help from Nick. If you modify a .h-file NEVER copy-paste the code but type it. If copy-pasted the changes are visible, appear totally normal but the compiler does not read it properly.

buton

Hey this is great I just bought the sensor and it is pretty small, how did you manage to solder it, any recommendations?

What did you use for the 32.768. khz clock? I bought t a DS32khz/ 14-dip .. http://www.maxim-ic.com/datasheet/index.mvp/id/2940
I will be using an arduino pro mini for the 3.3 volts that the sensor requires.

I will be use this a diving depth logger..

So I will keep you inform.

Thanks for the code I will try it, any more tips?
visit www.diveduino.com

godo

Hi there,
soldering that little one is a royal pain in the ... soldering hand, I can tell you. End of this week I will try it with a reflow oven, but up to now I managed with no clean flux and a lot of patience. Good luck anyway; if you use SPI for datalogging you will have to put a 74HC125 or so into the DOUT line to avoid interfering of the sensor with the sd-card. And THAT one is a demanding little bugger to solder!
This codeline
Code: [Select]
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite (clock, 128) ;
takes care of the signal on pin 9. It is not possible to use any pin but the timer pin, so do not simply switch it. It will allow you to skip the extra chip, so it might be an elegant possibility to keep it all small.
Good luck and share your progress and chalenges, by all means!

buton

Thanks for the info..

did you ever tried to do it without using the SPI? i don really want to add the 74HC125...but i will have to try it.. or maybe storing values in an external memory and then export it through serial port will be another idea..

i will keep you posted..
visit www.diveduino.com

buton

it was quite a challenge to solder this but and i do not if i broke the sensor for over-heating XD

this is what i go on the serial port when reading the calibration words...


Calibration word 1 =18820
Calibration word 2 =35237
Calibration word 3 =22501
Calibration word 4 =27826
2352
4646
351
217
2405
50
Temperature raw =65535
Pressure raw =65535
Real Temperature in °C=285.00
Compensated pressure in mbar =-209082
2nd order compensated temperature in °C =285.00


some of the values are pretty similar to yours...

but the temperature somehow is not working.. another interesting think is that i am using a 8 MHZ  arduino not the 16....

so i wonder if the divider is set correctly for the frequency...

thanks
visit www.diveduino.com

buton

second try i hooked the 32.768 khz clock i bought directly to the sensor and things got better

first reading is good, second reading is bad...


Temperature raw =30027
Pressure raw =2047
Real Temperature [°C]=31.00
Compensated pressure [mbar] =-12747
2nd order compensated temperature [°C] =31.00
Temperature raw =49151
Pressure raw =2047
Real Temperature [°C]=175.00
Compensated pressure [mbar] =-16794
2nd order compensated temperature [°C] =175.00

i reset and put my finger and temperature increases
visit www.diveduino.com

buton


second try i hooked the 32.768 khz clock i bought directly to the sensor and things got better

first reading is good, second reading is bad...


Temperature raw =30027
Pressure raw =2047
Real Temperature [°C]=31.00
Compensated pressure [mbar] =-12747
2nd order compensated temperature [°C] =31.00
Temperature raw =49151
Pressure raw =2047
Real Temperature [°C]=175.00
Compensated pressure [mbar] =-16794
2nd order compensated temperature [°C] =175.00

i reset and put my finger and temperature increases



I solder it again and it is working perfect

thank you man..

the diving community really appreciate your effort

Temperature raw =29659
Pressure raw =14623
Real Temperature [°C]=28.00
Compensated pressure [mbar] =981
2nd order compensated temperature [°C] =28.00
visit www.diveduino.com

godo

Great, congratulations!
Let me know if you by chance modify the code, because for some reason it only gives X.00 (point zero) temperature values and I would like to have a better resolution.
It is great to contribute to the community after I received so much help and advice, I am very happy to share!

buton


Great, congratulations!
Let me know if you by chance modify the code, because for some reason it only gives X.00 (point zero) temperature values and I would like to have a better resolution.
It is great to contribute to the community after I received so much help and advice, I am very happy to share!


i think that i got it

change the calculation of the temeperature to double

Code: [Select]
const double TEMP = 200 + ((dT * (c6 + 100)) >> 11);

double TEMPREAL = TEMP/10;


:)

visit www.diveduino.com

godo

Wow, great, that is a bit of a surprise though, because:
Quote
The double implementation on the Arduino is currently exactly the same as the float, with no gain in precision.

But, on the other hand:
Quote
Users who borrow code from other sources that includes double variables may wish to examine the code to see if the implied precision is different from that actually achieved on the Arduino.

I will try that asap, thanks!

buton

I realized that having the microsd card and the sensor on the same buss will be too complicated due to the libray SDFAT.. and i dont want to add another IC

so i was thingking about doing some bit banging to get the data...

somehow i got it to work(i think)  the reset and pressure conversion sequence works because i am getting data

where i am having problems is on the reading, no reading the correct raw value...how ever if i manually press the sensor with my finger... i start getting numbers...also if i modify the delay on the clk while reading it also changes... :)

godo please helpme out if you see something weird.. i almost follow the datasheet and some insights of you spi code..

Code: [Select]



word start=0b1111010000000000;//start sequence
unsigned int p1,p2;
long reset=0b10101010101010100000000000000000;//reset sequence
byte counts;//for debug
int dout= 2;//pin for data out MOSI
int din=3;//pin for data in MISO
int clk=4;//data clock
boolean data=0;


void setup() {               
  // initialize the digital pin as an outputand input
 
  Serial.begin(9600);
  pinMode(dout, OUTPUT);     
    pinMode(din, INPUT); 
   pinMode(clk,OUTPUT);
 
}

void loop() {
  pressure();   //main function
  delay(3000);              // wait for a second
}

void pressure()
{
  Serial.println("start Reset");
  //---start REset sequence...
        for(int i=31;i>10;i--)
        {
         
          boolean x;
         
          x=bitRead(reset,i);
       
         
          digitalWrite(dout,x);
           digitalWrite(clk,HIGH);
            digitalWrite(clk,LOW);
        }
   
  //--------Start Conversion sequence
    for(int i=15; i>5;i--)   
    {
               
                       boolean x;
                       x=bitRead(start,i);
                       digitalWrite(dout,x);               
                       //--DRIVE CLOCK
                       digitalWrite(clk,HIGH);
                       digitalWrite(clk,LOW);   
                               
                                       
                               
                               
   }
               
         
         
   //wait unti conversion
    // i keep runing the clock and wait until the Din(miso) detects that it went to 0 and the data is ready
   
     data=  digitalRead(din);
    while(data==1)
   
    {
     
      digitalWrite(clk,HIGH);   
      digitalWrite(clk,LOW);
      data=digitalRead(din);
     
     
    }
   //------------


//---start reading
    //Serial.println("Read raw pressure");
     
        for(int i=16; i>=0;i--)
            {
                 digitalWrite(clk,HIGH);    // drive the clock down     
                 delay(10);       
                 digitalWrite(clk,LOW);
                 delay(10);
                 data= digitalRead(din);// i read on low cycle de input(output of the sensor)
                  if(data==1)
                  {
                   
                    bitWrite(p1,i,1);// write the value and i index the int to the right..
             
                    }
                 else
                 {
                bitWrite(p1,i,0);
             
                   
                 }
                 
              counts++;
            }
     
     
     
     
   
   
    //testing to see if shifting will help also
  Serial.println(p1);
  p2=p1>>1;
 
  Serial.println(p2);
  Serial.println(counts);//test to se how many times went into for cycle
  counts=0;
 
}

visit www.diveduino.com

buton

visit www.diveduino.com

Go Up