Dienstag, 5. Juni 2012

HP03S Luftdruck Temperatursensor mit Arduino

Hat zwar nichts mit DRM zu tun, aber ist vielleicht trotzdem interessant.

Ich hab mir vor kurzem bei Neuhold-Elektronik (so eine Art Pollin-Österreich) einen HP03S Luftdrucksensor gekauft und diesen jetzt endlich einmal an meinem Arduino-Board angeschlossen.
Der Sensor hat 3,3V Betriebsspannung, daher muss man bein Anschließen etwas aufpassen. Die Pegelanpassung habe ich mit ein paar Widerständen, ein paar Dioden und einer Zenerdiode gelöst. Zenerdiode (2,7V) auf Masse, 5V Versorgungsspannung von Arduino-Board über 1 KOhm an Zenerdiode und mit einem Kondensator 1uF an Masse. Alle anderen Datenleitungen vom Arduino-Board mit 10 kOhm mit dem Sensor und zusätzlich sensorseitig über eine normale Diode an die Zenerdiode.  Damit erzeuge ich aus den 5V des Arduinoboard selber die 3,3V für den Sensor. Das wäre zwar nicht 100% notwendig, aber so kann mir nicht passieren, dass ich 3,3V und 5V Anschluss vertausche.
Zur Pegelanpassung gibt es sicher auch schönere Varianten, aber funktionieren tut es so auch.

Nachdem ich dann aber etwas forschen habe müssen, bis ich die Sensorwerte auslesen konnte, möchte ich mein Programm zum Auslesen von Druck und Temperatur hier veröffentlichen. Vielleicht hilft's ja irgend jemanden.
Das Programm gibt die Sensorwerte alle 30 Sekunden über die Serielle Schnittstelle aus.

Anschluss:
MCLK = Digital 5 (Pegelanpassung !!!)
XCLR  = Digital 9 (Pegelanpassung !!!)
SDA = AnalogA4 (Pegelanpassung !!!)
SCL = Analog A5 (Pegelanpassung !!!)
VSS = GND
VDD =  siehe Text

#include <Wire.h>

// address of HP03S EEPROM is 0xA1 (8-Bit)
// wire-Library requires 7-Bit value -> shift 1 Bit to the right
// (see library docu)

#define eepromAdr (0xa1 >> 1)
#define adcAdr (0xee >> 1)
int XCLRpin = 9;
int MCLKpin = 5;

#define Const_E  2.718281828459

// Parameter Range(Hex:Dec)
// C1 0x100 -- 0xFFFF : 256 -- 65535
// C2 0x00 -- 0x1FFF ; 0 -- 8191
// C3 0x00 -- 0x400 ; 0 -- 3000
// C4 0x00 -- 0x1000 ; 0 -- 4096
// C5 0x1000 -- 0xFFFF ; 4096 -- 65535
// C6 0x00 -- 0x4000 ; 0 -- 16384
// C7 0x960 -- 0xA28 ; 2400 -- 2600
// C  0x01 -- 0x0F ; 1 -- 15
// D  0x01 -- 0x0F ; 1 -- 15
// A  0x01 -- 0x3F ; 1 -- 63
// B  0x01 -- 0x3F ; 1 -- 63
// D1 0x00 -- 0xFFFF ; 0 -- 65535
// D2 0x00 -- 0xFFFF ; 0 -- 65535

//coefficients
word C1;
word C2;
word C3;
word C4;
word C5;
word C6;
word C7;
byte A;
byte B;
byte C;
byte D;

word D1;
word D2;

void setup()
{
  Serial.begin(9600);  // start serial for output
  delay(1000);
  Serial.println("Start");
 
  hp03s_init();
//  hp03s_print_vals(); 
}

void loop()
{
  hp03s_get_sens_value(5);
 



 
  Serial.print("Luftdruck abs ");
  Serial.print(hp03s_pressure_abs() );
 
  Serial.print(" mbar  Luftdruck Meer ");
  Serial.print(hp03s_pressure_0m(510.0) );
 
  Serial.print(" mbar   Seehoehe ");
  Serial.print(hp03s_level(1013.0) );

  Serial.print(" m   Temperatur ");
  Serial.print(hp03s_temp() );
  Serial.println(" C");
   
  delay(30000);
 
}


void hp03s_print_vals() {
Serial.print("C1 = "); Serial.println(C1);
Serial.print("C2 = "); Serial.println(C2);
Serial.print("C3 = "); Serial.println(C3);
Serial.print("C4 = "); Serial.println(C4);
Serial.print("C5 = "); Serial.println(C5);
Serial.print("C6 = "); Serial.println(C6);
Serial.print("C7 = "); Serial.println(C7);
Serial.print("A  = "); Serial.println(A);
Serial.print("B  = "); Serial.println(B);
Serial.print("C  = "); Serial.println(C);
Serial.print("D  = "); Serial.println(D);

Serial.print("D1 = "); Serial.println(D1);
Serial.print("D2 = "); Serial.println(D2);
}

void hp03s_get_sens_value(int avg_cnt) {

  long D1_sum;
  long D2_sum;
  int i;
 
   D1_sum = 0;
   D2_sum = 0;

   startMstClk();

    for (int i=0; i < avg_cnt; i++){
      hp03s_get_sens_value_2();
   
      D1_sum = D1_sum + D1;
      D2_sum = D2_sum + D2;
      delay(2500);
    }     
   stopMstClk(); 
   
   D1 = D1_sum / avg_cnt;
   D2 = D2_sum / avg_cnt;
  
  
}   

void hp03s_get_sens_value() {
  startMstClk();
  hp03s_get_sens_value_2();
  stopMstClk(); 
}
     
void hp03s_get_sens_value_2() {
 
// read values fom sensor and fill variables D1 and D2 
 
    byte pressure[2]; 
    byte temp[2]; 
  
    Wire.beginTransmission(adcAdr);  // Start transmission
    Wire.write(byte(0xFF));
    Wire.write(byte(0xF0));
    Wire.endTransmission();         // Reset
    delay(6400);                   // = 100 ms  !!!
    Wire.beginTransmission(adcAdr);
    Wire.write(byte(0xFD));
    Wire.endTransmission();
    Wire.beginTransmission(adcAdr);
    Wire.requestFrom(adcAdr, 2);

    for (int i=0; i < 2; i++){
      pressure[i] = Wire.read();
    }
    Wire.endTransmission();

 
    Wire.beginTransmission(adcAdr);  // Start transmission
    Wire.write(byte(0xFF));
    Wire.write(byte(0xe8));
    Wire.endTransmission();         // Reset
    delay(6400);                    // = 100 ms  !!!
    Wire.beginTransmission(adcAdr);
    Wire.write(byte(0xFD));
    Wire.endTransmission();
    Wire.beginTransmission(adcAdr);
    Wire.requestFrom(adcAdr, 2);

    for (int i=0; i < 2; i++){
      temp[i] = Wire.read();
    }
    Wire.endTransmission();
    
    
    D1 = word(pressure[0], pressure[1]);
    D2 = word(temp[0], temp[1]);
}

float hp03s_pressure_abs() {
 
// calculate absolute pressure  
 
 
  long dUT;
  long OFF;
  long SENS;
  long ZW;
  long X;
  float P;


 
// D2 >= C5: dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * A / 2^C
// D2 <  C5: dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * B / 2^C 

   ZW = long(D2) - long(C5); 
   if ( ZW >= 0 ) {
     dUT = ZW -  (( ZW * ZW / 128  * long(A) / 128 ) >> C);
   }  
   else {
     dUT = ZW -  (( ZW * ZW / 128  * long(B) / 128 ) >> C);
   } 


// OFF=(C2+(C4-1024)*dUT/2^14)*4
//  OFF = ( long(C2) + ( long(C4) - 1024 ) * dUT / ( 1 << 14 ) ) * 4;
  OFF =  long(C2)* 4 + ( ( ( long(C4) - 1024 ) * dUT ) >> 12  ) ;


// SENS = C1+ C3*dUT/2^10
  SENS = long(C1)   + ((long(C3) * dUT) >> 10 ) ;
// X= SENS * (D1-7168)/2^14 - OFF
  X =  ( SENS * ( long(D1) - 7168  ) >> 14 ) - OFF ;

// P=X*10/2^5+C7 
// P=X*100/2^5+C7*10  (für eine bessere Auflösung)
  P =  (( X * 100) >> 5) + long(C7 )* 10 ;
 
  return P/100;



}

float hp03s_pressure_0m( float level) {

// calculate absolute pressure at sea level 
 
  float P;
  float P0;
 
  P = hp03s_pressure_abs();
  P0 = P / pow(Const_E, ( - level / 7990 ) );


  return P0;
}



float hp03s_level( float P0) {
 
// calculate level based on sealevel pressure and absolute pressure

  float level;
  float P;
 
  P = hp03s_pressure_abs();

  level = -7990.0 * log( P / P0);

  return level;
}

float hp03s_temp() {
 
// calculate temperature

  long dUT;
  long ZW; 

  float T;
 
 
// D2 >= C5: dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * A / 2^C
// D2 <  C5: dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * B / 2^C 

   ZW = long(D2) - long(C5); 
   if ( ZW >= 0 ) {
     dUT = ZW -  (( ZW * ZW / 128  * long(A) / 128 ) >> C);
   }  
   else {
     dUT = ZW -  (( ZW * ZW / 128  * long(B) / 128 ) >> C);
   } 


// T = 250 + dUT * C6 / 2 ^ 16-dUT/2^D

  T = round(250L + dUT * long(C6) / 65536 -  dUT / pow(2,D));

  return T/10;

}




void hp03s_init() {
 
// array to save values
  byte result[18]; 
 
 
  pinMode(XCLRpin, OUTPUT);
  pinMode(MCLKpin, OUTPUT);
  digitalWrite(XCLRpin, LOW);
  analogWrite(MCLKpin, 0);
 
  Wire.begin();        // join i2c bus

 
  delay(100);
// First coefficient at adress 0x10
// initialise EEPROM to read from 0x10
  Wire.beginTransmission(0x50);  // Start transmission
  Wire.write(0x10);                // Set adress to 0x10
  Wire.endTransmission();         // Reset

  delay(100);

// read the next 18 bytes starting from this address
  Wire.beginTransmission(0x50);  // start transmission
  Wire.requestFrom(0x50, 18);    // request 18 bytes from



// Save values from EEPROM
  if (Wire.available() == 18) {
    for (int i=0; i < 18; i++){
      result[i] = Wire.read();
    }

// stop transmission
    Wire.endTransmission();

// get together MSB:LSB
    C1 = word(result[0],result[1]);
    C2 = word(result[2],result[3]);
    C3 = word(result[4],result[5]);
    C4 = word(result[6],result[6]);
    C5 = word(result[8],result[9]);
    C6 = word(result[10],result[11]);
    C7 = word(result[12],result[13]);
    A = result[14];
    B = result[15];
    C = result[16];
    D = result[17];
 
 
 
    hp03s_get_sens_value();  // ersten Wert lesen und verwerfen 
  }
  D1 = 0;
  D2 = 0;
}

void startMstClk() {
  TCCR0B = TCCR0B & 0b11111000 | 0x01;
  analogWrite(MCLKpin, 127);
  digitalWrite(XCLRpin, HIGH);
  delay(8000);  // Timer0 mit divisor 1
}

void stopMstClk() {
  TCCR0B = TCCR0B & 0b11111000 | 0x03;
  analogWrite(MCLKpin, 0);
  digitalWrite(XCLRpin, LOW);
}

========================================
Output des Programms:
Luftdruck abs 953.40 mbar  Luftdruck Meer 1016.24 mbar   Seehoehe 484.49 m   Temperatur 22.70 C
Luftdruck abs 953.40 mbar  Luftdruck Meer 1016.24 mbar   Seehoehe 484.49 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.50 mbar  Luftdruck Meer 1016.35 mbar   Seehoehe 483.65 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.37 mbar  Luftdruck Meer 1016.21 mbar   Seehoehe 484.74 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
Luftdruck abs 953.40 mbar  Luftdruck Meer 1016.24 mbar   Seehoehe 484.49 m   Temperatur 22.70 C
Luftdruck abs 953.46 mbar  Luftdruck Meer 1016.30 mbar   Seehoehe 483.99 m   Temperatur 22.70 C
Luftdruck abs 953.43 mbar  Luftdruck Meer 1016.27 mbar   Seehoehe 484.24 m   Temperatur 22.70 C
 





1 Kommentar:

  1. Hallo,

    könnten Sie evtl. den Schaltplan des Anschlusses veröffentlichen?

    Gruß Andreas

    AntwortenLöschen