Lire la température / l'humidité avec Java de Raspberry Pi 3 & DHT11

introduction

Utilisez le Raspberry Pi 3 pour lire les informations de température et d'humidité à partir du capteur de température et d'humidité bon marché et disponible DHT11. Le langage de programmation utilise Java.

DHT11
M-07003.jpg

Préparation

Utilisez Pi4J pour contrôler le GPIO du Raspberry Pi à partir de Java. Pour l'environnement Pi4J, reportez-vous à «Installation de Pi4J» dans l'article suivant.

Représentez graphiquement les informations du capteur de Raspberry Pi et préparez un environnement qui peut être vérifié avec un navigateur Web

Cette fois, Raspberry Pi et DHT11 sont connectés comme suit. La fiche technique indiquait une résistance de 5KΩ entre VDD et le chemin de données, mais je ne l'avais pas, alors je l'ai remplacée par 10KΩ (je ne suis pas très familier avec cela, donc je vais bien pour le moment ...).

(Référence) DHT11 Datasheet

schéma DHT11.png ** Schéma de câblage réel ** DHT11_ブレッドボード.png

programme

Le programme est une version Java du programme Python référencé ci-dessous (avec quelques modifications).

DHT11 Python library

Le programme se compose des trois fichiers suivants.

Lors de la création d'une instance de la classe principale DHT11, spécifiez le ** numéro GPIO ** de la broche du Raspberry Pi à laquelle la broche Data de DHT11 est connectée au constructeur. Par exemple, si vous êtes connecté à la broche 8 de votre Raspberry Pi, spécifiez le numéro GPIO 15 correspondant.

(Référence) Affectation des broches de 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;
    }
}

Compiler et exécuter

Placez les trois fichiers ci-dessus dans un répertoire approprié et compilez.

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

Après la compilation, exécutez avec les privilèges root. Lit et affiche les données de température et d'humidité toutes les 2 secondes. Entrez Ctrl + C pour quitter.

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:~ $

En raison de la communication urgente de DHT11, la lecture à partir de Java exécuté sur un système d'exploitation multitâche échoue souvent relativement souvent, en particulier au démarrage plusieurs fois de suite. Lorsque vous l'utilisez réellement, vérifiez le résultat de la lecture avec la méthode isValid () de la classe DHT11Result comme indiqué dans l'exemple de code (DHT11Demo.java) et réessayez jusqu'à ce que cela réussisse (si la méthode retourne false, la lecture échoue. J'ai).

Recommended Posts

Lire la température / l'humidité avec Java de Raspberry Pi 3 & DHT11
Lire la pression et la température de Raspberry Pi 3 et BMP180 avec Java
Trouvez Raspberry Pi d'Android avec mDNS
Afficher les caractères sur l'écran LCD I2C 1602 avec Raspberry Pi 3 et Java
Coder Java depuis Emacs avec Eclim
Traitez le mouvement détecté par le capteur humain HC-SR501 avec Raspberry Pi 3 et Java
Afficher les caractères définis par l'utilisateur sur l'écran LCD I2C 1602 avec Raspberry Pi 3 et Java
Surveillez facilement l'environnement intérieur - ⑩ Obtenez température / humidité / pression à partir du BME280 (substitut) avec Java (I2C / Pi4J) -
Appeler la bibliothèque Java à partir de C avec JNI
Intégration API de Java avec Jersey Client
Raspberry Pi Zero avec Yocto-gcc de style Ubuntu avec libusb
Introduction à Java à partir de 0 Partie 1
Lire le fichier xlsx en Java avec Selenium
Exécutez du code Java à partir de cpp sur cocos2dx
Surveillez facilement l'environnement intérieur ~ ③ Obtenez la température / l'humidité / l'éclairement, etc. de TI SensorTag CC2650 avec Java (Bluetooth LE / bluez-dbus) ~
Exécuter Rust depuis Java avec JNA (Java Native Access)
Lire une chaîne dans un fichier PDF avec Java
[Java] Réglez l'heure depuis le navigateur avec jsoup
[Android] Lire à partir de l'image du code QR avec zxing
Je n'ai pas pu installer docker avec raspberry pi2 b +.
Extraction de texte en Java à partir de PDF avec pdfbox-2.0.8
Mémo: [Java] Obtenez des données Raspberry Pi avec SFTP