BMP180 I2C Problem?

Gast #4039083
Lesenswert?

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
    long temp_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_t BMP180_read_temperature()
2
{
3
  long UT; // holds the raw temperature value read from BMP180
4
  long X1, X2;
5
  long truetemperature, 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_start(BMP180_address+I2C_READ);
18
  UT  = (long)i2c_readAck()<<8;
19
  UT |= (long)i2c_readNak();
20
  i2c_stop();
21
  
22
  X1 = ((long)(UT - AC6)) * ((long)(AC5)) >> 15;
23
   X2 = ((long)MC << 11) / (X1 + MD); 
24
   B5 = (long)X1 + X2; 
25
  truetemperature = (long)((B5 + 8) >> 4);
26
  
27
  truetemperature = truetemperature / 10;
28

29
  return truetemperature;
30
}
31

32
unsigned long BMP180_read_pressure(uint8_t oversampling_setting)
33
{
34
  long      B6, X1, X2, X3, B3;
35
  unsigned long  B4,B7;  
36
  long      UP, B5;   
37
  unsigned long  truepressure;
38
  
39
  i2c_start(BMP180_address+I2C_WRITE);
40
  i2c_write(0xF4);
41
  i2c_write(0xF4);  
42
  i2c_stop();
43
  _delay_ms(40);
44
  
45
  i2c_rep_start(BMP180_address+I2C_WRITE);
46
  i2c_write(0xF6);
47
  
48
  i2c_rep_start(BMP180_address+I2C_READ);
49
  UP  = (long)i2c_readAck()<<8;
50
  UP |= (long)i2c_readNak();
51
  //i2c_stop();
52

53

54
#if sample_calibration_test == 1
55
    
56
  /*sample calibrations*/   
57
  oversampling_setting = 0;  
58
  AC1 = (short)408;
59
  AC2 = (short)-72;
60
  AC3 = (short)-14383;
61
  AC4 = (unsigned short) 32741;
62
  AC5 = (unsigned short)32757;
63
  AC6 = (unsigned short)23153;
64
  B1 = (short)6190;
65
  B2 = (short)4;
66
  MB = (short)-32768;
67
  MC = (short)-8711;
68
  MD = (short)2868;
69
   
70
  UP = 23843;  
71
  B5 = 2399;
72

73
#endif
74

75

76
    B6 = B5 - 4000;
77
   X1 = (B2 * (B6 * B6 / 4096)) / 2048;
78
   X2 = (AC2 *  B6) / 2048;
79
   X3 = X1 + X2;
80
   B3 = (((AC1 * 4 + X3) << oversampling_setting) + 2) / 4;
81
   X1 = AC3 * B6 / 8192;
82
   X2 = (B1 * (B6 * B6 / 4096)) / 65536;
83
   X3 = ((X1 + X2) + 2) / 4;
84
   B4 = AC4 *(unsigned long) (X3 + 32768) / 32768;
85
   B7 = ((unsigned long)UP-B3) * (50000 >> oversampling_setting);
86
 
87
  if(B7 < 0x80000000)
88
  {
89
     truepressure = (B7 * 2) / B4;
90
   }
91
   else
92
  {
93
     truepressure = (B7 / B4) *2;
94
   }   
95
   
96
   X1 = (truepressure / 256) * (truepressure / 256);
97
  X1 = (X1 * 3038) / 65536;    
98
   X2 = (-7357 * truepressure) / 65536;
99
   truepressure = truepressure + (X1 + X2 + 3791) / 16;
100

101
  truepressure = truepressure * 0.01;
102
  return (unsigned long)truepressure;
103
}
#4039728
Lesenswert?

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...
#4040004
Lesenswert?

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_t BMP180_read_temperature()
2
{
3
  long UT; // holds the raw temperature value read from BMP180
4
  long X1, X2;
5
  long truetemperature, 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...
23

24
  
25
  X1 = ((long)(UT - AC6)) * ((long)(AC5)) >> 15;
26
   X2 = ((long)MC << 11) / (X1 + MD); 
27
   B5 = (long)X1 + X2; 
28
  truetemperature = (long)((B5 + 8) >> 4);
29
  
30
  truetemperature = truetemperature / 10;
31

32
  return truetemperature;
33
}
34

35
unsigned long BMP180_read_pressure(uint8_t oversampling_setting)
36
{
37
  long      B6, X1, X2, X3, B3;
38
  unsigned long  B4,B7;  
39
  long      UP, B5;   
40
  unsigned long  truepressure;
41
  
42
  i2c_start(BMP180_address+I2C_WRITE);
43
  i2c_write(0xF4);
44
  i2c_write(0xF4);  
45
  i2c_stop();
46
//  _delay_ms(40);
47
  _delay_ms(80); // <--- hier mal laenger warten
48
  
49
//  i2c_rep_start(BMP180_address+I2C_WRITE);
50
  i2c_start(BMP180_address+I2C_WRITE); // <--- hier NICHT rep_start
51
  i2c_write(0xF6);
52
  
53
  i2c_rep_start(BMP180_address+I2C_READ);
54
  UP  = (long)i2c_readAck()<<8;
55
  UP |= (long)i2c_readNak();
56
  //i2c_stop();
57

58
  i2c_stop();   // <--- diese stop condition brauchst du mit Sicherheit
59
  _delay_ms(1); // <--- auch ausprobieren
60

61
  (...)
#4040492
Lesenswert?

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)
#4040494
Lesenswert?

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.
#4040495
Lesenswert?

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!
Angehängte Dateien:
#4040508
Lesenswert?

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?
#4040513
Lesenswert?

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.
#4040514
Lesenswert?

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.
#4040519
Lesenswert?

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?
#4040522
Lesenswert?

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.
#4040526
Lesenswert?

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?
#4040537
Lesenswert?

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?
#4040541
Lesenswert?

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?
1
unsigned long BMP180_read_pressure(uint8_t oversampling_setting)
2
{
3
  long      UP, B5;   
4
....
5
    B6 = B5 - 4000;
6
....

richtig. Wir wissen es nicht. Irgendeinen. Zufällig. Was halt gerade im 
Speicher stand, als die Funktion betreten wurde.
#4040544
Lesenswert?

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 ?
#4040549
Lesenswert?

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.
#4040551
Lesenswert?

@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.
#4040553
Lesenswert?

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_t BMP180_read_i16(uint8_t reg)
2
{
3
  int16_t tmp_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
10
  
11
  i2c_rep_start(BMP180_address+I2C_READ);
12
  tmp_cal  = i2c_readAck()<<8;
13
  tmp_cal |= i2c_readNak();
14
  i2c_stop();
15
  
16
  return tmp_cal;
17
}
#4040554
Lesenswert?

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...
#4040557
Lesenswert?

Hier

1
#if sample_calibration_test == 1
2
    
3
...   
4
  UP = 23843;  
5
  B5 = 2399;
6

7
#endif

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).
#4040559
Lesenswert?

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?
#4040566
Lesenswert?

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
#4040570
Lesenswert?

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));
#4040571
Lesenswert?

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 ;-)
#4040586
Lesenswert?

