Lesen Sie Temperatur / Luftfeuchtigkeit von Raspberry Pi 3 & DHT11 mit Java ab

Einführung

Verwenden Sie den Raspberry Pi 3, um Temperatur- und Feuchtigkeitsinformationen vom kostengünstigen und verfügbaren Temperatur- und Feuchtigkeitssensor DHT11 zu lesen. Die Programmiersprache verwendet Java.

DHT11
M-07003.jpg

Vorbereitung

Verwenden Sie Pi4J, um den GPIO des Raspberry Pi von Java aus zu steuern. Informationen zur Pi4J-Umgebung finden Sie im folgenden Artikel unter "Installieren von Pi4J".

Stellen Sie die Sensorinformationen von Raspberry Pi grafisch dar und bereiten Sie eine Umgebung vor, die mit einem Webbrowser überprüft werden kann

Diesmal sind Raspberry Pi und DHT11 wie folgt verbunden. Das Datenblatt listete einen 5KΩ-Widerstand zwischen VDD und dem Datenpfad auf, aber ich hatte ihn nicht, also ersetzte ich ihn durch 10KΩ (ich bin damit nicht sehr vertraut, also bin ich damit einverstanden ...).

(Referenz) DHT11-Datenblatt

Schaltplan DHT11.png ** Aktueller Schaltplan ** DHT11_ブレッドボード.png

Programm

Das Programm wird unter Bezugnahme auf das unten verlinkte Python-Programm (mit einigen Änderungen) in Java umgeschrieben.

DHT11 Python library

Das Programm besteht aus den folgenden drei Dateien.

Geben Sie beim Erstellen einer Instanz der Hauptklasse DHT11 die ** GPIO-Nummer ** des Pins des Raspberry Pi an, mit dem der Daten-Pin von DHT11 mit dem Konstruktor verbunden ist. Wenn Sie beispielsweise an Pin 8 Ihres Raspberry Pi angeschlossen sind, geben Sie die entsprechende GPIO-Nummer 15 an.

(Referenz) Pinbelegung von Raspberry Pi 3

DHT11Demo.java


import java.util.Date;
import java.util.concurrent.TimeUnit;

public class DHT11Demo {
    public static void main(String[] args) throws InterruptedException {
        DHT11 dht11 = new DHT11(15); // use GPIO pin 15

        while (true) {
            DHT11Result result = dht11.read();

            if (result.isValid()) {
                System.out.println("Last valid input: " + new Date());
                System.out.printf("Temperature: %.1f C\n" , result.getTemperature());
                System.out.printf("Humidity:    %.1f %%\n", result.getHumidity());
            }

            TimeUnit.SECONDS.sleep(2);
        }
    }
}

DHT11.java


import java.util.ArrayList;
import java.util.List;

import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.GpioUtil;

public class DHT11 {
    // DHT11 sensor reader class for Raspberry Pi

    private int pin; // GPIO pin number
    private List<Integer> data    = new ArrayList<>(10000);
    private List<Integer> lengths = new ArrayList<>(40); // will contain the lengths of data pull up periods

    public DHT11(int pin) {
        // setup wiringPi
        if (Gpio.wiringPiSetup() != 0) {
            throw new RuntimeException("Initialization of the GPIO has failed.");
        }
        this.pin = pin;
        GpioUtil.export(pin, GpioUtil.DIRECTION_OUT);
    }

    public DHT11Result read() {
        data.clear();
        lengths.clear();

        // change to output, then send start signal
        Gpio.pinMode(pin, Gpio.OUTPUT);

        Gpio.digitalWrite(pin, Gpio.LOW);
        Gpio.delay(18); // ms

        Gpio.digitalWrite(pin, Gpio.HIGH);

        // change to input
        Gpio.pinMode(pin, Gpio.INPUT);

        // collect data into a list
        collectInput();

        // parse lengths of all data pull up periods
        parseDataPullUpLengths();

        // if bit count mismatch, return error (4 byte data + 1 byte checksum)
        if (lengths.size() != 40)
            return new DHT11Result(DHT11Result.ERR_MISSING_DATA, 0.0, 0.0, data.size(), lengths.size());

        // calculate bits from lengths of the pull up periods
        boolean[] bits = calculateBits();

        // we have the bits, calculate bytes
        byte[] bytes = bitsToBytes(bits);

        // calculate checksum and check
        if (bytes[4] != calculateChecksum(bytes))
            return new DHT11Result(DHT11Result.ERR_CRC, 0.0, 0.0, data.size(), lengths.size());

        // ok, we have valid data, return it
        return new DHT11Result(DHT11Result.ERR_NO_ERROR,
                Double.parseDouble(bytes[2] + "." + bytes[3]),
                Double.parseDouble(bytes[0] + "." + bytes[1]),
                data.size(), lengths.size());
    }

