Go Down

Topic: Sensor Amsys5812 (Read 6783 times) previous topic - next topic

weyoun

Guten Tag werte Gemeinde,

so, das erste mal in meinem leben darf ich programmieren. Etwas richtiges, keine Osterdatum, sondern ich möchte von einem Sensor Daten auslesen.
Ich benutze einen Sensor namens "Amsys 5812-0150-B" dies ist ein barometrischer Druck Sensor, der mir auf einem analogen Ausgang das Signal des Drucksensors ausgibt, der Messbereich geht von 758,4-1206 mbar. Aus dem I2C bekomme ich ebenfalls den Druck und kann zusätzlich noch die Temperatur auslesen.

Ersteres habe ich ohne Probleme lesen können. Das Signal wurde mir schön ausgegeben. Da ich aber auch einen Temperatursensor bei habe will ich auch dieses Signal auswerten. Also machte ich mich ans Werk und mein Elend begann......
Ich habe den Sensor korrekt angeschlossen an mein Arduino Dueminalove-Board und ein kleines Programm geschrieben das ich jetzt hier mal reinsetze:

Code: [Select]
#include <Wire.h>
int DruckPin = 1;    // Drucksensor eingang
float val = 0;
#define address 0x78 /hex-adresse des sensors



void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Momentanen Druck auslesen und ausgeben");
  Serial.println();
  pinMode(DruckPin, INPUT);  // DruckPIN Eingang
 
}

void loop() {
 
  Wire.beginTransmission(address); // drucksensor initialisieren
  Wire.send(0);// Zeiger auf 0 setzen
  Wire.requestFrom(address, 4);// bescheid sagen wiviele Bytes kommen. nämlich 4
 
 
  int Druck1;// variablen für die einzelnen Bytes
  int Druck2;
  int Temperatur1;
  int Temperatur2;

 
  if (Wire.available()) {
     Druck1 = Wire.receive(); //1.Byte
       
     Druck2 = Wire.receive();//2.Byte
   
     Temperatur1 = Wire.receive();//3.byte
     
     Temperatur2 = Wire.receive();//4.Byte
     
   
      }
  Wire.endTransmission();// ende der übertragung
  Serial.println("-----------");//hier beginnt die ausgabe
  Serial.println(Druck1);// 1.Byte
  Serial.println(Druck2);//2.Byte
  Serial.println(Temperatur1);//3.byte
  Serial.println(Temperatur2);//4.Byte

  val =analogRead(DruckPin);    // der analoge Ausgang des Sensors wird ausgelesen
  Serial.println(val);          //wert von val in bit wird ausgegeben
  val = (val*0.438)+758,4;      // umrechnung des wertes in val wird umgerechnet in mbar.
  Serial.println(val);          // ausgabe des wertes auf serial monitor
  delay(500);                  // kurze pause, dann geht es wieder von vorne los
}


auf dem Serial monitor erscheint dann alles was ich ihm sage, leider stimmen meine Werte nicht.

Der analog Wert ergibt auf dem Serialmonitor nach der Umrechnung ungefähr 1010mbar, damit liege ich auf jedenfall richtig, die Wetterstation die etwas weiter wegliegt gibt ähnliche Werte.

Wenn ich jedoch die Bytes aus dem I2C auslese bekomme ich folgendes:
72 // 1.Byte Druck
40//  2.Byte Druck
56//3.byte Temp
220//4.byte Temp


So diese Werte muss ich jetzt in den Messwert umwandeln. für den Druck sieht das dann folgendermaßen aus: 1.+2.Byte ergibt: 7240
Ich vermute dass es sich um einen Hex-Wert handelt. Dies ergibt Dezimalumgewandelt: 29248(Warum ich das brauche erzähle ich jetzt)

Das Datenblatt des Sensor http://www.amsys.de/sheets/amsys.de.ams5812.pdf gibt mir vor das der Wert dezimal umgewandelt werden muss, siehe Seite 9, im Datenblatt um auf counts zu kommen und um dann gemäss der Formel aus dem Datenblatt daraus den Messwert zuerechnen.
Ich habe das mal per Hand durchgerechnet und bin zu folgendem ergebnis gekommen:

