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 |
---|
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.
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 ** Schéma de câblage réel **
Le programme est une version Java du programme Python référencé ci-dessous (avec quelques modifications).
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;
}
}
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