Karl Heinz schrieb:
> Da
>
1
>   X1 = (UT - AC6) * AC5 >> 15;
2
>    X2 = MC << 11 / (X1 + MD);
3
>
>
> 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
1
   X1 = ( (UT - AC6) * AC5 ) >> 15;
#4040588
Lesenswert?

>  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.
#4040590
Lesenswert?

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.
#4040594
Lesenswert?

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?
#4040601
Lesenswert?

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
Angehängte Dateien:
#4040608
Lesenswert?

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?)
#4040616
Lesenswert?

Die Klammer spielt eine entscheidende Rolle:
1
        AC5 = 32757;
2
        AC6 = 23153;
3
        MC = -8711;
4
        MD = 2868;
5

6
        UT = 27898;
7

8

9
        X1 = (UT - AC6) * AC5 >> 15;
10
        X2 = MC << 11 / (X1 + MD);
11
        B5 = X1 + X2;
12
        truetemperature = (B5 + 8) >> 4;
13

14
        printf("%ld\n", truetemperature);

Ausgabe: -248
1
X2 = (MC << 11) / (X1 + MD);

Ausgabe: 150


Aufpassen auch bei negativen Zahlen.
Da ist Bitshiften etwas anderes wie Multiplizieren/Teilen...
#4040618
Lesenswert?

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.
Gast #4040774
Lesenswert?

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.
#4040799
Lesenswert?

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?

:-)
#4040847
Lesenswert?

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.
#4041879
Lesenswert?

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.
#4041885
Lesenswert?

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
#4041917
Lesenswert?

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
1
  if (UT & 0x8000) UT |= 0xFFFF0000;

Bei Druck könnte/sollte man das Gleiche machen.
#4041920
Lesenswert?

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
int main()
4
{
5
  int AC5 = 24808;
6
  int AC6 = 20872;
7
  int MC = -11782;
8
  int MD = 2937;
9

10
  int UT = 28522;
11

12
  int X1 = (( UT - AC6 ) * AC5 ) >> 15;
13
  int X2 = ( MC << 11 ) / ( X1 + MD );
14
  int B5 = X1 + X2;
15

16
  int Temp = ( 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
  return 0;
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
#4041935
Lesenswert?

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.
#4041943
Lesenswert?

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?
#4041953
Lesenswert?

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.
#4041973
Lesenswert?

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)
1
s16 bmp180_get_temperature(u32 v_uncomp_temperature_u32)
2
{
3
  s16 v_temperature_s16 = C_BMP180_ZERO_U8X;
4
  s32 v_x1_s32, v_x2_s32 = C_BMP180_ZERO_U8X;
5
  /* calculate temperature*/
6
  v_x1_s32 = (((s32) v_uncomp_temperature_u32 -
7
  (s32) p_bmp180->calib_param.ac6) *
8
  (s32) p_bmp180->calib_param.ac5) >> BMP180_SHIFT_15_POSITION;
9
  if (v_x1_s32 == C_BMP180_ZERO_U8X && p_bmp180->calib_param.md
10
  == C_BMP180_ZERO_U8X) {
11
    return C_BMP180_ZERO_U8X;
12
  } else {
13
    v_x2_s32 = ((s32) p_bmp180->calib_param.mc
14
    << BMP180_SHIFT_11_POSITION) /
15
    (v_x1_s32 + p_bmp180->calib_param.md);
16
  }
17
  p_bmp180->param_b5 = v_x1_s32 + v_x2_s32;
18
  v_temperature_s16 = ((p_bmp180->param_b5 + C_BMP180_EIGHT_U8X)
19
  >> BMP180_SHIFT_4_POSITION);
20

21
  return v_temperature_s16;
22
}

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).
#4041980
Lesenswert?

Karl Heinz schrieb:
> Karl Heinz schrieb:
>
>>
1
>> s16 bmp180_get_temperature(u32 v_uncomp_temperature_u32)
2
>> {
3
>>
>
> dafür ist der Eingangswert wieder ein unsigned mit 32 Bit, der von 16
> Bit vom Sensor stammmt.

Der zur Rechnerei
1
  v_x1_s32 = (((s32) v_uncomp_temperature_u32 -
wieder auf einen signed mit 32 Bit umgecastet wird :-)


Ganz ehrlich: Ruhmesblatt ist das alles nicht.
#4041990
Lesenswert?

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.
:-)
#4042097
Lesenswert?

@ 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 . . .

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren