Raspberry-Pi-Projekt: Differenzdrucksensor SDP6xx

Prof. Jürgen Plate

Raspberry Pi: Differenzdrucksensor SDP6xx

Allgemeines

Ein Differenzdrucksensor von Sensiron ermöglicht den unkomplizierten Aufbau eines Windmessers im Mini-Format, und zwar ohne bewegliche Teile. Neben dem Einsatz als Taschen-Windmesser ergeben sich für den Sensor vielfältige Einsatzbereiche, etwa zur Überwachung von Umwälzanlagen, zur Anzeige des Luftwiderstands eines Filters (Verschmutzung) und so weiter. der Sensor wird über die I2C-Schnittstelle mit dem Raspberry Pi (oder auch einem Arduino) verbunden.

Die SDP600-Serie arbeitet mit 3,3 V Versorgungsspannung. Das Signal ist intern linearisiert und temperaturkompensiert. Der Sensor ist in zwei verschiedenen Gehäuseformen verfügbar, für direktes Anflanschen und für Schlauchanschluss (siehe Datenblatt). Für jedes Gehäuse gibt es dann noch drei unterschiedliche Maximaldruck-Werte: 25, 125 oder 500 Pascal (Pa).

Der elektrische Anschluß erfolgt über vier Anschlußpins.

SignalPin SDP6xxPin GPIO
SDA13
SCL45
VDD31
GND29

Windgeschwindigkeitsmesser

Die beiden Druckanschlußstutzen des Sensors können, wie im folgenden zu sehen, in die Halbschalen eines zerschnittenen Tischtennisballes ragen (bzw. durch kurze Schlauchstücke passend verlängert werden). Die Halbschalen dienen zur Verstärkung des Staudrucks auf der einen sowie der Ausbildung eines Unterdrucks auf der anderen Seite. So lässt sich nicht nur eine Aussage über die Strömungsgeschwindigkeit, sondern auch über deren Richtung (Ausschlags-Maximum) machen.

Zum Kalibrieren des Windgeschwindigkeitmessers genügt es, das Gerät in einen beliebigen Orkan mit einer Windgeschwindigkeit von 100 km/h zu halten und den Messwert zu notieren. Sollte gerade schönes Wetter herrschen, kann man sich auch mit einer kurzen Autofahrt bei Windstille behelfen. Während der Fahrer 100 km/h exakt fährt (Toleranz des Tachos berücksichtigen), hält der Beifahrer(!) das Gerät, gegebenenfalls an einer Verlängerung befestigt, aus dem Fenster und notiert den Messwert.

Andere Varianten der Sensornutzung

Es gibt noch verschiedene andere Möglichkeiten, den Drucksensor zu nutzen, wie die folgenden Bilder zeigen. Das Verfahren ist immer das gleiche: es wird die Druckdifferenz ausgenutzt. Bei Schiffen, Flugzeigen und Fahrzeugen werden für die Über- und Unterdruckseite nur andere konstruktive Massnahmen getroffen. Statt der Halbschalen wie oben, ist hier ein Staudruckrohr im Einsatz.

Zur Messung der Verschmutzung eines Filters wird beidseits des Filters gemessen. Je stärker der Filter verschmutzt ist, desto höher ist der Widerstand, den er der durchströmenden Luft bietet.

Interessant ist auch die Bestimmung der Durchflussmenge in einem Rohr. Damit auch da höhere Druckunterschiede gemessen werden können, wird eine Lochblende in das Rohr eingesetzt. Die Zunahme der Geschwindigkeit an der durch die Blende erzeugten Einschnürungsstelle bewirkt entsprechend der bernoullischen Energiegleichung eine Verringerung des statischen Druckes. Die dabei entstehende Druckdifferenz ist ein Maß für den Durchfluss.

Die wesentlichen Merkmale einer solchen "Normblende" sind eine scharfe Einlaufkante, eine konzentrische Anordnung der Bohrung sowie eine zylindrische Bohrung von definierter Länge.

Als "Volumenstrom" bezeichnet man ein Volumen, welches innerhalb einer bestimmten Zeit fließt. Die SI-Einheit für den Volumenstrom ist somit m3/s bzw. L/s. Der Volumenstrom, der durch eine Blende fließt, wird wie folgt berechnet:

Dabei gilt:
Q: Volumenstrom [m3/s]
α0: Durchflusskoeffizient
A0: Strömungsquerschnitt der Blende [m2]
ρ: Dichte des Fluids in [kg/m3] - bei Luft 1,3 kg/m3
Δp = p1 – p2: Druckdifferenz in [bar]

Software

