В этой статье подключим датчики 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_SUCCESS
if (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)
Отличная статья!Жаль нет пошаговой инструкции для чайников.Будем разбираться 🙂
Здравствуйте, спасибо за ваше руководство. Когда я запускаю программу, время от времени я получаю следующую ошибку. Мой метод использует аннотацию @Scheduled (fixedRate = 10000). Как ее решить?
java.lang.Exception: Atempts 4
Caused by: java.lang.Exception: DHT_ERROR_TIMEOUT: 32000 pulses, 70
at ru.micropi.pi4j.dhtxx.DHTxxBase.getRawData(DHTxxBase.java:119)
at ru.micropi.pi4j.dhtxx.DHT22.getData(DHT22.java:19)
Здравствуйте. Что-то не получается скомпилировать C++
/tmp/ccRZ5e8m.o: In function `main’:
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::DHTxx(int, int)’
/dht22/cpp/dht.cpp:14: undefined reference to `DHTxx::init()’
/dht22/cpp/dht.cpp:16: undefined reference to `DHTxx::read(float*, float*)’
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::~DHTxx()’
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::~DHTxx()’
Добрый день!
при компиляции получаю ошибку
DHTxx.cpp:256:1: error: stray ‘\177’ in program
датчик dht22
))) сам дурак, все поправил.
Подскажите еще такой момент, чем теперь удобнее собирать данные в файл или еще лучше прикрутить график для удаленного мониторинга?
Насколько я понимаю это уже в perl или python, что лучше выбрать?
Ранее программированием не занимался.
IndianPharmacyAbp: India pharmacy ship to USA — Indian Pharmacy Abp
Best online Indian pharmacy: Best Indian pharmacy — Indian Pharmacy Abp
https://indianpharmacyabp.shop/# Best online Indian pharmacy
mexican online pharmacies prescription drugs
vipps approved canadian online pharmacy: canadian drug stores — canada pharmacy online
canadian pharmacy ltd: Canadian Pharmacy AAPD — canadian pharmacies compare
Услуги от компании stroit-master — это экспертность, приобретенный за годы работы с новостройками. Профессиональная диагностика позволит сохранить время и спокойствие. Передайте сложные задачи лучшим в своей сфере.
https://indianpharmacyabp.com/# Best Indian pharmacy
mexican online pharmacies prescription drugs
best online pharmacy india: IndianPharmacyAbp — Online medicine home delivery
http://mexicanpharmacyacp.com/# mexican pharmacy acp
purple pharmacy mexico price list
Online medicine home delivery: India pharmacy ship to USA — Best Indian pharmacy
Оформите экспертную проверку недавно приобретенного помещения от компании stroit-master. Наши эксперты предлагаем всесторонний набор работ по оценке квартир. Благодаря большому багажу знаний наша команда предоставляем высочайшее качество работ.
canadian drug pharmacy: canadian drug — onlinecanadianpharmacy
IndianPharmacyAbp: Indian pharmacy international shipping — Best Indian pharmacy
https://neokomsomol.kz/# Ргровые автоматы доступны всем желающим.
https://neokomsomol.kz/# Крути барабаны и жди победы!
Крути барабаны Рё жди победы!: balloon казино играть — balloon казино демо
Автомат Ballon — идеальный СЃРїРѕСЃРѕР± расслабиться.: balloon казино — balloon игра
Hunting for a trustworthy platform for entertainment? 1win casino offers an remarkable selection of gaming choices. Explore this destination to experience engaging playtime.
Казино — место для увлекательных РёРіСЂ.: balloon казино — balloon game
Рграйте РІ казино Рё забудьте Рѕ заботах.: balloon казино официальный сайт — balloon казино играть
Explore the thrilling world of online gaming at casino 1win. Gamers can savor diverse rewards and exceptional support. Attempt your chance right away.
Казино — это шанс РЅР° финансовую СЃРІРѕР±РѕРґСѓ.: balloon игра — balloon казино демо
Want to find a dependable web-based gaming venue? prof-casino.com stands out with its easy-to-use layout. Gamers internationally trust this venue for its honesty and captivating play varieties.
Ballon — это ваш шанс РЅР° победу.: balloon казино демо — balloon game
https://balloonigra.kz/# Автоматы Ballon поднимают настроение каждому.
In Mine Gems, the maximum multiplier is x14.28 on Step 12, so with a stake of €100, the highest possible win is €1,428. The game’s low volatility offers frequent payouts that depend on how many multipliers you accumulate successfully and when you decide to tap on Cashout. One of the best things about the Mines game is its perfect blend of strategy and unpredictability. While players may set their difficulty level by adjusting the amount of mines, each tile reveal keeps the game interesting. Moreover, when you’re ready to step up your game, the switch from the Mines demo to real money play is both smooth and enticing. The range of bets available in the Mines free online casino demo game we tested, ran from a minimum bet per spin of 0.1$ £ € up to a maximum of 100$ £ € per spin.
http://dogbuteamve1981.cavandoragh.org/full-article
Mac88 is the popular provider of online card games at Ultrawin online betting site. You can log in to your account and choose the card games from the recommended games section. A wide variety of card games you can play at our casino are: The supplier Hacksaw Gaming has created a truly customizable game. Select one of the grids: 3×3, 5×5, 7×7 or 9×9. Choose the number of mines. The 7-mine system is riskier, but the multipliers are also higher. When we tested this game, we tried different strategies and both were winning. If you like to play it safe, go for the 3-mine version. In addition, the game has a unique RTP of 98%, while most variations give around 96%. Artifacts and minerals which need to be donated to the museum will be marked in the results, however the Fossilized Skull (which can be found in Golden Coconuts and donated to the Ginger Island Field Office) does not have donation status checked.
balloon игра на деньги balloon казино играть Ballon радует РёРіСЂРѕРєРѕРІ разнообразием функций.
Experience the enticing universe of internet amusement at casino 1win. Users can relish various promotions and superior help. Attempt your chance immediately.
alo789in: alo789hk — alo789
https://alo789.auction/# alo 789
k8vip nha cai k8 nha cai k8
k8 bet: k8 th? dam — k8 bet
https://88betviet.pro/# 88bet
keo nha cai 88bet: 188bet 88bet — 88 bet
https://k8viet.gurum/# k8 th? dam
k8 k8vip k8
Desire to discover a dependable online casino? prof-casino.com distinguishes itself with its easy-to-use structure. Players globally rely on this destination for its transparency and exciting game selection.
k8 bet: nha cai k8 — nha cai k8
http://88betviet.pro/# 88 bet
k8 th? dam: k8 — link vao k8
188bet 88bet: nha cai 88bet — keo nha cai 88bet
k8: link vao k8 — nha cai k8
Experience the exciting world of virtual entertainment at casino 1win. Gamers can savor various rewards and superior help. Sample your fortune today.
https://k8viet.guru/# k8 bet
nha cai 88bet: keo nha cai 88bet — 88 bet
https://alo789.auction/# alo789hk
k8vip: link vao k8 — k8 bet
alo789 dang nh?p: alo 789 — 789alo
медицинская справка на права спб медицинская справка для водительских прав спб
http://88betviet.pro/# 188bet 88bet
k8 th? dam link vao k8 link vao k8
keo nha cai 88bet: 88 bet — nha cai 88bet
Specialized playing awaits you at prof-casino. This particular destination offers premium protection and fast cashouts. Become part of to appreciate unmatched amusement fun.
https://k8viet.guru/# link vao k8
nha cai 88bet: keo nha cai 88bet — keo nha cai 88bet
https://alo789.auction/# alo789
http://k8viet.guru/# nha cai k8
k8vip: k8vip — k8 bet
https://88betviet.pro/# keo nha cai 88bet
alo789in: alo789 chinh th?c — alo789
https://88betviet.pro/# 188bet 88bet
http://k8viet.guru/# nha cai k8
88bet slot 88bet slot 188bet 88bet
88 bet: 88bet slot — 88bet slot
http://88betviet.pro/# 88bet slot
keo nha cai 88bet: 88bet — 88 bet
http://alo789.auction/# alo 789
http://alo789.auction/# 789alo
http://88betviet.pro/# nha cai 88bet
88bet slot: nha cai 88bet — keo nha cai 88bet
alo 789: alo789 — alo789
https://88betviet.pro/# 188bet 88bet
alo 789: alo789 chinh th?c — alo789 chinh th?c
alo 789 dang nh?p: alo789in — alo 789
188bet 88bet 88bet slot 88bet
http://alo789.auction/# alo789 chinh th?c
k8 bet: k8 — k8
188bet 88bet: 188bet 88bet — 88bet slot
https://88betviet.pro/# 188bet 88bet
k8: link vao k8 — k8
покупка аккаунтов соц сетей покупка аккаунтов соц сетей
где продать аккаунт маркетплейс цифровых аккаунтов
где можно продать аккаунт продать аккаунты соц сетей
ordering drugs from canada: legitimate canadian pharmacies online — canadian pharmacy india
https://mexicanpharminter.shop/# buying from online mexican pharmacy
canada drugstore pharmacy rx
mexican pharmacy online store: Mexican Pharm International — mexican drug stores online
canada drugs online reviews online canadian pharmacy no prescription canadian pharmacy
https://indiamedfast.com/# online medicine shopping in india
canadian pharmacy meds review
canadian neighbor pharmacy: most reliable canadian online pharmacies — canadianpharmacy com
IndiaMedFast: order medicines online india — cheapest online pharmacy india
canadian pharmacy meds: legitimate canadian pharmacies online — canadianpharmacymeds
https://indiamedfast.shop/# online medicine shopping in india
legitimate canadian mail order pharmacy
canadian mail order pharmacy: Pharmacies in Canada that ship to the US — canadian pharmacy prices
Mexican Pharm International mexican pharmacy online store Mexican Pharm International
https://indiamedfast.com/# india online pharmacy store
safe canadian pharmacies
online medicine shopping in india: india online pharmacy store — online medicine shopping in india
why iphone new iphone
canada cloud pharmacy: legitimate canadian pharmacies online — canadian pharmacy online reviews
http://interpharmonline.com/# best rated canadian pharmacy
canada pharmacy reviews
MexicanPharmInter: mexican pharmacy online store — mexican drug stores online
https://interpharmonline.shop/# medication canadian pharmacy
canadian pharmacy online ship to usa
http://mexicanpharminter.com/# Mexican Pharm Inter
online canadian drugstore Cheapest online pharmacy canadian drugstore online
https://mexicanpharminter.shop/# mexican drug stores online
best canadian online pharmacy
best mail order pharmacy canada: Certified International Pharmacy Online — certified canadian international pharmacy
магазин продажи аккаунтов сайт аккаунтов социальной сети
биржа аккаунтов цифровой магазин аккаунтов
https://mexicanpharminter.shop/# Mexican Pharm International
canadian pharmacy uk delivery
http://interpharmonline.com/# canadian pharmacy prices
https://interpharmonline.shop/# buy canadian drugs
canadian pharmacy com
MexicanPharmInter: Mexican Pharm International — mexican pharmacy online order
canadian pharmacy service: Online pharmacy USA — canadian pharmacy king reviews
https://indiamedfast.com/# cheapest online pharmacy india
pharmacy canadian
магазин аккаунтов соц сетей площадка для продажи аккаунтов
https://mexicanpharminter.shop/# Mexican Pharm International
canada drugstore pharmacy rx
https://mexicanpharminter.com/# mexican pharmacy online
legal to buy prescription drugs from canada
canadian pharmacy 365: most trusted canadian pharmacies online — cheap canadian pharmacy
http://mexicanpharminter.com/# buying from online mexican pharmacy
my canadian pharmacy rx
Generic100mgEasy Sildenafil Citrate Tablets 100mg Sildenafil Citrate Tablets 100mg
https://generic100mgeasy.com/# buy viagra here
https://kamagrakopen.pro/# kamagra gel kopen
TadalafilEasyBuy.com: Cialis 20mg price — cialis without a doctor prescription
kamagra pillen kopen Kamagra Kopen Kamagra
https://kamagrakopen.pro/# kamagra kopen nederland
https://kamagrakopen.pro/# Kamagra Kopen
Generic Tadalafil 20mg price Tadalafil Easy Buy TadalafilEasyBuy.com
Tadalafil Easy Buy: cialis without a doctor prescription — cialis without a doctor prescription
kamagra pillen kopen: KamagraKopen.pro — Kamagra
http://tadalafileasybuy.com/# cialis without a doctor prescription
sildenafil 50 mg price: Cheapest Sildenafil online — Cheap generic Viagra
https://generic100mgeasy.com/# Generic 100mg Easy
cialis without a doctor prescription Tadalafil Easy Buy Tadalafil Easy Buy
https://tadalafileasybuy.com/# cialis without a doctor prescription
http://tadalafileasybuy.com/# Tadalafil Easy Buy
kamagra gel kopen kamagra pillen kopen kamagra pillen kopen
https://tadalafileasybuy.com/# п»їcialis generic
http://tadalafileasybuy.com/# TadalafilEasyBuy.com
Generic100mgEasy: Generic 100mg Easy — order viagra
https://generic100mgeasy.shop/# Generic100mgEasy
kamagra jelly kopen: kamagra gel kopen — kamagra 100mg kopen
kamagra jelly kopen Kamagra kamagra 100mg kopen