    // this is used to determine where is the end of the data
    private final int MAX_UNCHANGED_COUNT = 500;

    private void collectInput() {
        // collect the data while unchanged found
        int unchangedCount = 0;

        int last = -1;
        while (true) {
            int current = Gpio.digitalRead(pin);
            data.add(current);

            if (last != current) {
                unchangedCount = 0;
                last = current;
            } else {
                if (++unchangedCount > MAX_UNCHANGED_COUNT) break;
            }
        }
    }

    protected enum SignalTransition {
        STATE_INIT_PULL_DOWN      ,
        STATE_INIT_PULL_UP        ,
        STATE_DATA_FIRST_PULL_DOWN,
        STATE_DATA_PULL_UP        ,
        STATE_DATA_PULL_DOWN
    };

    private void parseDataPullUpLengths() {
        SignalTransition state = SignalTransition.STATE_INIT_PULL_DOWN;

        int currentLength = 0; // will contain the length of the previous period

        for (int current : data) {
            currentLength++;

            switch (state) {
            case STATE_INIT_PULL_DOWN:
                if (current == Gpio.LOW) {
                    // ok, we got the initial pull down
                    state = SignalTransition.STATE_INIT_PULL_UP;
                }
                break;

            case STATE_INIT_PULL_UP:
                if (current == Gpio.HIGH) {
                    // ok, we got the initial pull up
                    state = SignalTransition.STATE_DATA_FIRST_PULL_DOWN;
                }
                break;

            case STATE_DATA_FIRST_PULL_DOWN:
                if (current == Gpio.LOW) {
                    // we have the initial pull down, the next will be the data pull up
                    state = SignalTransition.STATE_DATA_PULL_UP;
                }
                break;

            case STATE_DATA_PULL_UP:
                if (current == Gpio.HIGH) {
                    // data pulled up, the length of this pull up will determine whether it is 0 or 1
                    currentLength = 0;
                    state = SignalTransition.STATE_DATA_PULL_DOWN;
                }
                break;

            case STATE_DATA_PULL_DOWN:
                if (current == Gpio.LOW) {
                    // pulled down, we store the length of the previous pull up period
                    lengths.add(currentLength);
                    state = SignalTransition.STATE_DATA_PULL_UP;
                }
                break;
            }
        }
    }

    private boolean[] calculateBits() {
        boolean[] bits = new boolean[40];

        int longestPullUp  = lengths.stream().mapToInt(Integer::intValue).max().getAsInt();
        int shortestPullUp = lengths.stream().mapToInt(Integer::intValue).min().getAsInt();

        // use the halfway to determine whether the period it is long or short
        int halfway = shortestPullUp + (longestPullUp - shortestPullUp) / 2;

        int i = 0;
        for (int length : lengths) bits[i++] = length > halfway;

        return bits;
    }

    private byte[] bitsToBytes(boolean[] bits) {
        byte[] bytes = new byte[5];
        byte   value = 0;

        for (int i = 0; i < bits.length; i ++) {
            value <<= 1;
            if (bits[i]) value |= 1;

            if (i % 8 == 7) {
                bytes[i / 8] = value;
                value = 0;
            }
        }
        return bytes;
    }

    private byte calculateChecksum(byte[] bytes) {
        return (byte)(bytes[0] + bytes[1] + bytes[2] + bytes[3]);
    }
}

DHT11Result.java


public class DHT11Result {
    // DHT11 sensor result returned by DHT11.read() method

    public static final int ERR_NO_ERROR     = 0;
    public static final int ERR_MISSING_DATA = 1;
    public static final int ERR_CRC          = 2;

    private int errorCode = ERR_NO_ERROR;
    private double temperature;
    private double humidity;
    private int listElements;                // for debug
    private int detectedBits;                // for debug

    DHT11Result(int errorCode, double temperature, double humidity, int listElements, int detectedBits) {
        this.errorCode   = errorCode;
        this.temperature = temperature;
        this.humidity    = humidity;

        this.listElements = listElements;
        this.detectedBits = detectedBits;
    }