Als erstes Rechne Ich Sensp(Siehe Seite 10) aus. Die Werte die ich einsetzen muss ergeben sich aus dem Datenblatt. Sensp errechnet sich daher zu: 58513. Wenn ich dies in die Formel für p eingebe, dann bekomme ich einen Druck von 1,202 bar als ergebnis. Das kann nicht stimmen, da ich mich in normaler umgebung befinde und mein analog-Ausgang mir einen realitischen Wert liefert
Mein Temperatur Wert ist totale Grütze, der kann gar nicht stimmen, da hier die Werte 56 und 220 aneinander gehangen 56220 ergeben was dezimal 352800 ergibt und mir dann in der Rechnung hinterher nen negativen Wert gibt.

Da der analoge Augang funktioniert muss der Sensor funktionieren, da das analoge Signal vom Sensor direkt aus dem I2C_Signal generiert wird. Bleibt nur ein Fehler meinerseits.
Wer nach diesem langen Roman jemand so nett und könnte mal auf den Quellcode rauflinsen? ich bin gerade sehr ratlos was der fehler sein könnte:-(

volvodani

Du weist das man nochmal am Ende PSI in hPA umwandeln muss und dann bin ich bei einer Tascherechnerrechung mit deinen Werten auf 1024hPa gekommen was wiederum plausibel erscheint.
"Komm wir essen Opa!" - Satzzeichen retten Leben!

uwefed

Auf welcher Meereshöhe wohnst Du?
1024mbar können für Meereshöhe plausibel sein.
Grüße Uwe

weyoun

Ich sitze an der Nordseeküste und dieserWert ist durchaus plausibel.
Aaaaber:
Ich habe doch den Wert für Sensp mit mbar berechnet, da muss ich doch auch direkt ohne umrechnung mbar rausbekommen und die Zahlenwerte für die Temperaturberechnung hauen meines Erachtens ja auch nicht so hin. Oder begehe ich irgendwo einen Denkfehler??

weyoun

Hier mal die Rechenschritte für PSI:

sensp=(digoutmax-digoutmin)/pmax-pmin
sensp=(29491-3277)/17,5-11
Sensp=4032,9  counts/psi



p=((digout-digoutmin)/Sensp)+pmin

p=((29248-3277)/4032,9)+11
17.43psi
ich müsste aber bei normaldruck um die 14,8psi errechnen


Jetzt zur Temperatur:

wieder sensp=
sensp=(digoutmax-digoutmin)/Tmax-Tmin
sensp=(29491-3277)/85°C-(-25°C)
sensp=238,3 Counts/°C

T=((digout-digoutmin)/Sensp)+Tmin

T=((digout-3277)/4032,9)+(-25°C)
digout= 3.Byte an 4.Byte rangehangen: 56220
hex in dezimal=>352800
T=((352800-3277)/4032,9)+(-25°C)
T=61,66°C

=> entweder liegt mein lab sehr tief und es ist sehr warm oder ich begehe einen fundamentalen fehler.
ockham sagt die annahme die die wenigsten grundannahmen vorraussetzt ist richtig.

uwefed

Hallo weyoun
Jetzt hab ichs.

Quote
72 // 1.Byte Druck
40//  2.Byte Druck
56//3.byte Temp
220//4.byte Temp

Da können keine Hexadezimalzahlen sein weil 0x220 ist größer als ein Byte, also müssen es Dezimalzahlen sein.
Dann ist Druck: 72*256+40 = 18472
und Temperatur: 56*256+220 = 14556

Druck ( wenn man die mbar min und max Werte einsetzt, braucht man nicht von PSI auf mbar umrechnen)

Sensp=(digoutmax-digoutmin)/pmax-pmin
Sensp=(29491 - 3277) /(1206 -758,4) = 58,5656
Sensp= 58,5656 counts/mbar

p=((digout-digoutmin)/Sensp)+pmin

p=((18472-3277)/ 58,5656)+758,4
p = 1017,44 mbar (Ein wenig Hochdruck)

Jetzt zur Temperatur:

senst=(digoutmax-digoutmin)/Tmax-Tmin
senst=(29491-3277)/85°C-(-25°C)
senst=238,3 Counts/°C

T=((digout-digoutmin)/Senst)+Tmin

T=((digout-3277)/238,3)+(-25°C)
digout= 14556
T=((14556-3277)/238,3)+(-25°C)
T=22,33°C (nicht der wärmste Tag)

Grüße Uwe

weyoun

Wow, diese Werte sind in der Tat plausibel. War ja auch tolles Wetter gestern:-) vielen dank für das einfache vorrechnen.
Folgendes hab ich jedoch nicht verstanden:

Quote
Da können keine Hexadezimalzahlen sein weil 0x220 ist größer als ein Byte, also müssen es Dezimalzahlen sein.
Dann ist Druck: 72*256+40 = 18472
und Temperatur: 56*256+220 = 14556


Woher hast du dir genommen das du das erste byte mit 256 multiplizieren musst?

Im Datenblatt steht ja:
Quote
Für einen Drucksensor vom Typ AMS 5812-0015-D (0…1.5PSI differentiell) wird ein digitaler Druckwert von
Digoutp(p) = 550AHex counts = 21770Dec counts
und ein digitaler Temperaturwert von
DigoutT(T) = 3A9AHex counts = 15002Dec counts

Darum ging ich davon aus das die Daten darstellung hexadezimal stattfindet.
Oder hätte mir dann der Serialmonitor für das erste Byte 0x72, fürs 2.byte 0x40 und analog folgend, ausgeben müssen?

uwefed


Woher hast du dir genommen das du das erste byte mit 256 multiplizieren musst?
Im Datenblatt steht ja:
Quote
Für einen Drucksensor vom Typ AMS 5812-0015-D (0…1.5PSI differentiell) wird ein digitaler Druckwert von
Digoutp(p) = 550AHex counts = 21770Dec counts
und ein digitaler Temperaturwert von
DigoutT(T) = 3A9AHex counts = 15002Dec counts

Darum ging ich davon aus das die Daten darstellung hexadezimal stattfindet.
Oder hätte mir dann der Serialmonitor für das erste Byte 0x72, fürs 2.byte 0x40 und analog folgend, ausgeben müssen?

Die Zahl 220 ist definitiv (uner der Bedingung sie ist eine 1Byte-Zahl) keine Hex-Zahl weil 8 Bit con 0 bis  0xff oder 0 bis 255dezimal geht.
Der Sensor schickt Dir immer 4 8-Bit Binärzahlen. Jetzt ist es an Dir diese darzustellen.
Wenn Du die 2 Byte, die Du vom Sensor bekommst als 2-stellige Hex-Zahl ausgeben läßt, kannst Du sie einfach zu einer 4 stelligen hintereinanderschreiben. Wenn Du sie als Dezimalzahl ausgibst mußt Du die Wertigkeit der höherwertigen Zahl berüchsichtigen, die nicht 100 dezimal ist sonder 256 dezimal ist.

Beim Umrechnen von den 2 1-Byte Werten zu einer unsigned Int-Variablen mußt Du den höherwertigen Teil mit 256 multiplizieren und dann den niederwertigen Teil addiren.
   
Die niederwertige Zahl geht von 0 bis 255.  Wenn du zu 255 eins dazuzähls, wird die niederwertige Zahl 0 und Du hast einen Übertrag von 1 der im nächst Höherwertigen Zahl gespeichert wird; also   1 und 0.
Dies, weil Du nicht mit mit einem System zu tun hast, das dezimal zählt, sondern binär und geschichtlich gesehen 8 Bit zu einer größeren Einheit (Byte) zusammengfaßt wurden.
Weiß nicht ob Dir mit meiner Erklärung schon alles klar ist.

Weiterer Versuch:

binär: 0101  0011     0111 1110            // 2 8-Bitzahlen nach 4 bit gruppiert rechts niederwertiges Bit.
hex:        5        3           7      E            //also 53 7E das sind in dezimal 21374 (Umwandlung Taschenrechner Windows)
binär:              83               126            // zusammengerechnet: 83*256+126 = 21374.

Quote from: weyoun

Darum ging ich davon aus, das die Daten Darstellung hexadezimal stattfindet.
Oder hätte mir dann der Serialmonitor für das erste Byte 0x72, fürs 2.byte 0x40 und analog folgend, ausgeben müssen?

