I2C TWI BMP180 C#

Gast #6097924
Lesenswert?

Hallo liebe pure C# Programmierer,
ich habe von meiner Techniker Schule die Vorgabe in C# ein Projekt zu 
machen.
Dieser Code wollte ich mit euch teilen und ein Problem von der Rechnung 
der Temperatur und Luftdruck besprechen.
Die Rechnung habe ich aus dem Datenblatt genommen und abgetippt.
Jedoch kommen noch die richtigen Werte raus.
Darum kümmere ich mich noch.
Trotzdem würde ich mich über Verbesserungsvorschläge freuen.

Vielen Dank
Eure Made
Angehängte Dateien:
Gast #6097947
Lesenswert?

Der Rechnungsteil um den es geht:
1
int32_t BMP_180_Temperatur_Rechnen(int32_t UT, uint16_t AC5, uint16_t AC6, int16_t MC, int16_t MD)
2
// Rechnet Temperatur aus
3
// Eingabeparameter:            UT, AC5, AC6, MC, MD
4
// Rückgabewert:                T  
5
{
6
  int64_t X1, X2, B5, t;
7
  int32_t  T;
8
  X1 = (((UT - AC6) * AC5) / 32768);
9
  X2 = ((MC * 2048) / (X1 + MD));
10
  B5 = (X1 + X2);
11
  t = ((B5 + 8) / 16);
12
  T=t;
13
  return T;   // Temperatur in 0,1°C
14
}
1
int32_t BMP_180_Luftdruck_Rechnen(int32_t UP, int32_t UT ,int16_t AC1, int16_t AC2, int16_t AC3,uint16_t AC4, uint16_t AC5,uint16_t AC6, int16_t B1, int16_t B2, int16_t MB, int16_t MC, int16_t MD)
2
// Rechnet Temperatur aus
3
// Eingabeparameter:            UT, AC5, AC6, MC, MD
4
// Rückgabewert:                T  
5
{
6
  int64_t B5, B6, X1, X2, X3, B3, p;
7
  uint32_t B4, B7;
8
  X1 = ((UT - AC6) * AC5) >> 15;// / 32768;
9
  X2 = MC * 2048 / (X1 + MD);
10
  B5 = X1 + X2;
11

12
  B6 = B5 - 4000;
13
  X1 = (B2 * ((B6 * B6) / 4096)) / 2048;
14
  X2 = (AC2 * B6) / 2048;
15
  X3 = X1 + X2;
16
  B3 = (((AC1 * 4 + X3)<<oss)+2)/4;
17

18
  X1 = (AC3 * B6) / 8192;
19
  X2 = (B1 * (B6 * B6 / 4096)) / 65536;
20
  X3 = ((X1 + X2) + 2) / 4;
21
  B4 = AC4 * (X3 + 32768) / 32768;
22
  B7 = (UP - B3) * (50000 >> oss);
23
  if (B7 < 0x80000000)
24
  {
25
    p = (B7 * 2) / B4;
26
  }
27
  else
28
  {
29
    p = (B7 / B4) * 2;
30
  }
31
  X1 = (p / 256) * (p / 256);
32
  X1 = (X1 * 3038) / 65536;
33
  X2 = (-7357 * p) / 65536;
34
  p = p + (X1 + X2 + 3791) / 16;
35

36
  return p;   // Luftdruck in Pa
37
}
Gast #6097992
Lesenswert?

Moin,


1. Das ist kein C#. Das ist einfach nur C.

2. Du solltest Variablen ordentlich benennen. Z.Bsp. X2 als Name geht 
einfach gar nicht. Wer soll denn da durchblicken.

3. Du hast ein haufen Wiederholungen drinnen. Du solltest mal 
nachforschen, wie das besser geht.

4. Die BMP_180_EPromData_Lesen() hat viel zu viele Parameter. Die 
solltest du einkürzen.

5. Warum gibt die BMP_180_EPromData_Lesen() Daten auf der Seriellen aus. 
Das gehört da nicht rein. Mach am besten eine getrennte Funktion dafür.

6. Warum sollte jemand so was veröffentlichen wollen. Damit schädigt man 
nur seiner Reputation :)

Das ist nur ein paar Sachen, die mir auf die schnelle Aufgefallen sind.

Grüße
Gast #6097994
Lesenswert?

nicht"Gast" schrieb:
> 2. Du solltest Variablen ordentlich benennen. Z.Bsp. X2 als Name geht
> einfach gar nicht. Wer soll denn da durchblicken.

Macht eher keinen Sinn, weil das fast eins zu eins der Code von Bosch 
ist (siehe Datenblatt). Da wirds eher unübersichtlicher, wenn du dir 
noch eigene Namen einfallen lässt.
Gast #6098006
Lesenswert?

donvido schrieb:
> Macht eher keinen Sinn, weil das fast eins zu eins der Code von Bosch
> ist (siehe Datenblatt). Da wirds eher unübersichtlicher, wenn du dir
> noch eigene Namen einfallen lässt.

Öhm, nö

Nur weil das Datenblatt ebenso kacke ist, heißt es ja nicht, das der 
Code auch so schlimm sein muss. Zumal der geneigte Leser ja gewöhnlich 
nicht das Datenblatt zur Hand hat bzw es beim Lesen vom Code nicht 
brauchen sollte.

Außerdem scheinst du die Fomeln selber nicht zu verstehen. Sonst würde 
es dir keine Schwierigkeiten bereiten vernünftige Namen zu vergeben.

Grüße
#6099025
Lesenswert?

Der Code ist grauenhaft. Da sind haufenweise Codewiederholungen drin, 
das macht es unnötig unleserlich.
Z.B. aus
1
    while (bit_is_clear(UCSR0A,5)) {}         // UCSR0A warten bis gesendet wurde
2
    UDR0 = 48;                                // UDR0 Zahl senden
usw. macht man eine Unterfunktion:
1
void uputchar(char c)
2
  while (bit_is_clear(UCSR0A,5));
3
  UDR0 = c;
4
}
5
// ...
6
uputchar('0');
Dann kann man auch später ganz einfach die Ausgabe auf UART mit 
Interrupt und FIFO verbessern oder auf ein LCD umleiten.

Ebenso diese Wiederholungen:
1
        *AC1 = (TWIM_ReadAck () << 8);
2
        *AC1 += TWIM_ReadAck ();
3
    UART_Sende_Zahl(*AC1);
4
    UART_Sende_Tab();
Das kann man auch sehr schön modularisieren:
1
uint16_t read_twi_u16(void)
2
{
3
  uint16_t val = TWIM_ReadAck() << 8;
4
  return val | TWIM_ReadAck();
5
}
6

7
void usend_val_tab(unit16_t val)
8
{
9
  char buf[10];
10
  sprintf(buf, "%u\t", val);
11
  uputs(buf);
12
}
13
//..
14
  usend_val_tab(*AC1 = read_twi_u16());
15
  usend_val_tab(*AC2 = read_twi_u16());
16
// usw.

Vorzugsweise macht man aus allen ähnlichen Sequenzen, die >=2 mal 
auftreten, eine Unterfunktion.
Code sollte immer so kompakt wie möglich sein. Niemand möchte ähnliche 
Sequenzen wieder und immer wieder lesen müssen. Das erschwert nur das 
Verstehen der eigentlichen Funktion.

Und warum machst Du die Zahlenausgabe zu Fuß und nimmst nicht sprintf()?
Gast #6099034
Lesenswert?

Max M. schrieb:
> Es macht einfach keinen Sinn sich neue Variablennamen auszudenken wenn
> der Hintergrund eine komplexe Formel aus dem Datenblatt ist.

Mittlerweile habe ich mir auch mal aus Neugier das komplette Datenblatt 
angeschaut.

So einen Mist hab ich schon lange nicht mehr als Datenblatt gesehen. 
Keine Erklärungen, die Kalibrierwerte nur als Kürzel. Die Formeln nicht 
erklärt und mit Magic Numbers versehen.

Da kann ich verstehen, dass der TE das einfach kopiert hat.
#6099081
Lesenswert?

nicht"Gast" schrieb:
> So einen Mist hab ich schon lange nicht mehr als Datenblatt gesehen.
> Keine Erklärungen, die Kalibrierwerte nur als Kürzel. Die Formeln nicht
> erklärt und mit Magic Numbers versehen.

Das ist eine Formel welche die Kalibrierwerte nutzt um echte Daten aus 
dem Sensor zu erhalten. Um die Formel zu verstehen müsste man also die 
internas des Sensors kennen.

> Da kann ich verstehen, dass der TE das einfach kopiert hat.

Die Formel selbst soll man ja auch einfach kopieren, man muss die aber 
halt schon auf seine Programmiersprache anpassen. Und die muss man dafür 
halt kennen. Nicht den Sinn der Formel.
Gast #6099089
Lesenswert?

Cyblord -. schrieb:
> Das ist eine Formel welche die Kalibrierwerte nutzt um echte Daten aus
> dem Sensor zu erhalten. Um die Formel zu verstehen müsste man also die
> internas des Sensors kennen.


Na ja, aber die Kalibrierwerte einem so hinzurotzen ist schon ziemlich 
mies. Wenn man die Namen vernünftig gewählt hätte und den Magic Numbers 
auch aussagekräftige Namen gegeben hätte und noch ein paar Kommentare 
zur Berechnung hinterlassen hätte, wäre schon viel erreicht. So ist das 
einfach nur Faul vom Dokumenteur.

(ganz schön viele 'hätte' im Text).

Ändert nicht viel dran, dass das Datenblatt Rotz ist und ein Beispiel, 
wie man es nicht machen sollte. Andere Hersteller bekommen das deutlich 
besser hin.
Gast #6099092
Lesenswert?

Nachtrag.

Eine vernünftige Vorgehensweise wäre natürlich gewesen, die Kalibrierung 
intern zu machen. Einen Prozessor haben die ja sicherlich eh schon 
drauf, nachdem die ja ADC und I2C und Eeprom drauf haben.

Aber das ist eine andere Diskussion und auch nicht Zielführend.
Gast #6099094
Lesenswert?

nicht"Gast" schrieb:
> Wenn man die Namen vernünftig gewählt hätte und den Magic Numbers
> auch aussagekräftige Namen gegeben hätte und noch ein paar Kommentare
> zur Berechnung hinterlassen hätte, wäre schon viel erreicht. So ist das
> einfach nur Faul vom Dokumenteur.

Wenns nun aber einfach nur Koeffizienten eines Polynoms sind um die 
Nichtlinearität des Sensors zu kompensieren, dann kann man halt entweder 
kurze Bezeichner dafür verwenden, oder die Formel über 3 Seiten 
vollkommen unübersichtlich präsentieren.
In der Schule wird doch in der Regel auch nur mit einzelnen Buchstaben 
gerechnet und nicht mit ganzen Wörtern ;).
(Firma: Trier) #6104947
Lesenswert?

Danke für all die Antworten.

Ich muss mich für meine Programmierung entschuldigen.
Außerdem habe ich eine neue Version, welche das Datentypenproblem löst.
Nicht schön aber funktioniert.

Kommentare kommen erst am Ende bei Abgabe des Projekt.

Vielen Dank für die Info mit dem Datenblatt vom BMP280.
Werde ich mir dann mal durchlesen.

Druck und Temperatur bekomme ich raus (sind geprüft).
Aber die Höhe kann ich so nicht berechnen:
1
/*
2
  pi = p;
3
  H = 44330.0*(1.0-(pi/101325.0)^(1.0/5.255));
4
  Hi = H*1000;
5
  char AUSGABE_H[] = "Hoehe :";
6
  UART_Sende_Text (AUSGABE_H);
7
  UART_Sende_Tab();
8
  UART_Sende_Zahl(H);
9
*/

Hoch Float-Typen kann C nicht.
Also auch keine x-te Wurzeln.
Es gibt zwar Bibliotheken und Algorithmen aber das Problem wollte ich 
simpel lösen.


Ich bin Anfänger im Programmieren also verzeiht mir meine Fehler aber 
weist mich auch bitte darauf hin.

Vielen Dank
Holzmade
Angehängte Dateien:
Gast #6105097
Lesenswert?

Der ^ Operator ist in C, C++ und C# der bitweise XOR Operator, also 
macht er nicht das was du erwartest.
Nachdem du die avr-libc verwendest, brauchst du nur math.h inkludieren 
und dann die Funktion pow() nutzen. Das ist der einfachste Weg. Da 
potenzieren für eine CPU/Microkontroller nicht wirkloch so einfach ist 
(schon gar nicht bei floats) gibt es dafür kein Sprachfeature, sondern 
nur plattformabhängige Implementierungen als Funktion.

Und warum schreibst du C++ code, wenn dein Projekt C# sein soll?
Gast #6105118
Lesenswert?

Und noch ein par Verbesserungen:
1.) Inkludiere cstdint für uint8_t und co., dass es so funktioniert ist 
Glück
2.) Mach alle Variablen, die sich nie ändern, und beim Compilieren schon 
einen bekannten Inhalt haben constexpr, dann kann der Compiler besser 
optimieren. Das sind bei dir alle globalen Variablen. Wenn du aus 
welchen Gründen auch immer einen C-Compiler (dann passt der Dateiname 
mit *.cpp aber nicht) oder eine C++ Version die älter als C++14 
verwendest, funktioniert das nicht, und du solltest sie zumindest const 
machen.
Gast #6105173
Lesenswert?

nicht"Gast" schrieb:
> 2. Du solltest Variablen ordentlich benennen. Z.Bsp. X2 als Name geht
> einfach gar nicht. Wer soll denn da durchblicken.

Soll die Variable vielleicht besser 
int64_Zwischenwert_BoschAlgorithmus_Berechnung_Luftdruck_X2 heißen?

Da es sich um lokale Variablen in der Umrechnungsroutine handelt, ist es 
doch völlig in Ordnung, die Namen aus dem Algorithmus genau wie im 
Datenblatt zu verwenden.
(Firma: Trier) #6106448
Lesenswert?

Hallo

Danke für die Hilfe mit dem Höhenproblem.
Ich habe mir die Funktionen der math.h angeschaut aber habe keine 
Funktion gefunden um eine x-te Wurzel zu ziehen.
Wenn ^ die XOR Funktion ist muss ich diese Berechnung outsourcen.
Könnte das mit einem Raspi als Display verbinden.
Dann kann ich die Umrechnung in Python schreiben.
Die Funktion dort habe ich mir schon angeschaut.

Ich habe zur Höhenberechnung 2 Formeln gefunden.
Die Internationale Höhenformel (Problem: 5,255te-Wurzel ziehen)
Die Barometrische Höhenformel (ungenauer und e^x Funktion)

Was ist außerdem cstdint?
Eine Bibliothek?

Vielen Dank
Ihr helft neuen Programmierern sehr :)
Angehängte Dateien:

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