    public boolean isValid() {
        return errorCode == ERR_NO_ERROR;
    }
    public int getErrorCode() {
        return errorCode;
    }
    public double getTemperature() {
        return temperature;
    }
    public double getHumidity() {
        return humidity;
    }
    double getListElements() {
        return listElements;
    }
    double getDetectedBits() {
        return detectedBits;
    }
}

Kompilieren und ausführen

Legen Sie die obigen drei Dateien in ein geeignetes Verzeichnis und kompilieren Sie sie.

pi@raspberrypi:~ $ pi4j -c DHT11Demo.java
--------------------------------------------
Pi4J - Compiling: DHT11Demo.java
--------------------------------------------
+ javac -classpath '.:classes:*:classes:/opt/pi4j/lib/*' -d . DHT11Demo.java
pi@raspberrypi:~ $

Führen Sie nach dem Kompilieren die Root-Berechtigungen aus. Liest alle 2 Sekunden Temperatur- und Feuchtigkeitsdaten und zeigt sie an. Geben Sie zum Beenden Strg + C ein.

pi@raspberrypi:~ $ sudo pi4j DHT11Demo
+ java -classpath '.:classes:*:classes:/opt/pi4j/lib/*' DHT11Demo
Last valid input: Sun May 13 11:02:56 JST 2018
Temperature: 26.6 C
Humidity:    52.0 %
Last valid input: Sun May 13 11:02:58 JST 2018
Temperature: 26.7 C
Humidity:    52.0 %
Last valid input: Sun May 13 11:03:00 JST 2018
Temperature: 26.7 C
Humidity:    52.0 %
Last valid input: Sun May 13 11:03:02 JST 2018
Temperature: 26.7 C
Humidity:    52.0 %
Last valid input: Sun May 13 11:03:06 JST 2018
Temperature: 26.8 C
Humidity:    51.0 %
^Cpi@raspberrypi:~ $

Aufgrund der zeitkritischen Kommunikation von DHT11 schlägt das Lesen von Java unter einem Multitasking-Betriebssystem häufig relativ häufig fehl, insbesondere beim mehrmaligen Start in Folge. Wenn Sie es tatsächlich verwenden, überprüfen Sie das Leseergebnis mit der Methode isValid () der DHT11Result-Klasse, wie im Beispielcode (DHT11Demo.java) gezeigt, und wiederholen Sie den Vorgang, bis er erfolgreich ist (wenn die Methode false zurückgibt, schlägt der Lesevorgang fehl. Ich habe).

Recommended Posts

Lesen Sie Temperatur / Luftfeuchtigkeit von Raspberry Pi 3 & DHT11 mit Java ab
Lesen Sie Druck und Temperatur von Raspberry Pi 3 & BMP180 mit Java ab
Finden Sie Raspberry Pi von Android mit mDNS
Zeigen Sie Zeichen auf dem I2C 1602 LCD mit Raspberry Pi 3 und Java an
Code Java von Emacs mit Eclim
Verarbeiten Sie die vom menschlichen Sensor HC-SR501 erkannte Bewegung mit Raspberry Pi 3 & Java
Zeigen Sie benutzerdefinierte Zeichen auf dem I2C 1602 LCD mit Raspberry Pi 3 und Java an
Einfache Überwachung des Innenraumklimas - ⑩ Beziehen Sie Temperatur / Luftfeuchtigkeit / Druck von BME280 (Ersatz) mit Java (I2C / Pi4J) -
Rufen Sie die Java-Bibliothek von C mit JNI auf
API-Integration von Java mit Jersey Client
Raspberry Pi Zero mit Ubuntu-artigem Yocto-gcc mit libusb
Einführung in Java ab 0 Teil 1
Lesen Sie die xlsx-Datei in Java mit Selenium
Führen Sie Java-Code von cpp auf cocos2dx aus
Einfache Überwachung des Innenraumklimas ~ ③ Beziehen Sie Temperatur / Luftfeuchtigkeit / Beleuchtungsstärke usw. vom TI SensorTag CC2650 mit Java (Bluetooth LE / bluez-dbus) ~
Führen Sie Rust von Java mit JNA (Java Native Access) aus.
Lesen Sie eine Zeichenfolge in einer PDF-Datei mit Java
[Java] Stellen Sie die Zeit im Browser mit jsoup ein
[Android] Mit zxing aus dem QR-Code-Bild lesen
Ich konnte Docker nicht mit Himbeer pi2 b + installieren.
Textextraktion in Java aus PDF mit pdfbox-2.0.8
Anmerkung: [Java] Raspberry Pi-Daten mit SFTP abrufen