Die Serial.print() Funktion gibt standartmäßig die Zahl als einen Dezimalwert aus. Du kannst das mit einem zusätzlichen Parameter auch ändern.
Serial.print(val, format)  siehe http://arduino.cc/en/Serial/Print
Die Serial.print() Funktion gibt aber zur Hex-Zahl kein "0x" hinzu.
Im Beispiel im Datenblatt haben sie HEX-Werte genommen, weil das einfacher zu rechnen ist. (4 bit gruppieren und zu einer Zahl von 0 bis F umrechnen und dann alles zusammenhängen. Hexzahlen von 1 Byte haben immer nur 2 Stellen.

Grüße Uwe


weyoun

Wow, danke für die ausführliche Auskunft. :)

Ich werde mich mal nächste Woche ausführlicher damit beschäftigen.

Leider hatte ich in meinem Studium nicht allzuviel am Hut mit Mikrocontrollern. Kennst du ein gutes Buch zur Einführung empfehlen,so dass auch laien dieser Thematik sich selbst so etwas erarbeiten können. Das scheint ja etwas sehr fundamentales zu sein und ich hab keine Lust, mit so etwas anscheinend sehr trivialem Leute in nem Forum zu nerven.


Danke im vorraus, weyoun

weyoun

Sooo leider muss ich dieses Thema mal wieder aus der Versenkung ausgraben:-(

ich habe weiterhin Probleme mit meinem Drucksensor und der I2C Schnittstelle.

Das Problem muß irgendwie im Quellcode liegen. Die Kommunikation mit dem Sensor  funktioniert nicht Richtig.
Mir ist aufgefallen das die Werte für den Druck beim Durchlaufen des Programmes sich nicht ändern. Ich beobachte den Wert über den Serialmonitor und es passiert nicht. Er zeigt ständig Die selbe Temperatur an, wenn ich den Sensor mit Kältespray besprühe ändert sich der Wert erst wenn ich das USB-Kabel einmal abziehe.
Das Programm läuft jedoch durch, ich habe nach jeder Zeile ein Serialprint mit einer Zahl eingefügt.
Hier der Code:
Quote
#define address2 0x78
#include <Wire.h>



void setup(){
Serial.begin(9600);}

void loop(){
  Serial.println(0);
   Wire.begin();
   Serial.println(1);
  Wire.beginTransmission(address2); // drucksensor initialisieren
  Serial.println(2);
  Wire.send(0);// Zeiger auf 0 setzen
  Serial.println(3);
  Wire.requestFrom(address2, 4);// bescheid sagen wiviele Bytes kommen. nämlich 4
  Serial.println(4);
  int Druck1;// variablen für die einzelnen Bytes
  int Druck2;
  int Druck;
  int Temperatur1;
  int Temperatur2;
  int Temperatur;
  int ausgabewert_Druck;
  int ausgabewert_Temperatur;

     Druck1 = Wire.receive(); //1.Byte
     Serial.println(5);
    // Serial.println(Druck1);
   
     Druck2 = Wire.receive();//2.Byte
    //Serial.println(Druck2);
     Serial.println(6);
    Temperatur1 = Wire.receive();//3.byte
    Serial.println(7);
    // Serial.println(Temperatur1);
    Temperatur2 = Wire.receive();//4.Byte
    Serial.println(8);
  //Serial.println(Temperatur2);
   
     Serial.println(9);
  //Wire.endTransmission();// ende der übertragung
  Druck = (((256*Druck1+Druck2)-3277)/58)+758;
  Serial.println(10);
  Temperatur=(((256*Temperatur1+Temperatur2)-3277)/238.31)-25;
  Serial.println(11);
 
  Serial.println(Temperatur);
  Serial.println(Druck);
  Serial.println(13);
   Wire.endTransmission();// ende der übertragung
  delay(2000);
}

Welchen Fehler mache ich?
Ich starte die Kommunikation, ich beende sie, egal wo ich das endTransmission hinsetze es ändert nichts:-( hat wer nen guten Tip?


weyoun

So ich habe gerad mal was ausprobiert,

Code: [Select]
#define address2 0x78
#include <Wire.h>
[b]int add=0;[/b]

void setup(){
Serial.begin(9600);}

void loop(){
Wire.begin();
Wire.beginTransmission(address2); // drucksensor initialisieren
[b]Wire.send(add);// Zeiger auf 0 setzen[/b]
Wire.requestFrom(address2, 4);// bescheid sagen wiviele Bytes kommen. nämlich 4
  int Druck1;// variablen für die einzelnen Bytes
  int Druck2;
  int Druck;
  int Temperatur1;
  int Temperatur2;
  int Temperatur;
  int ausgabewert_Druck;
  int ausgabewert_Temperatur;
  Druck1 = Wire.receive(); //1.Byte
  // Serial.println(Druck1);
      Druck2 = Wire.receive();//2.Byte
    //Serial.println(Druck2);
   Temperatur1 = Wire.receive();//3.byte
// Serial.println(Temperatur1);
    Temperatur2 = Wire.receive();//4.Byte
    //Serial.println(Temperatur2);
   //Wire.endTransmission();// ende der übertragung
  Druck = (((256*Druck1+Druck2)-3277)/58)+758;
  Temperatur=(((256*Temperatur1+Temperatur2)-3277)/238.31)-25;
  Serial.println(Temperatur);
  Serial.println(Druck);
  Wire.endTransmission();// ende der übertragung
  [b] add++;
  if(add==3){
     add=0;
   }[/b]
  delay(200);
}


den fettgedruckten teil habe ich gerade eingefügt und seitdem zeigt mir der Sensor Schwankende Temperaturen und auch Druckwerte an.
Ich habe für add verschiedene Werte ausprobiert aber sobald ich höre zahlen eingebe kommt quatsch raus anch 4 messung ist der Wert grütze.
Ich frage jetzt mal, was habe ich da gemacht?
es muss irgendwas mit Speicherregister zu tun haben. Ich weiss nur nich was und wie ich die richtige Frage formulieren soll.
Kann mir mal wer auf die Sprünge helfen?

pfeili

Liebe Leute,

auch ich beschäftige mich mit diesem Problem und bin sehr glücklich, auf diesen Beitrag gestoßen zu sein. Mein Sensor ist ein AMS5812-0003-D-B, also ein Differenzdrucksensor. Das Problem mit dem "Festhängen" der Werte hatte ich ebenfalls. In der Anleitung lese ich etwas von "If no acknowledge bit is generated by the receiving master, the pressure sensor is set to inactive." Dies deckt sich ja mit unserer Beobachtung: erst nach Ab- und Wiederanstecken wurde ein neuer Wert gelesen, doch auch dieser festgehalten.

Mithilfe deines Codes und dem Anpassen der Messbereichsgrenzen messe ich plausible Werte, die ich mithilfe eines Schrägrohrmanometers überprüft habe.

Code: [Select]

#define address 0x78
#include <Wire.h>

// Variablendeklaration
int add=0;
int Druck1;
int Druck2;
int Temperatur1;
int Temperatur2;
float Druck;
float Temperatur;
 
void setup(){
  Serial.begin(9600);
  }

void loop(){

  Wire.begin();
  Wire.beginTransmission(address); // Kommunikation starten
  Wire.write(add);// ???
  Wire.requestFrom(address, 4); // 4 Bytes anfordern

  Druck1 = Wire.read(); // MSB
  Druck2 = Wire.read(); // LSB
  Temperatur1 = Wire.read(); // MSB
  Temperatur2 = Wire.read(); //LSB

  // Berechnung unter Berücksichtigung von Most/Least Significant Byte
  Druck = (((256*Druck1+Druck2)-3277)/(26214/41.36))-20.68;
  Temperatur=(((256*Temperatur1+Temperatur2)-3277)/(26214/110))-25;
 
  // Ausgabe
  Serial.println("Druck in mbar: "); 
  Serial.println(Druck);
  Serial.println("Temperatur in °C: "); 
  Serial.println(Temperatur);
  Serial.println("-------------------");
 
  // Kommunikation beenden
  Wire.endTransmission();
  add++;
  if(add==3){
     add=0;
  }
  delay(200);
  }



Auch mich interessiert nun, warum ab dem Befehl

Code: [Select]

Wire.write(4)


Unsinn heraus kommt. Was genau tut denn die write-Funktion?

Für jegliche Hilfestellung bin ich dankbar.

Viele Grüße

pfeili

Serenifly

Der I2C Code ist falsch:

Code: [Select]

  Wire.begin();
  Wire.beginTransmission(address); // Kommunikation starten
  Wire.write(add);// ???
  Wire.requestFrom(address, 4); // 4 Bytes anfordern


1.) Wire.begin() macht man einmal in setup()
2.) beginTransmission() schreibt nur in den Ausgangs-Puffer. Das muss mit endTransmission() abgeschlossen werden. endTransmission() schließt das Schreiben ab, nicht das Lesen

Bei wire.write() wird das Register übergeben ab dem du Daten auslesen willst. Also z.B. 0 wenn du von 0-3 Lesen willst

requestFrom() liest genaugenommen auch die Daten schon aus und fordert diese nicht nur an. Mit read() werden sie dann aus dem Eingangspuffer entfernt. requestFrom() hat auch einen Rückgabe-Wert: die Anzahl der Bytes die wirklich empfangen wurden

Korrekt:
Code: [Select]

  Wire.beginTransmission(address); //Schreiben zu Slave mit Adresse "address"
  Wire.write(register);       //Anfangs-Register setzen
  Wire.endTransmission();  //Daten auf den Bus schreiben
  Wire.requestFrom(address, 4); // 4 Bytes anfordern

  Druck1 = Wire.read(); // MSB
  Druck2 = Wire.read(); // LSB
  Temperatur1 = Wire.read(); // MSB
  Temperatur2 = Wire.read(); //LSB


Und das endTransmission() ganz am Ende entfernen

pfeili

Vielen Dank für deine rasche und umfassende Antwort. Ich habe den Code (hoffentlich nach deinen Vorstellungen) umgesetzt:

Code: [Select]

#define address 0x78
#include <Wire.h>

// Variablendeklaration
int startregister = 0;
int Druck1;
int Druck2;
int Temperatur1;
int Temperatur2;
float Druck;
float Temperatur;
 