Jede einzelne Messung erfolgt durch einen separaten Lesevorgang auf dem Bus. Es werden zwei Übertragungssequenzen benötigt, um eine Messung durchzuführen. Zuerst wird das Befehlsbyte 0xF1 (trigger measurement) an den Sensor gesendet und anschließend ein Lesevorgang zum Auslesen der Messung und zum Abrufen der Sensorinfo ausgeführt. Bei Empfang eines Headers mit R/W = 1 erzeugt der Sensor die Hold-Master-Bedingung auf dem Bus bis die Messung abgeschlossen ist. Nach dem Freigeben der Hold-Master-Bedingung kann das Ergebnis in Form zweier aufeinanderfolgender Bytes gelesen werden. Als dritter Wert folgt ein CRC-Byte, das optional ausgewertet werden kann. Der Sensor prüft, ob der Master ein ACK oder NAK sendet und bricht die Übertragung bei NAK ab.

Achtung: Nach dem Einschalten oder einem Reset des Sensors ist der erste gelesene Wert ungültig.

Dementsprechend einfach fallen auch die Programme zum Auslesen des Sensors aus. Es wird ein Kommandobyte geschrieben und dann zwei Datenbytes (MSB, LSB) gelesen. Dies ergibt zunächst einen 16-Bit-Wert: (MSB << 8) + LSB. Da auch negative Werte vorkommen können, handelt es sich um eine Darstellung im Zweierkomplement. Für negative Zahlen ist eine entsprechende Korrektur eingebaut. Je nach Maximalwert des jeweiligen Sensors muss diser Wert durch einen Skalierungsfaktor geteilt werden, um den Differenzdruck in Pascal zu erhalten. Im Programm ist dazu die Konstante MAXPRESSURE anzupassen. Sie kann entsprechend den angebotenen Typen die Werte 25, 125 und 500 annehmen. In der Funktion SDP610_read() wird der entsprechende Divisor bestimmt (die Divisorwerte sind dem Datenblatt entnommen).

Das C-Programm benötigt neben den "Allerweltsbibliotheken" lediglich die für I2C und den Lowlevel-Dateizugriff notwendigen Bibliotheken. Der Programmablauf ist recht übersichtlich. Im Hauptprogramm wird zuerst die I2C-Schnittstelle geöffnet und dann kontinuierlich der Druck ausgelesen und angezeigt.

/*
  Auslesen eines Sensors aus der Sensiron SDP6xx-Reihe.
  ...
  Compile with: gcc -Wall -o sdp610 SDP610.c
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

/* I2C-Adresse des Sensors */
#define SDP610ADDR 0x40

/* Typ des SDP6xx (Maximaldruck): 500, 125, 25 */
#define MAXPRESSURE 125

/* I2C-Bus 1 verwenden */
char *BUS = "/dev/i2c-1";

/*
 * Auslesen des SDP610. Eingabeparameter ist das geoeffnete
 * Devicehandle fuer den I2C-Bus.
 * Als Ergebnis wird der gemessene Differenzdruck zurueckgegeben.
 */
float SDP610_read(int fd)
  {
  float result, scalefactor;  /* Resultat und Skalierungsfaktor */
  unsigned char Reg;          /* fuer I2C-Kommando */
  unsigned char LSB, MSB;     /* Ergebnisbytes vom Sensor */
  int iresult;

  /* Skalierungsfaktor (DP -> Pa) */
  if (MAXPRESSURE == 500)
    scalefactor = 60.0;
  else if (MAXPRESSURE == 125)
    scalefactor = 240.0;
  else if (MAXPRESSURE == 25)
    scalefactor = 1200.0;
  else
    {
    printf("Falsche Druckangabe\n");
    exit(1);
    }
  /* Kommando senden: Trigger differential pressure measurement */
  Reg = 0xF1;
  write(fd, &Reg, 1);
  /* Ergebnis auslesen */
  read(fd, &MSB, 1);
  read(fd, &LSB, 1);
  /* Umrechnen in 16-bit-Wert */
  iresult = (int)(MSB)*256 + LSB;
  /* ggf. Komplement korrigieren */
  if (iresult > 0x7FFF)
    iresult = iresult - 0x10000;
  /* in Pascal umrechnen */
  result = (float)(iresult/scalefactor);
  return result;
  }

int main()
  {
  int device;    /* I2C-Devicehandle */
  float press;   /* Differenzdruck */

  /* I2C-Bus oeffnen */
  if((device = open(BUS, O_RDWR)) < 0)
    {
    printf("Failed to open the i2c bus. \n");
    exit(1);
    }
  /* get I2C device */
  ioctl(device, I2C_SLAVE, SDP610ADDR);

  /* Messung und Ausgabe in Endlosschleife */
  for (;;)
    {
    press = SDP610_read(device);
    printf("Druck: %7.2f\n", press);
    sleep(1);
    }
    
  return 0;
  }

Das Python-Programm gleicht dem C-Programm. Es verwendet die smbus-Bibliothek von Python. Auch hier erfolgen Messung und Ausgabe innerhalb einer Endlosschleife.

 
#!/usr/bin/env python

#  Auslesen eines Sensors aus der Sensiron SDP6xx-Reihe.
#  ...

import smbus
import time

# I2C-Adresse des Sensors
SDP610 = 0x40

# Typ des SDP6xx (Maximaldruck). Erlaubte Werte: 500, 125, 25
MAXPRESSURE = 125

# I2C-Bus 1 verwenden
BUS = 1

# Get I2C bus
bus = smbus.SMBus(BUS)


# Auslesen des SDP610. Eingabeparameter ist das geoeffnete
# Devicehandle fuer den I2C-Bus.
# Als Ergebnis wird der gemessene Differenzdruck zurueckgegeben.
def readDP(addr):
  # Skalierungsfaktor (DP -> Pa)
  if (MAXPRESSURE == 500):
    scalefactor = 60.0
  elif (MAXPRESSURE == 125):
    scalefactor = 240.0
  elif (MAXPRESSURE == 25):
    scalefactor = 1200.0
  else:
    print >> sys.stderr, "Falsche Druckangabe!"
    exit(1)
    
  # Kommando senden: Trigger differential pressure measurement 
  bus.write_byte(addr,0xF1)
  #time.sleep(0.1)
  # Ergebnis auslesen
  MSB = bus.read_byte(addr)
  LSB = bus.read_byte(addr)
  # Umrechnen in 16-bit-Wert
  result = (MSB << 8) + LSB
  # ggf. Komplement korrigieren
  if result > 0x7FFF:
    result = result - 0x10000
  # in Pascal umrechnen  
  result = float(result/scalefactor)
  return result

# Messung und Ausgabe in Endlosschleife 
while True:
  press = readDP(SDP610)
  print("%7x %7.2f" % (SDP610, press))
  time.sleep(1)
Beide Programmquellen können über die Links unten heruntergeladen werden.

I2C-Treiber-Probleme unter Raspbian "Stretch"

Der I2C-Treiber der Raspbian-Version vom Oktober 2017 meldet I/O-Errors beim Zugriff auf manche Sensoren. Meine Theorie ist, dass entweder das I2C-Device "repeated starts" nicht unterstützt oder dass der I2C-Treiber das "Clock Stretching" nicht implementiert hat. Für genauere Analyse fehlte mir die Zeit. Es gibt aber eine Lösung:

  1. Das alte Treibermodul herunterladen: i2c1-bcm2708.dtbo
  2. Die Datei i2c1-bcm2708.dtbo in das Verzeichnis /boot/overlays hineinkopieren. Sollte bereits eine Datei gleichen Namens vorhanden sein, diese vorher in i2c1-bcm2708.dtbo.orig umbenennen.
  3. In der Datei /boot/config.txt die folgende Zeile am Ende hinzufügen:
    dtoverlay=i2c1-bcm2708
    
  4. Den Raspberry rebooten.

I2C-Adresse ändern

Bei den meisten I2C-Sensoren kann unter mehreren Adressen ausgewählt werden. Beim SDP610 ist die Adresse auf 0x40 festgelegt. Will man mehrere Differenzdrucksensoren anschließen, müsste man eigentlich zwei I2C-Busse implementieren oder die Sensoren umschalten. Beim SDP6xx steht die Adresse in einem internen EEPROM. Man kann unter Verlust der Garantie die Adresse im EEPROM mit einem abweichenden Wert überschreiben. Erreicht wird dies durch eine Funktion, die nur ein einziges Mal ausgeführt werden muss, wobei nur der zu modifizierende Sensor am I2C-Bus angeschlossen sein darf. Im Python-Programm befindet sich deshalb noch eine zweite Funktion, changeAddress(), mit der sich das interne EEPROM mit einer alternativen I2C-Adresse programmieren läßt. Der Hersteller verweist darauf, dass deren Anwendung zum Wegfall der Garantie führt - Verwendung auf eigene Gefahr. In der Funktion wird beispielhaft die Adresse 0x41 eingestellt, man kann natürlich auch jede andere Adresse nehmen.

def changeAddress(sensor):
  # change I2c address from 0x40 to 0x41
  # according to instructions sensirion
  # RUN ONLY ONCE! NEVER RUN THIS AGAIN!
  # Use on your own risk!
  Bdata = [0x2C,0x20,0x001,0x0f]               # Ref. Sensirion
  i2c.write_i2c_block_data(sensor,0xFA,Bdata)
  time.sleep(0.1)
  i2c.write_byte(SDP01,0xFE)                   # soft reset
  i2c.write_byte(0x41,0xF1)                    # new address = 0x41
  return

Links


Copyright © Hochschule München, FK 04, Prof. Jürgen Plate und die Autoren
Letzte Aktualisierung: