2020
HOME

Umweltdaten auf dem Raspberry Pi mit Shell
I2C in LibreOffice Basic
BME280-Sensor mit Shell und Bash-Kommandos auslesen - ohne Python

Sensor BME280Der Bosch-Environment-Sensor BME280 kann verschiedene Umgebungsgrößen erfassen. Der auf einem kleinen Breakout untergebrachte, winzige Sensor mit dem Loch im Metallgehäuse liefert z. B. über eine I2C-Verbindung die aktuellen Werte von

  • Temperatur
  • Luftdruck
  • Luftfeuchte,

ist also Thermometer, Barometer und Hygrometer auf kleinstem Raum.


In einem anderen Beitrag ist beschrieben, wie dieser Sensor mittels ESP8266BASIC ansprechbar ist und wie dort die ziemlich komplizierte Berechnung gerade noch so eben realisiert werden kann. An dieser Stelle geht es darum das dort gezeigte Verfahren auf ein anderes Basic zu übertragen. Bedingung dazu ist, dass das Basic auf einer Hardware läuft, die einen I2C-Bus besitzt bzw. entsprechende Anschlüsse aufweist. Zusätzlich muss das Basic in der Lage sein mit diesem Gerät über I2C-Kommandos kommunizieren. Beide Bedingungen sind erfüllt bei Verwendung von

Der übliche Anwender eines Raspberry Pi programmiert in C, Python oder der Bash. Wer das nicht möchte, kann den hier gezeigten Weg ausprobieren. Für den Terminalprogrammierer gilt hier der Slogan "Bitte nicht nachmachen!". Tatsächlich ruft Basic mit dem Shell-Befehl Dinge über die Kommandozeile auf, schreibt das Ergebnis in eine Datei und ließt das Resultat aus der Datei, um es dann anzuzeigen oder anderwärtig zu benutzen. Das ist nicht elegant, funktioniert jedoch für schnelle Tests.

Der Raspberry Pi Zero und all die anderen Vertreter seiner Art verfügt über entsprechende Schnittstellen, die jedoch als Voreinstellung meist deaktiviert sind. Im Desktopmenü gibt es die Raspian-Einstellungen, womit diese Einstellungen änderbar sind. LibreOffice Calc verfügt über ein Menüpunkt Extras worunter die Basic-Umgebung aufrufbar ist. Wie in Office üblich, müssen sogenannte Makros in den Optionen unter Sicherheit erlaubt sein.



Anschluss und erster Kontakt Testkommunikation


Der Sensor wird über das I2C-Protokoll angesprochen, seine Adresse lautet 76HEX. Die Kommunikation läuft also über die Anschlüsse SCL (Serial Clock) und SDA (Serial Data). Die Versorgungsspannung (Vcc) 3,3 Volt und die Masse (Gnd) kommen vom Raspberry Pi.

RASPBERRY

BME280

1 VCC (3,3 Volt)

VCC

6 GND

GND

5 (GPIO03)

SCL

3 (GPIO02)

SDA

Der Sensor kann anhand seiner ID identifiziert werden. Im Register bzw. in der Speicherstelle D0HEX liegt die Zahl, die den BME280 vom BMP280 (ohne Hygrometer) unterscheidet. Um diesen Wert zu erhalten sind erste Schritte in I2C erforderlich. An den zwei Leitungen soll Teilnehmer 0x76 angesprochen -, und dazu bewegt werden das Byte von Adresse 0xD0 zu senden. In LibreOffice Basic sieht das so aus:

Sub BMEid 
 Shell("bash -c 'i2cget -y 1 0x76 0xd0 > hi'") 
 Wait 200 
 Print ReadLine("hi")
End Sub
'-----------------------------------------------
Function ReadLine(f) 'from file f
 n = Freefile()
 'on error resume next 
 Open f For input As #n
 Line Input #n,A$
 Close #n
 readline = A$
End Function

Ein Raspberry Pi kennt i2c-Kommandos für die Konsole, da diese Routinen bei der Installation vom Betriebsystem Raspian bereits vorhanden sind. Der Shell-Befehl in Basic ruft mit i2cget die Daten aus Register D0 ab und die Ausgabe wird in eine Textdatei hi umgeleitet. Diese Textdatei enthält eine Zeile Text, die sonst in der Konsole angezeigt würde. Die Funktion ReadlLine ließt diese Zeile in die Variable A$ und liefert das Ergebnis an den Aufrufer, was in diesem Falll die Print-Ausgabe ist. LibreOffice Basic zeigt solche Ausgaben in einer Art MessageBox an, die es auch erlaubt das laufende Programm zu beenden.

0x60

Das Ergebnis zeigt, dass bis hier hin alles richtig angeschlossen ist und funktioniert. Es ist ein BME280 vorhanden.

Rohdaten auslesen Messwerte holen


Die Messwerte der Sensoren liegen laut Datenblatt im Speicherbereich (Memory map) ab Adresse F7HEX des BME280. Die insgesamt 8 Bytes beinhalten Angaben zu Druck, Temperatur und Feuchtigkeit im Rohformat. Die Umrechnung dieser Rohdaten in Messwerte erfordert einigen Aufwand und ist weiter unten beschrieben.

Im Urzustand liefern diese Speicherplätze die Werte 128, 0, 0, 128, 0, 0, 128 ,0. Die 128 zeigt an, dass der betreffende Sensor nicht aktiv ist. Die Aktivierung von Druck- und Temperatursensor erfolgt über den Inhalt von Register bzw. Adresse F4HEX. Das Hygrometer bleibt zunächst aus, da es an anderer Stelle aktiviert werden muss.

Mit dem Bitmuster 00100111 bzw 32+7 in Register 0xF4 ändern sich nun die Rohdaten der Analog/Digitalwandler für Temperatur und Druck im Speicherbereich ab 0xF7. LibreOffice Basic liest mit BMEdata die 8 Bytes Rohdaten in das globale Array b von Calc nach dem einmaligen Aufruf von BMEstart.

Sub BMEstart 'Mode 
 i2cSET("0x76","0xF4","0x27") ' Temp & Press 
 Wait 200      
End Sub

Sub BMEdata 
 mem = hextoint("F7")
 For i = 0 To 7 
  v = i2cget("0x76",inttohex(mem)) 
  b(i) = v 
  mem = mem + 1
 Next i
End Sub

BME280 Einzelmessung für Temp und Druck mit Auslesen aller 8 Bytes in globalem Array b()

74, 56, 0, 130, 127, 0, 128, 0

Die Werte sind jeweils leicht unterschiedlich mit Ausnahme der letzten beiden Bytes, die dem Hygrometer zugeordnet sind, welches noch deaktiviert ist. Eine Messung von Temperatur und Druck findet jedoch offensichtlich statt.


Kalibrierdaten auslesen Exemplarstreuungen


Der Bosch-Sensor wird mit Kalibrierdaten ausgeliefert, die bei der Herstellung und der Qualitätskontrolle erfasst werden. Diese Daten sind für jedes Exemplar unterschiedlich. Die Berechnung der tatsächlichen Messwerte muss diese Kalibrierdaten berücksichtigen, damit die Messdaten auch stimmen. Im Datenblatt des BME280 gibt Bosch an, dass die Kalibrierdaten für die Temperatur und den Druck ab Adresse 0x88 in 24 Bytes abgelegt worden sind. Die ersten 6 Bytes sind Kalibrierdaten zum Temperatursensor, die restlichen 18 Bytes werden zur Berechnung des Luftdrucks herangezogen. Entsprechende Hygrometerdaten stehen an 0xA1 und ab 0xE1. Diese Kalibrierdaten und die Einrechnung erfolgt teilweise über vorzeichenbehaftete 64Bit-Integerwerte, die in BASIC normalerweise als Variablentyp nicht vorkommen. Ein vorzeichenloser ganzzahliger 16Bit-Wert, der in zwei Bytes abgelegt wird, erhält man üblicherweise mit der Rechnung

U16 = 256 * Highbyte + Lowbyte

Vorzeichenbehaftete ganzzahlige 16Bit-Werte liegen vor wenn der 16Bit-Zahlenbereich 0 bis 65535 so geteilt wird, dass auch negative Zahlen möglich sind. Der Bereich wäre dann -32767 bis +32768. Eine 65535 wäre dann eine -1. Da LibreOffice Basic wie die meisten anderen BASIC-Varianten nur Fließpunkzahlen als Typ kennen, muss entsprechend umgerechnet werden. Mit

if x > 32767 then x = x – 65536

erhält x den entsprechend negativen Wert. In C wäre dieser Typ ein int, im Gegensatz zum unsigned int. Oft wird der Typ um deklariert, damit auf jedem System klar wird, wie viele Bits beteiligt sind (z. B. uint32). Die Reihenfolge der Bytes kann unterschiedlich sein. Im BME280 ist die Reihenfolge Lowbyte (LSB), Highbyte (MSB)..