void setup(){
  Serial.begin(9600);
  Wire.begin();
  }

void loop(){
  Wire.beginTransmission(address); //Schreiben zu Slave mit Adresse "address"
  Wire.write(startregister);       //Anfangs-Register setzen
  Wire.endTransmission();  //Daten auf den Bus schreiben
  Wire.requestFrom(address, 4); // 4 Bytes anfordern

  Druck1 = Wire.read(); // MSB
  Druck2 = Wire.read(); // LSB
  Temperatur1 = Wire.read(); // MSB
  Temperatur2 = Wire.read(); //LSB
 
  // Berechnung unter Berücksichtigung von Most/Least Significant Byte
  Druck = (((256*Druck1+Druck2)-3277)/(26214/41.36))-20.68;
  Temperatur=(((256*Temperatur1+Temperatur2)-3277)/(26214/110))-25;
 
  // Ausgabe
  //Serial.println("Druck in mbar: "); 
  Serial.print(Druck);
  //Serial.println("Temperatur in °C: "); 
  //Serial.print(" ");
  //Serial.println(Temperatur);

  // nächstes Register auswählen
  startregister++;
  if(startregister==3){
     startregister=0;
  }
  delay(1000);
  }


Wire.begin() habe ich ins Setup genommen und das letzte Wire.endTransmission() herausgelöscht. Ich habe außerdem die Variable "register" in "startregister" umbenannt, da "register" scheinbar vorbelegt ist. Leider wird mir nach dem Upload im Serial Monitor nur

-26.26
-26.26
-26.26
.
.
.

angezeigt. Der Wert ändert sich auch bei Druckänderung nicht. Habe ich doch etwas falsch gemacht? Und: wieviele Register gibt es überhaupt?

Viele Grüße

pfeili

Serenifly

#14
Feb 06, 2015, 01:51 pm Last Edit: Feb 06, 2015, 02:03 pm by Serenifly
Laut Datenblatt Seite 9...:
http://www.amsys.info/sheets/amsys.en.ams5812_e.pdf

...wird da aber eigentlich gar nichts zum Sensor geschickt. Man soll wohl immer 4 Bytes auslesen. Nach der Adresse ist gleich das 1. Byte auf dem Bus.

Probiere also mal den beginTransmission(), write(), endTransmission() Teil ganz wegzulassen


Das ist aber nur die Theorie laut Datenblatt. Praktische Erfahrung habe ich mit dem Teil nicht.


Du kannst mal das als Test probieren:
Code: [Select]

int received = Wire.requestFrom(address, 4);
Serial.print("rec: "); Serial.println(received);

Dann siehst du wie viele Bytes empfangen wurden

Go Up