В этой статье подключим датчики DHT11 и DHT22 к Raspberry Pi, а точнее к Orange Pi PC, так как эта плата у меня есть. В принципе это не имеет значения, потому что ниже приведённые библиотеки и примеры запустятся и на Banana Pi, Odroid и NanoPi. Это что касается примеров на Java, использующие библиотеки Pi4J. А примеры на C/C++ можно запустить на все платы, на которые можно установить WiringPi.
Я раньше писал о популярных датчиках влажности и температуры DHT11 и DHT22 в статье Датчики температуры и влажности DHT11 и DHT22. Там же и документация по DHT11 и DHT22.
За основу использовалась библиотека от Adafruit — одна из стабильных версий, найденных мною в Интернете. Это Python библиотека для чтения данных с датчиков влажности и температуры DHT серии на Raspberry Pi и Beaglebone Black. Однако для чтения данных непосредственно с датчика используется язык программирования C, чтобы уменьшить вероятность ошибки во время чтения.
Библиотека C/C++
Изначально планировал сделать только на Java, так как это серия уроков по Pi4J, но решил сделать библиотеку и на C/C++, чтобы не писать отдельную статью.
DHTxx.h
#ifndef DHTXX_H_
#define DHTXX_H_
#include <stdint.h>
/*
* Define errors and return values.
*/
#define DHT_ERROR_TIMEOUT -1
#define DHT_ERROR_CHECKSUM -2
#define DHT_ERROR_ARGUMENT -3
#define DHT_ERROR_GPIO -4
#define DHT_SUCCESS 0
/*
* Define sensor types.
*/
#define DHT11 11
#define DHT22 22
#define AM2302 22
/**
* This is the only processor specific magic value, the maximum amount of time to
* spin in a loop before bailing out and considering the read a timeout. This should
* be a high value, but if you're running on a much faster platform than a Raspberry
* Pi or Beaglebone Black then it might need to be increased.
*/
#define DHT_MAXCOUNT 32000
/**
* Number of bit pulses to expect from the DHT. Note that this is 41 because
* the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
* the data afterwards.
*/
#define DHT_PULSES 41
class DHTxx {
private:
int pin;
int sensor;
public:
DHTxx(int pin, int sensor);
virtual ~DHTxx();
int init();
/**
* Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be
* returned in the provided parameters. If a successfull reading could be made a value of 0
* (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will
* be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
*/
int read(float* humidity, float* temperature);
int getPin() const;
void setPin(int pin);
int getSensor() const;
void setSensor(int sensor);
private:
/**
* Busy wait delay for most accurate timing, but high CPU usage.
* Only use this for short periods of time (a few hundred milliseconds at most)!
*/
void busyWaitMilliseconds(uint32_t millis);
/**
* General delay that sleeps so CPU usage is low, but accuracy is potentially bad.
*/
void sleepMilliseconds(uint32_t millis);
/**
* Increase scheduling priority and algorithm to try to get 'real time' results.
*/
void setMaxPriority(void);
/**
* Drop scheduling priority back to normal/default.
*/
void setDefaultPriority(void);
};
#endif /* DHTXX_H_ */
init()
Инициализация GPIO и WiringPi.
int init();
read(float*, float*)
Считывает данные с датчика DHT, подключенного к выводу GPIO (с использованием нумерации WiringPi). Влажность и температура будут возвращены в заданных параметрах. Если чтение успешное, будет возвращено значение 0 (DHT_SUCCESS). Если при считывании данных произошла ошибка, возвращается отрицательное значение. Некоторые ошибки можно игнорировать и повторять чтение, в частности DHT_ERROR_TIMEOUT или DHT_ERROR_CHECKSUM.
int read(float* humidity, float* temperature);
busyWaitMilliseconds(uint32_t)
Приостанавливает работу потока, в котором она была вызвана, на указанное в аргументе время, загрузка процессора высокая, а точность высокая. Используйте этот метод только в течение короткого периода времени (не более нескольких сотен миллисекунд)!
void busyWaitMilliseconds(uint32_t millis);
sleepMilliseconds(uint32_t)
Приостанавливает работу потока, в котором она была вызвана, на указанное в аргументе время, загрузка процессора низкая, но точность потенциально плохая.
void sleepMilliseconds(uint32_t millis);
setMaxPriority()
Увеличивает приоритет планирования и алгоритм, чтобы попытаться получить результаты «реального времени» (SCHED_FIFO: планировщик FIFO (First In-First Out)).
void setMaxPriority(void);
setDefaultPriority();
Сбрасывает приоритет на нормальный/по умолчанию (SCHED_OTHER: стандартный алгоритм планировщика с разделением времени).
void setDefaultPriority(void);
DHTxx.cpp
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <wiringPi.h>
#include "DHTxx.h"
DHTxx::DHTxx(int pin, int sensor) {
this->pin = pin;
this->sensor = sensor;
}
DHTxx::~DHTxx() {
}
int DHTxx::init() {
/*
* Initialize GPIO library.
*/
if (wiringPiSetup() == -1) {
return DHT_ERROR_GPIO;
}
return DHT_SUCCESS;
}
int DHTxx::read(float* humidity, float* temperature) {
/*
* Validate humidity and temperature arguments and set them to zero.
*/
if (humidity == NULL || temperature == NULL) {
return DHT_ERROR_ARGUMENT;
}
*temperature = 0.0f;
*humidity = 0.0f;
/*
* Store the count that each DHT bit pulse is low and high.
* Make sure array is initialized to start at zero.
*/
uint32_t pulseCounts[DHT_PULSES * 2] = { 0 };
/*
* Set pin to output.
*/
pinMode(pin, OUTPUT);
/*
* Bump up process priority and change scheduler to try to try to make process more 'real time'.
*/
setMaxPriority();
/*
* Set pin high for ~500 milliseconds.
*/
digitalWrite(pin, HIGH);
sleepMilliseconds(500);
/*
* The next calls are timing critical and care should be taken
* to ensure no unnecssary work is done below.
*/
/*
* Set pin low for ~20 milliseconds.
*/
digitalWrite(pin, LOW);
busyWaitMilliseconds(20);
/*
* Set pin at input.
*/
pinMode(pin, INPUT);
/*
* Need a very short delay before reading pins or else value is sometimes still low.
*/
for (volatile int i = 0; i < 50; ++i) {
}
/*
* Wait for DHT to pull pin low.
*/
uint32_t count = 0;
while (digitalRead(pin)) {
if (++count >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
setDefaultPriority();
return DHT_ERROR_TIMEOUT;
}
}
/*
* Record pulse widths for the expected result bits.
*/
for (int i = 0; i < DHT_PULSES * 2; i += 2) {
/*
* Count how long pin is low and store in pulseCounts[i]
*/
while (!digitalRead(pin)) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
setDefaultPriority();
return DHT_ERROR_TIMEOUT;
}
}
/*
* Count how long pin is high and store in pulseCounts[i+1]
*/
while (digitalRead(pin)) {
if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
setDefaultPriority();
return DHT_ERROR_TIMEOUT;
}
}
}
/*
* Done with timing critical code, now interpret the results.
*/
/*
* Drop back to normal priority.
*/
setDefaultPriority();
/*
* Compute the average low pulse width to use as a 50 microsecond reference threshold.
* Ignore the first two readings because they are a constant 80 microsecond pulse.
*/
uint32_t threshold = 0;
for (int i = 2; i < DHT_PULSES * 2; i += 2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES - 1;
/*
* Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
* If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
* then it must be a ~70us 1 pulse.
*/
uint8_t data[5] = { 0 };
for (int i = 3; i < DHT_PULSES * 2; i += 2) {
int index = (i - 3) / 16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
/*
* One bit for long pulse.
*/
data[index] |= 1;
}
/*
* Else zero bit for short pulse.
*/
}
/*
* Verify checksum of received data.
*/
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
if (sensor == DHT11) {
/*
* Get humidity and temp for DHT11 sensor.
*/
*humidity = (float) data[0];
if (data[1] > 0) {
if (data[1] <= 9) {
*humidity += data[1] / 10.0;
} else {
*humidity += data[1] / 100.0;
}
}
*temperature = (float) data[2];
if (data[3] > 0) {
if (data[3] <= 9) {
*temperature += data[3] / 10.0;
} else {
*temperature += data[3] / 100.0;
}
}
} else if (sensor == DHT22) {
/*
* Calculate humidity and temp for DHT22 sensor.
*/
*humidity = (data[0] * 256 + data[1]) / 10.0f;
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
if (data[2] & 0x80) {
*temperature *= -1.0f;
}
}
return DHT_SUCCESS;
} else {
return DHT_ERROR_CHECKSUM;
}
}
int DHTxx::getPin() const {
return pin;
}
void DHTxx::setPin(int pin) {
this->pin = pin;
}
int DHTxx::getSensor() const {
return sensor;
}
void DHTxx::setSensor(int sensor) {
this->sensor = sensor;
}
void DHTxx::busyWaitMilliseconds(uint32_t millis) {
/*
* Set delay time period.
*/
struct timeval deltatime;
deltatime.tv_sec = millis / 1000;
deltatime.tv_usec = (millis % 1000) * 1000;
struct timeval walltime;
/*
* Get current time and add delay to find end time.
*/
gettimeofday(&walltime, NULL);
struct timeval endtime;
timeradd(&walltime, &deltatime, &endtime);
/*
* Tight loop to waste time (and CPU) until enough time as elapsed.
*/
while (timercmp(&walltime, &endtime, <)) {
gettimeofday(&walltime, NULL);
}
}
void DHTxx::sleepMilliseconds(uint32_t millis) {
struct timespec sleep;
sleep.tv_sec = millis / 1000;
sleep.tv_nsec = (millis % 1000) * 1000000L;
while (clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR)
;
}
void DHTxx::setMaxPriority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
/*
* Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
*/
sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);
}
void DHTxx::setDefaultPriority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
/*
* Go back to default scheduler with default 0 priority.
*/
sched.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sched);
}
Подключение DHT11 к Orange Pi One
Чтобы проверить работоспособность приведённого выше года, я подключил DHT11 к Orange Pi PC, скомпилировал и запустил ниже приведённый пример. На схеме Orange Pi One, потому что не нашёл компонент Orange Pi PC в fritzing.
Схема подключения DHT11 к Orange Pi One
Лучше использовать подтягивающий резистор на 10 кОм, при подключении резистора номинала 4.7 к — датчик не заработал.
Пример программы на C/C++
main.cpp
#include <iostream>
#include <unistd.h>
#include "DHTxx.h"
using namespace std;
int main() {
float humidity;
float temperature;
int pin = 7;
DHTxx dht11(pin, DHT11);
if (dht11.init() == DHT_SUCCESS) {
for (int i = 0; i < 10; ++i) {
int result = dht11.read(&humidity, &temperature);
switch (result) {
case DHT_ERROR_TIMEOUT:
cout << "DHT_ERROR_TIMEOUT" << endl;
break;
case DHT_ERROR_CHECKSUM:
cout << "DHT_ERROR_CHECKSUM" << endl;
break;
case DHT_ERROR_ARGUMENT:
cout << "DHT_ERROR_ARGUMENT" << endl;
break;
case DHT_ERROR_GPIO:
cout << "DHT_ERROR_GPIO" << endl;
break;
case DHT_SUCCESS:
cout << "humidity = " << humidity << " %" << endl;
cout << "temperature = " << temperature << " °C" << endl;
break;
default:
break;
}
sleep(3);
}
}
return 0;
}
Принцип работы примера
- Включаем файл
DHTxx.h#include "DHTxx.h"
- Объявляем переменные
humidityиtemperatureдля сохранения данных температуры и относительной влажностиfloat humidity; float temperature;
- Создаём объект класса
DHTxx. Первый параметр — это WiringPi пин, а второй — тип датчикаDHTxx dht11(pin, DHT11);
- Инициализируем датчик и продолжаем читать данные, если возвращаемый результат метода
init()равенDHT_SUCCESSif (dht11.init() == DHT_SUCCESS) {/*...*/} - Создаём цикл и читаем данные при помощи метода
int result = dht11.read(&humidity, &temperature);. Если возвращаемый результат методаread()в переменнуюresultравенDHT_SUCCESS, тогда выводим температуру и влажность на экран. А если во время чтения возникла какая-то ошибка, тогда выводим на экран код ошибки.for (int i = 0; i < 10; ++i) { int result = dht11.read(&humidity, &temperature); switch (result) { case DHT_ERROR_TIMEOUT: cout << "DHT_ERROR_TIMEOUT" << endl; break; case DHT_ERROR_CHECKSUM: cout << "DHT_ERROR_CHECKSUM" << endl; break; case DHT_ERROR_ARGUMENT: cout << "DHT_ERROR_ARGUMENT" << endl; break; case DHT_ERROR_GPIO: cout << "DHT_ERROR_GPIO" << endl; break; case DHT_SUCCESS: cout << "humidity = " << humidity << " %" << endl; cout << "temperature = " << temperature << " °C" << endl; break; default: break; } sleep(3); } - Минимальный интервал очередного чтения около двух секунд, я поставил 3.
sleep(3);
Результат
humidity = 53 % temperature = 29.1 °C DHT_ERROR_CHECKSUM humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 52 % temperature = 28.9 °C
Подключение DHT22 к Orange Pi One
Всё вышесказанное про DHT11 подойдёт и для DHT22. Единственное отличие только в том, что, при инициализации объекта класса DHTxx, второй параметр — это DHT22.
DHTxx dht22(pin, DHT22);
Схема подключения DHT22 к Orange Pi One
Пример программы на C/C++
main.cpp
#include <iostream>
#include <unistd.h>
#include "DHTxx.h"
using namespace std;
int main() {
float humidity;
float temperature;
int pin = 7;
DHTxx dht22(pin, DHT22);
if (dht22.init() == 0) {
for (int i = 0; i < 10; ++i) {
int result = dht22.read(&humidity, &temperature);
switch (result) {
case DHT_ERROR_TIMEOUT:
cout << "DHT_ERROR_TIMEOUT" << endl;
break;
case DHT_ERROR_CHECKSUM:
cout << "DHT_ERROR_CHECKSUM" << endl;
break;
case DHT_ERROR_ARGUMENT:
cout << "DHT_ERROR_ARGUMENT" << endl;
break;
case DHT_ERROR_GPIO:
cout << "DHT_ERROR_GPIO" << endl;
break;
case DHT_SUCCESS:
cout << "humidity = " << humidity << " %" << endl;
cout << "temperature = " << temperature << " °C" << endl;
break;
default:
break;
}
sleep(3);
}
}
return 0;
}
Результат
humidity = 49 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C DHT_ERROR_TIMEOUT
Библиотека Java
С помощью инструмента Pi4J я перевёл C/C++ код на Java. Проблема Джавы в том, что при чтении данных с датчика очень часто возникают ошибки. Проблема может быть решена двумя костылями: первое — это использовать нативные методы и вызывать C/C++ функции с помощью JNI, что является более правильным решением; второе и самое простое — это запросить данные с датчика пока не получим правильный результат.
Если ещё не установили Pi4J на вашу плату перейдите на страницу Установка Pi4J на Raspberry Pi и Orange Pi, Banana Pi.
DhtData.java
Класс DhtData содержит информацию о влажности и температуре.
package ru.micropi.pi4j.dhtxx;
public class DhtData {
private double temperature;
private double humidity;
public DhtData() {
super();
}
public DhtData(double temperature, double humidity) {
super();
this.temperature = temperature;
this.humidity = humidity;
}
public double getTemperature() {
return temperature;
}
public void setTemperature(double temperature) {
this.temperature = temperature;
}
public double getHumidity() {
return humidity;
}
public void setHumidity(double humidity) {
this.humidity = humidity;
}
@Override
public String toString() {
return "Temperature: " + temperature + "°C\nHumidity: " + humidity + "%";
}
}
DHTxx.java
Интерфейс DHTxx — это абстракция устройств DHT. Он позволяет инициализировать GPIO/WiringPi и читать данные с DHT11/DHT22.
package ru.micropi.pi4j.dhtxx;
import com.pi4j.io.gpio.Pin;
public interface DHTxx {
public void init() throws Exception;
public Pin getPin();
public void setPin(Pin pin);
public DhtData getData() throws Exception;
}
init()
Метод инициализирует GPIO/WiringPi, выбрасывает исключение, если это не удалось сделать.
public void init() throws Exception;
getData()
Метод считывает и проверяет данные с датчика, а после возвращает эти данные в виде объекта класса DhtData. В случае ошибки выбрасывает исключение.
public DhtData getData() throws Exception;
DHTxxBase.java
В абстрактном классе DHTxxBase реализованы методы: getPin(), setPin() и init(). Также добавлен метод getRawData(), именно здесь происходит чтение и преобразование данных с датчиков DHT11/DHT22. Эти методы являются общими для обоих датчиков.
package ru.micropi.pi4j.dhtxx;
import com.pi4j.io.gpio.Pin;
import com.pi4j.wiringpi.Gpio;
public abstract class DHTxxBase implements DHTxx {
private static final int DHT_MAXCOUNT = 32000;
private static final int DHT_PULSES = 41;
private Pin pin;
public DHTxxBase(Pin pin) {
this.pin = pin;
}
public Pin getPin() {
return pin;
}
public void setPin(Pin pin) {
this.pin = pin;
}
@Override
public void init() throws Exception {
/*
* Initialize GPIO library.
*/
if (Gpio.wiringPiSetup() == -1) {
throw new Exception("DHT_ERROR_GPIO");
}
}
protected int[] getRawData() throws Exception {
/*
* Store the count that each DHT bit pulse is low and high. Make sure array
* is initialized to start at zero.
*/
int pulseCounts[] = new int[DHT_PULSES * 2];
/*
* Set pin to output.
*/
Gpio.pinMode(pin.getAddress(), Gpio.OUTPUT);
/*
* Bump up process priority and change scheduler to try to try to make
* process more 'real time'.
*/
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
/*
* Set pin high for ~500 milliseconds.
*/
Gpio.digitalWrite(pin.getAddress(), Gpio.HIGH);
Gpio.delay(500);
/*
* The next calls are timing critical and care should be taken to ensure no
* unnecessary work is done below.
*/
/*
* Set pin low for ~20 milliseconds.
*/
Gpio.digitalWrite(pin.getAddress(), Gpio.LOW);
Gpio.delay(20);
/*
* Set pin at input.
*/
Gpio.pinMode(pin.getAddress(), Gpio.INPUT);
/*
* Need a very short delay before reading pins or else value is sometimes
* still low.
*/
/*
* for (int i = 0; i < 50; ++i) {}
*/
/*
* Wait for DHT to pull pin low.
*/
long count = 0;
while (Gpio.digitalRead(pin.getAddress()) == 1) {
if (++count >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
throw new Exception("DHT_ERROR_TIMEOUT");
}
}
// Record pulse widths for the expected result bits.
for (int i = 0; i < DHT_PULSES * 2; i += 2) {
/*
* Count how long pin is low and store in pulseCounts[i]
*/
while (Gpio.digitalRead(pin.getAddress()) == 0) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
throw new Exception("DHT_ERROR_TIMEOUT: " + pulseCounts[i] + " pulses, " + i);
}
}
/*
* Count how long pin is high and store in pulseCounts[i+1]
*/
while (Gpio.digitalRead(pin.getAddress()) == 1) {
if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) {
/*
* Timeout waiting for response.
*/
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
throw new Exception("DHT_ERROR_TIMEOUT: " + pulseCounts[i + 1] + " pulses, " + i);
}
}
}
/*
* Done with timing critical code, now interpret the results.
*/
/*
* Drop back to normal priority.
*/
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
/*
* Compute the average low pulse width to use as a 50 microsecond reference
* threshold. Ignore the first two readings because they are a constant 80
* microsecond pulse.
*/
long threshold = 0;
for (int i = 2; i < DHT_PULSES * 2; i += 2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES - 1;
/*
* Interpret each high pulse as a 0 or 1 by comparing it to the 50us
* reference. If the count is less than 50us it must be a ~28us 0 pulse, and
* if it's higher then it must be a ~70us 1 pulse.
*/
int data[] = new int[5];
for (int i = 3; i < DHT_PULSES * 2; i += 2) {
int index = (i - 3) / 16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
/*
* One bit for long pulse.
*/
data[index] |= 1;
}
/*
* Else zero bit for short pulse.
*/
}
return data;
}
}
DHTxxBase(Pin)
Конструктор класса DHTxxBase, как параметр получает номер пина по WiringPi, к которому подключён DHT датчик.
public DHTxxBase(Pin pin)
getRawData()
Метод считывает и преобразовывает данные с датчиков DHT11/DHT22. Возвращает массив из 5 байт, содержащий сведения о влажности, температуре и контрольной сумме. Выбрасывает исключение, если во время чтения возникла ошибка.
protected int[] getRawData() throws Exception
DHT11.java
package ru.micropi.pi4j.dhtxx;
import com.pi4j.io.gpio.Pin;
import com.pi4j.wiringpi.Gpio;
public class DHT11 extends DHTxxBase {
private static final int DHT_WAIT_INTERVAL = 2000;
public DHT11(Pin pin) {
super(pin);
}
@Override
public DhtData getData() throws Exception {
int atempts = 0;
while (true) {
try {
int[] data = getRawData();
/*
* Verify checksum of received data.
*/
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
throw new Exception("DHT_ERROR_CHECKSUM");
}
/*
* Get humidity and temp for DHT11 sensor.
*/
double humidity = data[0];
if (data[1] > 0) {
if (data[1] <= 9) {
humidity += data[1] / 10.0;
} else {
humidity += data[1] / 100.0;
}
}
double temperature = data[2];
if (data[3] > 0) {
if (data[3] <= 9) {
temperature += data[3] / 10.0;
} else {
temperature += data[3] / 100.0;
}
}
return new DhtData(temperature, humidity);
} catch (Exception e) {
atempts++;
if (atempts <= 3) {
Gpio.delay(DHT_WAIT_INTERVAL);
continue;
}
throw new Exception("Atempts " + atempts, e);
}
}
}
@Override
public String toString() {
return "DHT11, pin: " + getPin();
}
}
DHT22.java
package ru.micropi.pi4j.dhtxx;
import com.pi4j.io.gpio.Pin;
import com.pi4j.wiringpi.Gpio;
public class DHT22 extends DHTxxBase {
private static final int DHT_WAIT_INTERVAL = 2000;
public DHT22(Pin pin) {
super(pin);
}
@Override
public DhtData getData() throws Exception {
int atempts = 0;
while (true) {
try {
int[] data = getRawData();
/*
* Verify checksum of received data.
*/
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
throw new Exception("DHT_ERROR_CHECKSUM");
}
/*
* Calculate humidity and temp for DHT22 sensor.
*/
double humidity = (data[0] * 256 + data[1]) / 10.0;
double temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0;
if ((data[2] & 0x80) != 0) {
temperature *= -1.0f;
}
return new DhtData(temperature, humidity);
} catch (Exception e) {
atempts++;
if (atempts <= 3) {
Gpio.delay(DHT_WAIT_INTERVAL);
continue;
}
throw new Exception("Atempts " + atempts, e);
}
}
}
@Override
public String toString() {
return "DHT22, pin: " + getPin();
}
}
Классы DHT11 и DHT22 расширяют класс DHTxxBase, переопределён конструктор класса и реализован метод getData().
getData()
Метод getData() классов DHT11 и DHT22 почти одинаковые, отличаются лишь тем, как преобразовываются данные в градусах цельсия и процентах. Полученные данные возвращаются в виде объекта класс DhtData.
public DhtData getData() throws Exception {}
Из-за того, что очень часто при чтении возникают ошибки, функция пытается считывать данные из датчика до первой удачной попытки. Количество попыток ограничено 3.
if (atempts <= 3) {
Gpio.delay(DHT_WAIT_INTERVAL);
continue;
}
Если не удалось получить результат, тогда выбрасывается исключение.
Проблема в том, Raspberry Pi/Orange Pi не работают в режиме реального времени, то есть, программные задержки не всегда точны и это приводит к ошибкам при считывании данных.
Работа с DHT11 из Java
Ниже приведён пример программы, которая 10 запрашивает данные с интервалом в 2 секунд и выводит результат в терминале. Для DHT11 нужно создать экземпляр класса DHT11.
DHTxx dht11 = new DHT11(OrangePiPin.GPIO_07);
Схема подключения DHT11 к Orange Pi One
Пример программы на Java, DHT11Test.java
package ru.micropi.pi4j.dhtxx.tests;
import ru.micropi.pi4j.dhtxx.DHT11;
import ru.micropi.pi4j.dhtxx.DHTxx;
import com.pi4j.io.gpio.OrangePiPin;
public class DHT11Test {
private static final int DHT_WAIT_INTERVAL = 2000;
public static void main(String[] args) {
DHTxx dht11 = new DHT11(OrangePiPin.GPIO_07);
System.out.println(dht11);
try {
dht11.init();
for (int i = 0; i < 10; i++) {
try {
System.out.println(dht11.getData());
Thread.sleep(DHT_WAIT_INTERVAL);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
Результат
DHT11, pin: GPIO 7 Temperature: 28.6°C Humidity: 54.0% Temperature: 28.6°C Humidity: 53.0% Temperature: 28.6°C Humidity: 53.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 51.0% Temperature: 28.6°C Humidity: 51.0%
Работа с DHT22 из Java
Для работы с DHT22 создаём экземпляр класса DHT22, в остальном всё то же самое как и с DHT11.
DHTxx dht22 = new DHT22(OrangePiPin.GPIO_07);
Схема подключения DHT22 к Orange Pi One
Пример программы на Java, DHT22Test.java
package ru.micropi.pi4j.dhtxx.tests;
import ru.micropi.pi4j.dhtxx.DHT22;
import ru.micropi.pi4j.dhtxx.DHTxx;
import com.pi4j.io.gpio.OrangePiPin;
public class DHT22Test {
private static final int DHT_WAIT_INTERVAL = 2000;
public static void main(String[] args) {
DHTxx dht22 = new DHT22(OrangePiPin.GPIO_07);
System.out.println(dht22);
try {
dht22.init();
for (int i = 0; i < 10; i++) {
try {
System.out.println(dht22.getData());
Thread.sleep(DHT_WAIT_INTERVAL);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
Результат
DHT22, pin: GPIO 7 Temperature: 28.3°C Humidity: 48.7% Temperature: 28.3°C Humidity: 48.6% Temperature: 28.3°C Humidity: 48.9% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.2°C Humidity: 48.4% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.2°C Humidity: 48.4% Temperature: 28.3°C Humidity: 48.5%
Проекты Eclipse
DHT11 — Eclipse C++
DHTxx — Eclipse Java
Материалы
Adafruit Python DHT Sensor Library
Датчики температуры и влажности DHT11 и DHT22
Проект OpenNet: MAN sched_setscheduler (2) Системные вызовы (FreeBSD и Linux)

