Hallo,
ich versuche jetzt schon seit einiger Zeit den "BMP180" unter Kontrolle
zu bekommen. Leider klappt das noch nicht 100 % ig...
Was funktionert?
Ich kann die Temperatur und den Druck auslesen...
Leider nur getrent.
sieht so aus..
1
//int16_t tmp_temp = BMP180_read_temperature();
2
longtemp_pressure=BMP180_read_pressure(0);
Möchte ich wieder beides zusammen auslesen, ändern sich meine Werte
komplett in den Falschen Bereich (einzelnd passt Temperatur wie auch
Druck).
Ich vermute mal das ich irgendwas am abholen der Werte falsch mache...
Habt ihr eine Idee?
Hier die Routinen...
1
int16_tBMP180_read_temperature()
2
{
3
longUT;// holds the raw temperature value read from BMP180
Warum hast du in BMP180_read_pressure() das i2c_stop() auskommentiert?
Ausserdem solltest du zwischen den beiden Abfragen vermutlich auch ein
paar ms warten.
Joe F. schrieb:> Warum hast du in BMP180_read_pressure() das i2c_stop()> auskommentiert?> Ausserdem solltest du zwischen den beiden Abfragen vermutlich auch ein> paar ms warten.
- Ich habe schon überall gewartet > 50 ms... hat leider auch nichts
gebracht.
- das Stop habe ich nur testeshalber mal raus genommen (bringt leider
auch nichts).
ich weiß nicht mehr an was das liegen kann...
Dein start, stop, repeated start conditions sind etwas chaotisch.
Die Zeit für die pressure conversion kann auch lt. Datenblatt je nach
Mode bis zu 76.5ms dauern.
Ich denke es müsste so aussehen:
1
int16_tBMP180_read_temperature()
2
{
3
longUT;// holds the raw temperature value read from BMP180
4
longX1,X2;
5
longtruetemperature,B5;
6
7
i2c_start(BMP180_address+I2C_WRITE);
8
i2c_write(0xF4);
9
i2c_write(0x2E);
10
i2c_stop();
11
_delay_ms(5);
12
13
i2c_start(BMP180_address+I2C_WRITE);
14
i2c_write(0xF6);
15
// i2c_stop();
16
17
i2c_rep_start(BMP180_address+I2C_READ);// <--- hier repeated start
18
UT=(long)i2c_readAck()<<8;
19
UT|=(long)i2c_readNak();
20
i2c_stop();
21
22
_delay_ms(1);// <--- mal sicherheitshalber ausprobieren...
Das ändert leider auch nichts... Hier habe ich mal einen Auszug aus
meinem TeraTerm...
Kommentiere ich die einzelnen Funktionen aus, scheint es zu klappen...
So schlecht sieht das doch nicht aus!
1000 mbar sind plausibel, mit der Berechnung der Temperatur ist wohl
noch etwas falsch, aber immerhin schwanken die Werte nicht total absurd.
Joe F. schrieb:> So schlecht sieht das doch nicht aus!> 1000 mbar sind plausibel, mit der Berechnung der Temperatur ist wohl> noch etwas falsch, aber immerhin schwanken die Werte nicht total absurd.
Wieso denkst du, dass da was falsch ist ? Wenn ich alles einzelnd
ausgebe, passt es...
Mit welchem Code fährst du jetzt.
Ich würde mal sagen, du bist zu schnell dir das vermeintliche Ergebnis
abzuholen.
Wenn du nur eine Größe abfragst, dann kommst du damit durch, weil dann
immer wieder nur die Temperatur in die Ausgangsregister geschrieben
werden. D.h. du startest dann zwar eine neue Messung (die auch
irgendwann fertig wird), aus dem Ausgangsregister kriegst du aber das
Ergebnis einer vorhergehenden Messung. Da du zwischendurch nicht den
Messtypus umschaltest, sind die Werte dann auch plausibel.
Wie könnte man das abklären?
Ich würde mir mal die Bytes ausgeben lassen. So wie sie vom Sensor
kommen.
Einmal nur bei Temperatur. Einmal nur bei Druck. Und dann beides
gemeinsam. Wenn alles so läuft wie spekuliert, dann wirst du bei deiner
Temperaturmessung Bytewerte sehen, die dich an die Druckwerte erinnern.
(Ich bin überhaupt ein Fan davon, mit dir rohen Bytes erst mal anzusehen
und nicht gleich rumzurechnen. Ich hab das Gefühl, da sieht man
Zusammenhänge einfach viel besser, als bei offensichtlich falschen
Resultaten, von denen keiner erklären kann wie sie zustande kommen)
Wo werden denn die Variablen/Konstanten AC6, AC5, MC, MD für die
Funktion BMP180_read_temperature() definiert?
Kann es sein, dass du hier andere Werte hast, als die, die dann in
BMP180_read_pressure() gesetzt werden, und dadurch
BMP180_read_temperature() nach einem Aufruf von BMP180_read_pressure()
nicht mehr funktioniert?
Poste mal bitte den gesamten Code, und zwar als Dateianhang.
Joe F. schrieb:> Wo werden denn die Variablen/Konstanten AC6, AC5, MC, MD für die> Funktion BMP180_read_temperature() definiert?> Kann es sein, dass du hier andere Werte hast, als die, die dann in> BMP180_read_pressure() gesetzt werden, und dadurch> BMP180_read_temperature() nach einem Aufruf von BMP180_read_pressure()> nicht mehr funktioniert?> Poste mal bitte den gesamten Code, und zwar als Dateianhang.
Hier habt ihr mal den gesamten Code...
P.S
Danke schon mal für eure schnelle Hilfe!
Jan H. schrieb:> @ Karl Heinz...>> Du scheinst Recht zu haben. Leider klappt es auch mit Wartezeit > 100 ms> nicht.
Wie hoch bist du gegangen?
Geh mal ins Extrem. 1 Sekunde oder so. Nicht kleckern. Klotzen! Wir sind
auf Fehlersuche und nicht beim Wettbewerb.
(ps: mit %x, genauer %04x anstelle von %i oder %u kannst du dir im
sprintf eine hexadezimale Anzeige geben lassen. Hex ist es meist
einfacher Bytes zu vergleichen.)
Blöde Frage: die 8Mhz stimmen aber schon?
Karl Heinz schrieb:> Jan H. schrieb:>> @ Karl Heinz...>>>> Du scheinst Recht zu haben. Leider klappt es auch mit Wartezeit > 100 ms>> nicht.>> Wie hoch bist du gegangen?> Geh mal ins Extrem. 1 Sekunde oder so. Nicht kleckern. Klotzen! Wir sind> auf Fehlersuche und nicht beim Wettbewerb.>> (ps: mit %x, genauer %04x anstelle von %i oder %u kannst du dir im> sprintf eine hexadezimale Anzeige geben lassen. Hex ist es meist> einfacher Bytes zu vergleichen.)>> Blöde Frage: die 8Mhz stimmen aber schon?
Ich bin schon auf 2,5 sec. das klappt nicht.
Ich habe in der "main" 16 MHz definiert.
Karl Heinz schrieb:> Jan H. schrieb:>> @ Karl Heinz...>>>> Du scheinst Recht zu haben. Leider klappt es auch mit Wartezeit > 100 ms>> nicht.>>> Wie hoch bist du gegangen?> Geh mal ins Extrem. 1 Sekunde oder so.
Und das bei beidem: Temperatur UND Druck.
Nach dem Kommando 'Messen' gibst du dem Sensor mal alle Zeit der Welt in
Ruhe und gemütlich seine Messung zu machen.
Jan H. schrieb:> Ich habe in der "main" 16 MHz definiert.
IN deinen BMP Routinen steht aber 8Mhz?
Wenn dein µC mit 16Mnz taktet, dann ist klar, dass ein
1
_delay_ms(5);
keine 5 Millisekunden dauert, wenn der als Berechnungsgrundlage von 8Mhz
ausgeht.
Karl Heinz schrieb:> Jan H. schrieb:>>> Ich habe in der "main" 16 MHz definiert.>> IN deinen BMP Routinen steht aber 8Mhz?>> Wenn dein µC mit 16Mnz taktet, dann ist klar, dass ein _delay_ms( 5 );>> keine 5 Millisekunden dauert, wenn der als Berechnungsgrundlage von 8Mhz> ausgeht.
Habe das #define dort mal raus geschmissen. Nun müsste der Compiler doch
mit meinen "16MHz" von der "main" rechnen oder?
Jan H. schrieb:> Karl Heinz schrieb:>> Jan H. schrieb:>>>>> Ich habe in der "main" 16 MHz definiert.>>>> IN deinen BMP Routinen steht aber 8Mhz?>>>> Wenn dein µC mit 16Mnz taktet, dann ist klar, dass ein _delay_ms( 5 );>>>> keine 5 Millisekunden dauert, wenn der als Berechnungsgrundlage von 8Mhz>> ausgeht.>> Habe das #define dort mal raus geschmissen. Nun müsste der Compiler doch> mit meinen "16MHz" von der "main" rechnen oder?
Nein.
Jedes C File wird für sich selbst und unabhängig von allen anderen
übersetzt.
Wenn der Compiler die BMP180.c übersetzt, dann interessiert es niemanden
was in einem main.c steht.
Jedes C-File steht ganz allein auf weiter Flur und erst im Linker werden
die teilübersetzten Ergebnisse dann zum kompletten Programm
zusammenmontiert. Da ist es aber schon zu spät.
@ Jan H. (janiiix3)
>Habe das #define dort mal raus geschmissen. Nun müsste der Compiler doch>mit meinen "16MHz" von der "main" rechnen oder?
Nö. Poste deine originalen Quelltext als Anhang!
Was ich auch nicht verstehe...
Laut Datenblatt, wird "B5" für die Berechnung vom Druck benötigt.
Deßhalb habe ich "B5" global deklariert. Tue ich genau dies, passt der
Druck nicht mehr.
Deklariere ich "B5" jedes mal in der jeweiligen Funktion "neu"... Habe
ich aufeinmal einen Aktzeptablen Druck...
Muss man das verstehen?
Falk Brunner schrieb:> @ Jan H. (janiiix3)>>>Habe das #define dort mal raus geschmissen. Nun müsste der Compiler doch>>mit meinen "16MHz" von der "main" rechnen oder?>> Nö. Poste deine originalen Quelltext als Anhang!
Nicht wundern, ist nicht sonderlich aufgeräumt :(d
Jan H. schrieb:> Muss man das verstehen?
Ja das sollte man als C-Programmierer
Deine Funktionen sind voller Fehler.
Aber solange die Bytewerte nicht stimmen ist alles andere sinnlos.
Eines nach dem anderen. Erst mal wollen wir vom Sensor die richtigen
Bytewerte zum richtigen Zeitpunkt.
Dann kommt der Rest.
Karl Heinz schrieb:> Jan H. schrieb:>>> Muss man das verstehen?>> Ja das sollte man als C-Programmierer> Deine Funktionen sind voller Fehler.>> Aber solange die Bytewerte nicht stimmen ist alles andere sinnlos.> Eines nach dem anderen. Erst mal wollen wir vom Sensor die richtigen> Bytewerte zum richtigen Zeitpunkt.> Dann kommt der Rest.
Ich bin jetzt auch nicht so der "Pro" Programmierer. Fange ja erst
richtig an.
Wo sind denn Fehler?
Jan H. schrieb:> Karl Heinz schrieb:>> Jan H. schrieb:>>>>> Muss man das verstehen?>>>> Ja das sollte man als C-Programmierer>> Deine Funktionen sind voller Fehler.>>>> Aber solange die Bytewerte nicht stimmen ist alles andere sinnlos.>> Eines nach dem anderen. Erst mal wollen wir vom Sensor die richtigen>> Bytewerte zum richtigen Zeitpunkt.>> Dann kommt der Rest.>> Ich bin jetzt auch nicht so der "Pro" Programmierer. Fange ja erst> richtig an.>> Wo sind denn Fehler?
Zum Beispiel das B5 in der Druck Lesefunktion.
Welchen Wert hat es, wenn die Berechnungen starten?
Karl Heinz schrieb:> Zum Beispiel das B5 in der Druck Lesefunktion.> Welchen Wert hat es, wenn die Berechnungen starten?> unsigned long BMP180_read_pressure(uint8_t oversampling_setting)> {> long UP, B5;> ....> B6 = B5 - 4000;> ....>> richtig. Wir wissen es nicht. Irgendeinen. Zufällig. Was halt gerade im> Speicher stand, als die Funktion betreten wurde.
Ich sollte die Variablen vorher "auf null" setzen, richtig ?
Jan H. schrieb:> Karl Heinz schrieb:>> Zum Beispiel das B5 in der Druck Lesefunktion.>> Welchen Wert hat es, wenn die Berechnungen starten?>> unsigned long BMP180_read_pressure(uint8_t oversampling_setting)>> {>> long UP, B5;>> ....>> B6 = B5 - 4000;>> ....>>>> richtig. Wir wissen es nicht. Irgendeinen. Zufällig. Was halt gerade im>> Speicher stand, als die Funktion betreten wurde.>> Ich sollte die Variablen vorher "auf null" setzen, richtig ?
Was steht denn im Datenblatt?
0 wird wohl nicht so prickelnd sein.
Denn dann würde man wohl kein B5 in der Vorlage von Bosch finden,
sondern dann würde dort wohl gleich
1
B6=-4000;
stehen. Wäre doch um einiges einfacher. Oder nicht?
Du fängst zur raten an. Kein gutes Zeichen.
@Jan H. (janiiix3)
> read_BMP180.zip (5,73 MB, 0 Downloads)
Das 8MB Datenblatt hättest du uns ersparen können.
Dann wären es nur noch schlappe 99kB gewesen . . .
>Nicht wundern, ist nicht sonderlich aufgeräumt :(d
Die #define F_CPU sind in bmp180.c und read_bmp180.c richtig. Aber so
sollte man es dennoch nicht tun, denn man muss die gleiche Information
an zwei Orten aktuell halten.
Entweder im AVR Studio in den Projektoptionen einstellen, dann wird
daraus ein automatisches #define beim Compilieren
Oder EINMALIG in EINER main.h das #define reinschreiben. Diese wird dann
in allen anderen Dateien über #inlcude "main.h" genutzt.
Für deine Fehlersuche bringt das jetzt aber nicht viel.
Du hast an vielen Stellen sowas hier:
i2c_stop();
i2c_rep_start(BMP180_address+I2C_READ);
z.B. in BMP180_read_i16()
Das macht keinen Sinn.
Nach einer stop condition braucht man eine start condition.
repeated start nur ohne vorherige stop condition.
So wäre es richtig:
1
int16_tBMP180_read_i16(uint8_treg)
2
{
3
int16_ttmp_cal;
4
5
// i2c_rep_start(BMP180_address+I2C_WRITE);
6
i2c_start(BMP180_address+I2C_WRITE);// <--- hier start
7
8
i2c_write(reg);
9
// i2c_stop(); // <--- vor repeated start kein stop
Karl Heinz schrieb:> Jan H. schrieb:>> Karl Heinz schrieb:>>> Zum Beispiel das B5 in der Druck Lesefunktion.>>> Welchen Wert hat es, wenn die Berechnungen starten?>>> unsigned long BMP180_read_pressure(uint8_t oversampling_setting)>>> {>>> long UP, B5;>>> ....>>> B6 = B5 - 4000;>>> ....>>>>>> richtig. Wir wissen es nicht. Irgendeinen. Zufällig. Was halt gerade im>>> Speicher stand, als die Funktion betreten wurde.>>>> Ich sollte die Variablen vorher "auf null" setzen, richtig ?>> Was steht denn im Datenblatt?> 0 wird wohl nicht so prickelnd sein.> Denn dann würde man wohl kein B5 in der Vorlage von Bosch finden,> sondern dann würde dort wohl gleich B6 = -4000;> stehen. Wäre doch um einiges einfacher. Oder nicht?>> Du fängst zur raten an. Kein gutes Zeichen.
Ich habe doch weiter oben schon geschrieben, dass ich "B5" global
deklariert habe, da dieses mit in die Rechnung für den "Druck"
einfließt.
Nun tu ich das so, passt mein Druck in keiner weise mit dem aktuellen
Druck zusammen.
Deklariere ich die Variable in jeder Funktion neu, kommt der Druck
ungefähr hin...
hast du jedenfalls nicht 0 genommen.
Aber das gilt jetzt nichts, da ja
1
#define sample_calibration_test 0
dieser Wert nicht zum Zug kommt.
Können wir uns jetzt bitte erst mal auf das Teilproblem konzentrieren
'die richtigen Ergebnisbytes zur richtigen Messung vom Sensor'?
Du verzettelst dich sonst (gut, das hat du sowieso schon. Aber ich sehe
es als meine Aufgabe an, dich wieder zurückzubringen und dein
rumgestochere in geordnete Bahnen zu lenken).
Jan H. schrieb:> Ich habe doch weiter oben schon geschrieben, dass ich "B5" global> deklariert habe, da dieses mit in die Rechnung für den "Druck"> einfließt.>> Nun tu ich das so, passt mein Druck in keiner weise mit dem aktuellen> Druck zusammen.>> Deklariere ich die Variable in jeder Funktion neu, kommt der Druck> ungefähr hin...
Wollen wir jetzt wirklich noch einen Grundlagenkurs
"C, lokale Variablen und wie werden sie initialisiert"
oben draufsetzen?
Karl Heinz schrieb:> Können wir uns jetzt bitte erst mal auf das Teilproblem konzentrieren> 'die richtigen Ergebnisbytes zur richtigen Messung vom Sensor'?
Die A/D Werte habe ich doch oben schon gepostet.
Joe F. schrieb:> Du hast an vielen Stellen sowas hier:
Ich hätt auch gesagt:
schmeiss die 85 unterschiedlichen Read und Write Funktionen raus. Im
gegenständlichen Fall bringen sie sowieso nichts, weil sie kein Aas
benutzt.
Jan H. schrieb:> Karl Heinz schrieb:>> Können wir uns jetzt bitte erst mal auf das Teilproblem konzentrieren>> 'die richtigen Ergebnisbytes zur richtigen Messung vom Sensor'?>> Die A/D Werte habe ich doch oben schon gepostet.
Da waren wir aber noch im F_CPU Dilemma.
Deine Wartezeiten haben nicht gestimmt.
Insbesondere waren deine 5ms nur 2.5ms. Laut Bosch zuwenig für eine
Temperaturmessung
Das gleiche auch in BMP180_read_u16().
Ausserdem macht es keinen Sinn, 2 Funktionen hierfür zu haben.
BMP180_read_u16() reicht völlig aus.
Wenn deine Variable, der du den Rückgabewert von BMP180_read_u16 zuweist
ein int16_t ist, castet dir der Compiler das hin.
Oder du machst es eben explizit:
int16_t AC1;
AC1 = (int16_t)(BMP180_read_u16(0xAA));
Nur mal so. Wenn man das Prpjekt einfach mal compiliert, kommen 8
Warnungen! Die sollte man intelligenterweise NICHT ignorieren. U.a.
Warning 6 'B5' is used uninitialized in this function
[-Wuninitialized] D:\download\read_BMP180\read_BMP180\BMP180.c 164 8
read_BMP180
Ausserdem wird hier anfängertypisch ganz schön rumgewurschtelt, u.a. mit
globalen Variabeln in verteilten .c Dateien. Das geht meist schief ;-)
Jan H. schrieb:> So, nun noch mal die aktuellen A/D Werte.
Das sieht doch schon mal viel freundlicher aus. Zumindest unterscheidet
sich der vom Sensor als Temperatur ausgewiesene Wert schon mal vom
Druckwert.
Kaum macht mans richtig, funktioniert es auch.
>> fehlen doch mit Sicherheit ein paar Klammern.
Jep.
Und zwar hier
1
X2=(MC<<11)/(X1+MD);
und der anderen Zeile würde es auch nicht schaden, wenn man eine Klammer
einführt, auch wenn sie technisch nicht notwendig ist. Dem Verständnis
würde es IMHO zugute kommen
> X1 = (UT - AC6) * AC5 >> 15;> X2 = MC << 11 / (X1 + MD);>fehlen doch mit Sicherheit ein paar Klammern.>Mal bei Bosch nachsehen, wie das wirklich berechnet wird.
Alder, wenn bei einmaligem Aufruf der Funktion
korrekte Druck - und Termperaturwerte rauskommen
dann wird das Problem sicher nicht von fehlenden Klammern
verursacht.
Zugegeben, der Code sieht ohne Klammern scheisse
aus, aber man muss keine Klammern setzen wenn
man sie nicht braucht.
Klammern sind was für Leute die die Punkt-vor Strich-Regel
nicht kennen.
Was weiss man eigentlich über AC6 bzw. AC5 vom Zahlenwert her?
Stimmen die in etwa mit den Werten aus dem Datenblatt überein?
Der rohe Datenwert für die Temperatur ist ja nicht so weit weg vom
Datenblatt. Im Datenblatt ergibt sich im Beispiel aus 27898 eine
Temperatur von 15.0°C. Ich weiss jetzt nicht, wie warm oder kalt es bei
dir ist, aber 28830 ist von den 27898 nicht so weit weg. Das könnte
hinkommen, wenn die Werte für AC5 und AC6 in etwa mit dem Datenblatt
vergleichbar sind.
Frank Fahrenheit schrieb:>> X1 = (UT - AC6) * AC5 >> 15;>> X2 = MC << 11 / (X1 + MD);>>>>fehlen doch mit Sicherheit ein paar Klammern.>>Mal bei Bosch nachsehen, wie das wirklich berechnet wird.>> Alder,
Alder.
Ein << unterscheidet sich von einem / nun mal durch die Operator
Precedence.
> wenn bei einmaligem Aufruf der Funktion> korrekte Druck - und Termperaturwerte rauskommen> dann wird das Problem sicher nicht von fehlenden Klammern> verursacht.
So, so.
Du glaubst also, dass es bei ihm wirklich -17°C hat?
Karl Heinz schrieb:> Frank Fahrenheit schrieb:>>> X1 = (UT - AC6) * AC5 >> 15;>>> X2 = MC << 11 / (X1 + MD);>>>>>>>fehlen doch mit Sicherheit ein paar Klammern.>>>Mal bei Bosch nachsehen, wie das wirklich berechnet wird.>>>> Alder,>> Alder.> Ein << unterscheidet sich von einem / nun mal durch die Operator> Precedence.
Aber ich lad dich gerne ein, dir im Datenblatt die korrekte Formel
anzusehen und mit dem zu vergleichen, was er draus gemacht hat
Alder
> wenn bei einmaligem Aufruf der Funktion> korrekte Druck - und Termperaturwerte rauskommen> dann wird das Problem sicher nicht von fehlenden Klammern> verursacht.
Guckst Du mal beim Posting von 16:46
Frank Fahrenheit schrieb:>> wenn bei einmaligem Aufruf der Funktion>> korrekte Druck - und Termperaturwerte rauskommen>> dann wird das Problem sicher nicht von fehlenden Klammern>> verursacht.>> Guckst Du mal beim Posting von 16:46
Ja ich sehs.
Ein Raum, der sich in ... na so ca. 300ms von 43 Grad auf 19 Grad
abkühlt und dann wieder auf 23 Grad aufheizt.
Genau.
Aber ... du kannst ihm gerne helfen, wenn du magst.
(Das Bild mit der Formel aus dem Datenblatt schon gesehen?)
Karl Heinz schrieb:> Aber ... du kannst ihm gerne helfen, wenn du magst.> (Das Bild mit der Formel aus dem Datenblatt schon gesehen?)
Guckst du (siehe Bild)
Und jetzt das Suchbild: Wodurch unterscheidet sich das von
>Ein Raum, der sich in ... na so ca. 300ms von 43 Grad auf 19 Grad>abkühlt und dann wieder auf 23 Grad aufheizt.
Und fehlende Klammern erklären diese merkwürdigen Trends?
Frank Fahrenheit schrieb:>>Ein Raum, der sich in ... na so ca. 300ms von 43 Grad auf 19 Grad>>abkühlt und dann wieder auf 23 Grad aufheizt.>> Und fehlende Klammern erklären diese merkwürdigen Trends?
Weisst was. Studier eine operator precedence table.
Dann weisst du was der entscheidende Unterschied zwischen Rechts
Schieben und Multiplizieren ist. WEnn Bosch multiplizeren will, dann
kann man das nicht einfach so mir nichts dir nichts durch schieben
ersetzen.
Und da ist das Problem des Vorzeichens noch gar nicht inkludiert. Danke
Joe.
drama schrieb:> Und ich frag mich hier wieder, warum keiner den offiziellen Code nutzt:
Wär natürlich gegangen.
Aber auch den müsste man (nach einem ersten Eindruck beim
Drüberscrollen) noch ein wenig von Linux auf AVR anpassen.
Da gibt es natürlich noch mehr
Beitrag "Re: BMP180 Library"
Aber manchem C-Anfänger tut es gut, wenn er seinen Code nicht nur aus
Libraries zusammenbaut, sondern sich auch mal mit den Bits und Bytes
hinter den Kulissen beschäftigt.
Karl Heinz schrieb:> Wär natürlich gegangen.> Aber auch den müsste man (nach einem ersten Eindruck beim> Drüberscrollen) noch ein wenig von Linux auf AVR anpassen.
Der Code ist nicht speziell für Linux o.ä., der ist sehr generisch. Man
muss nur ein paar Funktionspointer in einem struct setzen, damit der
Zugriff auf I2C-Hardware klappt.
drama schrieb:> Karl Heinz schrieb:>> Wär natürlich gegangen.>> Aber auch den müsste man (nach einem ersten Eindruck beim>> Drüberscrollen) noch ein wenig von Linux auf AVR anpassen.>> Der Code ist nicht speziell für Linux o.ä., der ist sehr generisch. Man> muss nur ein paar Funktionspointer in einem struct setzen, damit der> Zugriff auf I2C-Hardware klappt.
Hab ich gesehen.
Und du denkst, das kriegt er hin?
:-)
Sein Code ist ja einigermaßen korrekt. Kein Grund alles umzubauen.
Die Temperaturberechnung muss gefixed werden (Bitshifts raus, Mathe
rein), und vor allem auch die I2C Kommunikation (start, stop,
repeated-start).
Kann ja sein, dass die total kaputte Kommunikation vielleicht sogar
irgendwie gerade eben funktioniert, nur entspricht sie absolut nicht der
Spezifikation.
Dass der Chip offenbar nach einem stop mit einem repeated-start klar
kommt ist reiner Zufall.
Wenn Bosch da irgendwann mal was am Chip ändert knallt es.
Schade nur, dass es keine Rückmeldung mehr gibt, ob die Temperatur-Werte
jetzt stimmen.
Der nächste Schritt wäre jetzt gewesen, den ominösen Wert B5 von der
Temperaturmessung in die Druckmessung zu übernehmen. Denn der Wert ist
dort Teil der Berechnung.
Hallo,
sorry das ich mich gestern nicht mehr gemeldet habe. Musste leider
dringend weg.
So, ich habe den Ratschlag mit dem Bitschifting befolgt und diesen
Codeteil umgebaut.
Nun habe ich mal die aktuellen "A/D Werte" mit "B5" ausgelesen.
Hier das Ergebninss.
Jan H. schrieb:> Hallo,>> sorry das ich mich gestern nicht mehr gemeldet habe. Musste leider> dringend weg.>> So, ich habe den Ratschlag mit dem Bitschifting befolgt und diesen> Codeteil umgebaut.>> Nun habe ich mal die aktuellen "A/D Werte" mit "B5" ausgelesen.
Alles schön.
Nur kann man ohne Kenntnis der zuvor ausgelesenen Koeffizienten AC5 und
AC6, UT, MC und MD nicht nachvollziehen, wie das Ergebnis zustande
kommt.
Karl Heinz schrieb:> Jan H. schrieb:>> Hallo,>>>> sorry das ich mich gestern nicht mehr gemeldet habe. Musste leider>> dringend weg.>>>> So, ich habe den Ratschlag mit dem Bitschifting befolgt und diesen>> Codeteil umgebaut.>>>> Nun habe ich mal die aktuellen "A/D Werte" mit "B5" ausgelesen.>> Alles schön.> Nur kann man ohne Kenntnis der zuvor ausgelesenen Koeffizienten AC5 und> AC6, UT, MC und MD nicht nachvollziehen, wie das Ergebnis zustande> kommt.
UT natürlich nicht. Das ist einfach nur die Zusammensetzung der beiden
Bytes vom Sensor
Ich muss noch dazu sagen, dass ich die Muster Kalibrationswerte vom
Datenblatt mit dem Algo. umgerechnet habe ( also mein µC hat es
umgerechnet ) und ich kam genau auf das Ergebniss wie im Datenblatt.
Also sollte die Umrechnung funktionieren.
Falk Brunner schrieb:> Ich glaube aber nicht, dass bei dir am Platz 36°C sind. Also> stimmt es> noch nicht so ganz.
Stimmt!
Habe hier im Raum ca. 18 - 20°C.
Ich kenne den Sensor und das Datenblatt nicht. Aber hier könnte ein
Fehler stecken.
UT = (long)i2c_readAck()<<8;
UT |= (long)i2c_readNak();
Damit wird man NIE negative Zahlen erhalten. Es fehlt die
Vorzeichenerweiterung. Der Cast macht das glaube ich nicht. Da fehlt
hinterher noch ein
Jan H. schrieb:> Karl Heinz schrieb:>> Sind 18.9°C als Temperatur in deiner Umgebung realistisch?>> Ja, durchaus!
OK.
Das sind deine Zwischenergebnisse
1
X1: 5791
2
X2: -2764
3
B5: 3027
4
Temp: 189
mit diesem Code
1
#include"stdafx.h"
2
3
intmain()
4
{
5
intAC5=24808;
6
intAC6=20872;
7
intMC=-11782;
8
intMD=2937;
9
10
intUT=28522;
11
12
intX1=((UT-AC6)*AC5)>>15;
13
intX2=(MC<<11)/(X1+MD);
14
intB5=X1+X2;
15
16
intTemp=(B5+8)>>4;
17
18
printf("X1: %d\n",X1);
19
printf("X2: %d\n",X2);
20
printf("B5: %d\n",B5);
21
printf("Temp: %d\n",Temp);
22
23
return0;
24
}
lass dich nicht von den int täuschen. Ich hab das auf dem PC gemacht, da
ist ein int 4 Byte gross. Auf einem AVR sind das alles long bzw. int32_t
Das hier
> int X2 = ( MC << 11 ) / ( X1 + MD );
ist natürlich extrem fies von Bosch.
Wenn bei der Multiplikation mit 2 hoch 11 der falsche Datentyp steht,
dann werden die Bits nicht korrekt an der 32 Bit Grenze abgeschnitten,
wie es vorausgesetzt wird.
Jan H. schrieb:> Karl Heinz schrieb:>> printf( "B5: %d\n", B5 );>> Also meinst du es liegt an meinem "uint16_t AC4, AC5, AC6;"?
Ja.
Denn der Bosch-Code beruht heftig darauf, dass die Ergebnisse in 32 Bbit
darstellbar sind. Multiplizierst du aber 16 Bit mit 16 Bit, dann kriegst
du auch nur ein 16 Bit Ergebnis und keines mit 32 Bit.
Du hast die Werte, setz sie in deinen Code ein, lass dir die
Zwischenergebnisse ausgeben und sieh dir an, wo du Abweichungen hast.
Karl Heinz schrieb:> Jan H. schrieb:>> Karl Heinz schrieb:>>> printf( "B5: %d\n", B5 );>>>> Also meinst du es liegt an meinem "uint16_t AC4, AC5, AC6;"?>> Ja.> Denn der Bosch-Code beruht heftig darauf, dass die Ergebnisse in 32 Bbit> darstellbar sind. Multiplizierst du aber 16 Bit mit 16 Bit, dann kriegst> du auch nur ein 16 Bit Ergebnis und keines mit 32 Bit.>> Du hast die Werte, setz sie in deinen Code ein, lass dir die> Zwischenergebnisse ausgeben und sieh dir an, wo du Abweichungen hast.
Kannst du mal dein Programm für den PC mit anhängen?
Karl Heinz schrieb:> Jan H. schrieb:>> Karl Heinz schrieb:>>> printf( "B5: %d\n", B5 );>>>> Also meinst du es liegt an meinem "uint16_t AC4, AC5, AC6;"?>> Ja.
und auch MC und MD.
Das ist allerdings auch nur die halbe Miete.
Wenn du da auf int32_t hochgehst, musst du beim Zusammensetzen der Bytes
aufpassen, wie Falk korrekt einwendet.
Jan H. schrieb:> Kannst du mal dein Programm für den PC mit anhängen?
Hab ich doch!
Ich hab keinen Sensor.
Ich nehm deine Kalbrierwerte, deinen Sensorwert, definier mir dafür die
Variablen und häng die Berechnungsvorschrift von Bosch rein.
und dann krieg ich 18.9 Grad Celsius raus, wenn ich alles in signed 32
Bit rechne.
Beitrag "Re: BMP180 I2C Problem?"
Karl Heinz schrieb:> Jan H. schrieb:>>> Kannst du mal dein Programm für den PC mit anhängen?>> Hab ich doch!>> Ich hab keinen Sensor.> Ich nehm deine Kalbrierwerte, deinen Sensorwert, definier mir dafür die> Variablen und häng die Berechnungsvorschrift von Bosch rein.>> und dann krieg ich 18.9 Grad Celsius raus, wenn ich alles in signed 32> Bit rechne.>> Beitrag "Re: BMP180 I2C Problem?"
Okay, ich werde es nacher dirkt noch einmal ausprobieren.
Karl Heinz schrieb:> lass dich nicht von den int täuschen. Ich hab das auf dem PC gemacht, da> ist ein int 4 Byte gross. Auf einem AVR sind das alles long bzw. int32_t
Die Temperatur- und Druckberechnung lässt sich auch mit Fließkommazahlen
ausführen, dem C-Compiler wird es egal sein. Oder spricht etwas dagegen?
Alex D. schrieb:> Karl Heinz schrieb:>> lass dich nicht von den int täuschen. Ich hab das auf dem PC gemacht, da>> ist ein int 4 Byte gross. Auf einem AVR sind das alles long bzw. int32_t>> Die Temperatur- und Druckberechnung lässt sich auch mit Fließkommazahlen> ausführen, dem C-Compiler wird es egal sein. Oder spricht etwas dagegen?
Weiss ich noch nicht.
Die Bosch Leute sind da .... etwas seltsam unterwegs.
Die Casten da in ihrem eigenen Code hemmungslos rum
(Hier die Temperatur)
AC5 und AC6 sind eigentlich unsigned Werte, werden aber zur Berechnung
auf signed 32 hochgecastet.
Im Moment hab ich noch keinen Überblick, wann und wo es zu einer
Vorzeichenerweiterung kommen muss und wo nicht (falls letzteres
überhaupt irgendwo der Fall sein sollte).
Schön langsam denke ich echt, drama hat hier
Beitrag "Re: BMP180 I2C Problem?"
recht.
Nimm die Umrechnungsfunktionen und die Strukturdefinition von Bosch her
wie sie sind. Definier dir entsprechende typedef, nimm deine I2C
Funktionen setz die Bytes entsprechend zusammen aber nimm um Himmels
Willen die Bosch Funktionen um die Werte umzurechnen.
Da stecken so viele Datentypfallen drinn, dass geht auf keine Kuhhaut.
Denn Bosch Code kann man vereinfachen, der ist dort natürlich in der
Version 'passt überall, wenn man die richtigen #define setzt'. Das kann
man abspecken. Aber ausser, dass der Pointer auf die Struktur rausfliegt
und durch eine direkte Adressierung ersetzt wird, greif die eigentliche
Berechnung bloss nicht an.
:-)
@ Karl Heinz (kbuchegg) (Moderator)
>Da stecken so viele Datentypfallen drinn, dass geht auf keine Kuhhaut.
Naja, bei Bosch arbeiten auch genügend Praktikanten. Dazu der bekannte
Spruch "Guten Leuten muss man absagen".
Und dieses Beispiel ist mal wieder ein "schönes" zum Thema "int
Datenbreit und C".
Mit int32_t wär das nicht passiert, 16 Jahre nach C99 . . .
Was ich nicht verstehe...
Wenn ich die Musterwerte in die umrechnung haue... Kommt doch das
richtige Ergebniss raus (laut Datenblatt : Seite 15)...
Also kann es doch nicht an der Umrechnung liegen? Sehe ich da etwas
falsch?