Forum: Mikrocontroller und Digitale Elektronik Bosch BME680 Luftgütesensor, Verständnisproblem


von Stephan (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Anhand des unter

https://github.com/BoschSensortec/BME680_driver

geliefeten Codes von Bosch versuche ich den o.g. Sensor zum Leben zu 
erwecken.

Die Datei README.md liefert eine Schritt-für-Schritt-Anleitung, dessen 
Schritte mir leider zu groß sind.

Beispiel:
1
## Usage guide
2
### Initializing the sensor
3
To initialize the sensor, you will first need to create a device structure. You can do this by creating an instance of the structure bme680_dev. Then go on to fill in the various parameters as shown below
4
5
#### Example for I2C
6
7
  struct bme680_dev gas_sensor;
8
  gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY;
9
  gas_sensor.intf = BME680_I2C_INTF;
10
  gas_sensor.read = user_i2c_read;         <-----------!!!
11
  gas_sensor.write = user_i2c_write;       <-----------!!!
12
  gas_sensor.delay_ms = user_delay_ms;     <-----------!!!
13
  int8_t rslt = BME680_OK;
14
  rslt = bme680_init(&gas_sensor);

Außerdem:
1
### Reading sensor data
2
#### Example for reading all sensor data
3
4
  struct bme680_field_data data;
5
  while(1) 
6
  {
7
    rslt = bme680_get_sensor_data(&data, &gas_sensor);
8
    printf("T: %.2f degC, P: %.2f hPa, H %.2f %%rH ", data.temperature / 100.0f,
9
      data.pressure / 100.0f, data.humidity / 1000.0f );
10
    /* Avoid using measurements from an unstable heating setup */
11
    if(data.status & BME680_GASM_VALID_MSK)
12
      printf(", G: %d ohms", data.gas_resistance);
13
    
14
    printf("\r\n");
15
  }

Und..
1
### Templates for function pointers
2
3
void user_delay_ms(uint32_t period)
4
{
5
    /*
6
     * Return control or wait,
7
     * for a period amount of milliseconds
8
     */
9
}
10
11
12
int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
13
{
14
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
15
16
    /*
17
     * The parameter dev_id can be used as a variable to store the I2C address of the device
18
     */
19
20
    /*
21
     * Data on the bus should be like
22
     * |------------+---------------------|
23
     * | I2C action | Data                |
24
     * |------------+---------------------|
25
     * | Start      | -                   |
26
     * | Write      | (reg_addr)          |
27
     * | Stop       | -                   |
28
     * | Start      | -                   |
29
     * | Read       | (reg_data[0])       |
30
     * | Read       | (....)              |
31
     * | Read       | (reg_data[len - 1]) |
32
     * | Stop       | -                   |
33
     * |------------+---------------------|
34
     */
35
36
    return rslt;
37
}
38
39
int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
40
{
41
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
42
43
    /*
44
     * The parameter dev_id can be used as a variable to store the I2C address of the device
45
     */
46
47
    /*
48
     * Data on the bus should be like
49
     * |------------+---------------------|
50
     * | I2C action | Data                |
51
     * |------------+---------------------|
52
     * | Start      | -                   |
53
     * | Write      | (reg_addr)          |
54
     * | Write      | (reg_data[0])       |
55
     * | Write      | (....)              |
56
     * | Write      | (reg_data[len - 1]) |
57
     * | Stop       | -                   |
58
     * |------------+---------------------|
59
     */
60
61
    return rslt;
62
}

Die mit "!" gekennzeichneten Zeilen verstehe ich nicht. Ich vermute, der 
Anwender soll seinem Code entsprechend I2C-Anweisungen durchführen. Aber 
wie nur?

von Sven G. (s705081)


Lesenswert?

Die von Dir angesprochen Zeilen musst du selber Implementieren. Da dies, 
von dem von dir verwendeten Micocontroller abhängig ist, macht es keinen 
Sinn Source Code anzugeben.

Viele Grüße

von Stephan (Gast)


Lesenswert?

Sven G. schrieb:
> Die von Dir angesprochen Zeilen musst du selber Implementieren.

Das hab´ich mir schon gedacht.. Nur, im ersten Abschnitt INIT, wird die 
Struktur gas_sensor.read mittels Funktion user_i2c_read; befüllt.

Warum ist denn dort nicht die Parameterliste angegeben?
dev_id,  reg_addr,  *reg_data,  len angegeben?

von Seibert (Gast)


Lesenswert?

Bosch wird da wohl kaum Murks geschrieben haben aber ein Funktionsaufruf 
sieht anders aus

von trag einfü (Gast)


Lesenswert?

Stephan schrieb:
> Sven G. schrieb:
>> Die von Dir angesprochen Zeilen musst du selber Implementieren.
>
> Das hab´ich mir schon gedacht.. Nur, im ersten Abschnitt INIT, wird die
> Struktur gas_sensor.read mittels Funktion user_i2c_read; befüllt.
>

NEIN!
Da wird ein Ptr auf eine Funktion zugewiesen!

> Warum ist denn dort nicht die Parameterliste angegeben?
> dev_id,  reg_addr,  *reg_data,  len angegeben?

Weil es KEIN Funktionsaufruf ist!

von Seibert (Gast)


Lesenswert?

trag einfü schrieb:
> NEIN!
> Da wird ein Ptr auf eine Funktion zugewiesen!

Magst Du das bitte erläutern?

von Axel S. (a-za-z0-9)


Lesenswert?

Stephan schrieb:
> Die mit "!" gekennzeichneten Zeilen verstehe ich nicht. Ich vermute, der
> Anwender soll seinem Code entsprechend I2C-Anweisungen durchführen.

Bei den gekennzeichneten Stellen mußt du Zeiger auf deine Funktionen 
zum Zugriff auf I2C (oder SPI) und für eine Delay-Funktion einfügen. 
Falls du das Konzept function pointer noch nicht kennst, ist jetzt 
genau der richtige Zeitpunkt, das nachzulesen.

Weiter unten sind leere Funktionsrümpfe für diese Funktionen gezeigt, 
aus denen du ersehen kannst, welche Parameter der Code von Bosch 
übergibt, wenn er deine Funktionen aufruft und welches Ergebnis er 
jeweils erwartet.

In bme680_defs.h findest du auch die typedefs für die function pointer 
und Makros für die erwarteten Rückgabewerte (z.B. BME680_OK, wenn alles 
glatt gelaufen ist).

von Stephan (Gast)


Lesenswert?

Vielen Dank Axel. Über Funktionspointer bin ich tatsächlich noch nicht 
gestolpert. Und, ich muss gestehen, dass mich die Lektüre des Artikels 
unter https://www.mikrocontroller.net/articles/Funktionszeiger_in_C nur 
mehr verwirrt hat. Zitat: "Um Menüs oder ähnliche Dinge aufzubauen, ist 
es oft praktisch, ein Array von Funktionszeigern zu definieren." Wo ist 
da der zusammenhang?!
Ich vermute stark, ich muss das u.g. Template mit Leben füllen. Vermute 
ferner, dass ich eine Funktion implementieren soll, dessen Rückgabewert 
der BME-Antwort gemäß Parameterliste entspricht. Nur warum ist der 
Rückgabewert ein int8_t?


[c]
int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t 
*reg_data, uint16_t len)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

    /*
     * The parameter dev_id can be used as a variable to store the I2C 
address of the device
     */

    /*
     * Data on the bus should be like
     * |------------+---------------------|
     * | I2C action | Data                |
     * |------------+---------------------|
     * | Start      | -                   |
     * | Write      | (reg_addr)          |
     * | Stop       | -                   |
     * | Start      | -                   |
     * | Read       | (reg_data[0])       |
     * | Read       | (....)              |
     * | Read       | (reg_data[len - 1]) |
     * | Stop       | -                   |
     * |------------+---------------------|
     */

    return rslt;
}
[/]

:(

von Axel S. (a-za-z0-9)


Lesenswert?

Stephan schrieb:
> Vielen Dank Axel. Über Funktionspointer bin ich tatsächlich noch nicht
> gestolpert. Und, ich muss gestehen, dass mich die Lektüre des Artikels
> unter https://www.mikrocontroller.net/articles/Funktionszeiger_in_C nur
> mehr verwirrt hat. Zitat: "Um Menüs oder ähnliche Dinge aufzubauen, ist
> es oft praktisch, ein Array von Funktionszeigern zu definieren." Wo ist
> da der zusammenhang?!

Dieser Zusammenhang ist in der Tat nicht zwingend. Die hauptsächliche 
Verwendung von Funktionspointern sind Callback-Funktionen 
(https://de.wikipedia.org/wiki/Rückruffunktion)

Ganz konkret füllst du für die Treiber-Software von Bosch eine Struktur 
mit Funktionszeigern und der Treiber ruft deine Funktionen immer dann 
auf (Callback) wenn er es für nötig befindet. Der Vorteil besteht an 
dieser Stelle darin, daß der exakt gleiche Code von Bosch verwendet 
werden kann, um den Sensor abzufragen, vollkommen egal ob der Sensor per 
I²C oder SPI angebunden ist, wie das Interface konkret aufgebaut ist und 
sogar, ob es vielleicht mehrere solche Sensoren am gleichen Bus gibt.

Und das einfach nur, indem du ein paar passende Funktionen für die 
low-Level Kommunikation mit dem Sensor schreibst und Zeiger auf (im 
Quelltext praktisch: die Namen für) diese Funktionen in eine Struktur 
füllst.

> Ich vermute stark, ich muss das u.g. Template mit Leben füllen. Vermute
> ferner, dass ich eine Funktion implementieren soll, dessen Rückgabewert
> der BME-Antwort gemäß Parameterliste entspricht. Nur warum ist der
> Rückgabewert ein int8_t?

Das ist der kleinste Wert, den eine Funktion in C zurückgeben kann. Und 
tatsächlich erwartet die Bosch Software ja auch nur entweder 0 oder 
einen von 0 verschiedenen Wert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.