Gesamtlisting mit Berechnungen


Mit diesem Ausführungen und dem Datenblatt des BME280 sollte der folgende Abschnitt für LibreOffice Basic deutlich werden. Im Kasten steht das komplette Listing zur Anzeige von Druck und Temperatur. Das Gesamtlisting beginnt hier mit der Deklaration der verwendeten globalen Variablen in einem original Syntax-Highlighting, wie es im Editor von LibreOffice dargestellt ist.

Mit dem Test als letzte Routine erfolgt die Ausgabe der Daten in einem Tabellenblatt mittels Aufruf der Cell-Routine.

REM ***** LibreOffice BASIC *****

Option base 0

Dim c(24),b(8),h(7),t_fine
Dim dig_T1,dig_T2,dig_T3
Dim dig_P1,dig_P2,dig_P3,dig_P4,dig_P5,dig_P6,dig_P7,dig_P8,dig_P9
Dim dig_H1,dig_H2,dig_H3,dig_H4,dig_H5,dig_H6,dig_H7

'-----------------------------------------------
Sub i2cSET(ad,rg,vl)
 Shell "bash -c 'i2cset -y 1 "+ad+" "+rg+" "+vl+" b'" 
 Wait 100 ' Je nach Hardware
End Sub
'-----------------------------------------------
Function i2cGET(ad,rg)
 Shell "bash -c 'i2cget -y 1 "+ad+" "+rg+" > hi'"
 Wait 300 ' Je nach Hardware
 i2cget = hextoint(Mid(readline("hi"),3,2))
End Function
'-----------------------------------------------
Function readline(f) 'from file f
 n = Freefile()
 'on error resume next 
 Open f For input As #n
 Line Input #n,s$
 Close #n
 readline = s$
End Function
'-----------------------------------------------
Function hextoint(z)
 a = "0123456789ABCDEF"
 h = Instr(a,Mid(z,1,1))-1
 l = Instr(a,Mid(z,2,1))-1
 hextoint = 16*h + l
End Function
'-----------------------------------------------
Function inttohex(i)'0xFE
 a = "": If i < 16 Then a = a + "0"
 a = a + hex$(i)
 inttohex = "0x" + a
End Function
'-----------------------------------------------
Sub BMEid 
 Shell("bash -c 'i2cget -y 1 0x76 0xd0 > hi'") 
 Wait 200
 Print readline("hi")
End Sub
'-----------------------------------------------
Sub BMEstart 'Mode
 i2cSET("0x76","0xF4","0x27") ' Temp & Press
 Wait 200
 i2cSET("0x76","0xF2","0x05") ' Humidity
End Sub

Sub BMEcal
 mem = hextoint("88")
 For i = 0 To 23
  v = i2cget("0x76",inttohex(mem))
  cell (i+1,1,v)
  c(i) = v
  mem = mem + 1
 Next i
 dig_T1 = c(0)  +c(1) * 256
 dig_T2 = c(2)  +c(3) * 256
 dig_T3 = c(4)  +c(5) * 256
 dig_P1 = c(6)  + 256 * c(7)
 dig_P2 = c(8)  + 256 * c(9)
 dig_P3 = c(10) + 256 * c(11)
 dig_P4 = c(12) + 256 * c(13)
 dig_P5 = c(14) + 256 * c(15)
 dig_P6 = c(16) + 256 * c(17)
 dig_P7 = c(18) + 256 * c(19)
 dig_P8 = c(20) + 256 * c(21)
 dig_P9 = c(22) + 256 * c(23)
 
 'Signed!
 If dig_T2 > 32767 Then dig_T2 = dig_T2 - 65536
 If dig_T3 > 32767 Then dig_T3 = dig_T3 - 65536
 If dig_P2 > 32767 Then dig_P2 = dig_P2 - 65536
 If dig_P3 > 32767 Then dig_P3 = dig_P3 - 65536
 If dig_P4 > 32767 Then dig_P4 = dig_P4 - 65536
 If dig_P5 > 32767 Then dig_P5 = dig_P5 - 65536
 If dig_P6 > 32767 Then dig_P6 = dig_P6 - 65536
 If dig_P7 > 32767 Then dig_P7 = dig_P7 - 65536
 If dig_P8 > 32767 Then dig_P8 = dig_P8 - 65536
 If dig_P9 > 32767 Then dig_P9 = dig_P9 - 65536
 
 'HUMIDITY
 dig_H1 = i2cget("0x76","0xA1")
 mem = hextoint("E1")
 For i = 0 To 6
  v = i2cget("0x76",inttohex(mem))
  h(i) = v
  mem = mem + 1
  cell (10+i,2,h(i))
 Next i
 dig_H2 = h(0) + (h(1) * 256) 'int16
 dig_H3 = h(2) 'uint8
 dig_H4 = h(3) * 16 + (h(4) And 15) 'uint16
 dig_H5 = h(5) * 16 + (h(4) And 240) / 16 'uint16
 dig_H6 = h(6) ' int8
 If dig_H2 > 32767 Then dig_H2 = dig_H2 - 65536
 If dig_H6 > 127 Then dig_H6 = dig_H6 - 256
End Sub

Sub BMEdata
 mem = hextoint("F7")
 For i = 0 To 7
  v = i2cget("0x76",inttohex(mem))
  cell (i + 1,2,v)
  b(i) = v
  mem = mem + 1
 Next i
End Sub

Sub BMEtemp
 'T BERECHNEN
 adc_T = b(3)*65566 + b(4)*256 + b(5)
 adc_T = adc_T/16
 var1 = (adc_T / 16384 - dig_T1 / 1024) * dig_T2 'OK!
 x = adc_T / 131072 - dig_T1/8192
 var2 = (x * x) * dig_T3
 t_fine = var1 + var2
 T = (var1 + var2) / 5120
 cell 1,3,T
End Sub

Sub BMEpress
 'P BERECHNEN 
 adc_p = b(0)*65536+b(1)*256+b(2)
 adc_p = adc_p / 16
 var1 = (t_fine/2) - 64000
 var2 = var1 * var1 * dig_P6 / 32768
 var2 = var2 + var1 * dig_P5 * 2
 var2 = (var2/4)+(dig_P4 * 65536)
 var1 = (dig_P3 * var1 * var1 / 524288 + dig_P2 * var1) / 524288
 var1 = (1 + var1 / 32768)*dig_P1
 p = 1048576 - adc_p
 p = ((p - var2 / 4096) * 6250) / var1
 var1 = dig_P9 * p * p / 2147483648
 var2 = p * dig_P8 / 32768
 p = p + (var1 + var2 + dig_P7) / 16
 press = p/100
 cell 2,3,press
End Sub

Sub test
 cell 1,4,0
 BMEid
 BMEcal
 BMEstart
 For i = 1 To 10
  BMEdata
  BMEtemp
  BMEpress
  cell 1,4,i
  Wait 10000
 Next i
End Sub

Diese Ausführungen sollen zeigen, wie ähnlich die Berechnungen in den verschiedenen Basic-Dialekten sind. Die Ausgabe erfolgt hier in einem Tabellenblatt von LibreOffice Calc mit einer Funktion Cell, die ähnlich der Cells-Methode in VBA reagiert. Der Aufruf Cell 21,2,89 schreibt in die Zeile 21 und Spalte 2 die Zahl 89 als Wert.

Sub Cell(x,y,v) 
 ThisComponent.CurrentController.getActiveSheet()._
  getcellbyposition(y-1,x-1).setvalue(v)
End Sub

Einige Dinge lassen sich in diesem Basic mit dem Shell-Kommando lösen. Eleganz und Geschwindigkeit sieht vermutlich anders aus. Wie ein Zusammenspiel zwischen Basic und Python in LibreOffice auf allen aktuellen Plattformen funktioniert und somit mehr Glanz verbreitet steht demnächst möglicherweise an einer anderen Stelle.


Schon im 1998 in der Erstausgabe erschienenen Messen Steuern Regeln mit Word & Excel war Basic in Office ein Thema. Durch die vertiefende Beschäftigung mit der Referenz zum Basic auf einem WiFi-fähigen Mikrokontroller entstand ein eigenes Buch Messen, Steuern und Regeln mit WiFi und ESP8266-BASIC, da sich ganz neue Perspektiven bei der Umsetzung von Ideen ergaben. Mit LibreOffice Basic und dem OpenSource-Prinzip, ergeben sich insbesondere ab der Version 6 interessante Möglichkeiten der Plattformunabhängigkeit.

Weitere Software
.
Startseite Bücher Software Digital RTV Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt