В этой статье подключим датчики 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, что лучше выбрать?
Ранее программированием не занимался.
покупка аккаунтов соц сетей покупка аккаунтов соц сетей
why iphone new iphone
магазин продажи аккаунтов сайт аккаунтов социальной сети
помыть окна цена за 1 окно cleaning-top24
автомобиль в аренду в москве дешево прокат машины в москве посуточно
аренда машины спб цена прокат авто в спб
scooby comic action comics 2025 online
manga blue lock manga reader no ads
фильмы в качестве боевики 2025 смотреть бесплатно HD
маркетплейс аккаунтов продать аккаунт
производство металлических значков https://metallicheskie-znachki-zakaz.ru
аккаунт для рекламы продать аккаунт
услуги по продаже аккаунтов площадка для продажи аккаунтов
продажа аккаунтов платформа для покупки аккаунтов
платформа для покупки аккаунтов https://kupit-akkaunt-top.ru/
Account marketplace Account Acquisition
Account market Online Account Store
Purchase Ready-Made Accounts Secure Account Sales
Secure Account Purchasing Platform Accounts market
profitable account sales account selling service
account buying service buy accounts
verified accounts for sale account exchange
account exchange service account sale
online account store website for selling accounts
account trading platform website for selling accounts
account catalog account exchange service
account purchase buy accounts
accounts for sale secure account purchasing platform
account catalog account sale
account trading database of accounts for sale
online account store website for buying accounts
verified accounts for sale account trading
online account store secure account purchasing platform
купить курсовую написать курсовую цена
online account store https://marketplace-social-accounts.org/
sell account account trading
account trading platform account marketplace
sell account account trading platform
курсовую купить kursovie24.ru/
¡Hola seguidores del casino !
Con 25 tiradas gratis puedes probar suerte sin invertir.
El mejor momento para probar suerte es ahora, con 25 giros gratis sin depГіsito para ti.
¡Que tengas magníficas rondas inolvidables !
account selling service website for selling accounts
accounts market account acquisition
sell account account market
secure account purchasing platform ready-made accounts for sale
Нужен номер для ТГ? Предлагаем купить виртуальный номер для телеграм дешево для одноразовой или постоянной активации. Регистрация аккаунта без SIM-карты, в любом регионе. Удобно, надёжно, без привязки к оператору.
buy and sell accounts https://accounts-marketplace.xyz
buy account https://social-accounts-marketplaces.live
accounts marketplace https://accounts-marketplace.live
website for selling accounts https://social-accounts-marketplace.xyz
ноутбуки каталог цены купить ноутбук 17
покупка электроники интернет магазины электроника магазин купить
купить смартфон в москве купить смартфон 256 гб
verified accounts for sale accounts marketplace
accounts marketplace account marketplace
website for buying accounts https://buy-accounts.live
купить ноутбук леново ноутбуки каталог цены
marketplace for ready-made accounts accounts market
купить аккаунт https://rynok-akkauntov.top/
маркетплейс аккаунтов https://kupit-akkaunt.xyz/
¡Hola seguidores del azar !
Con un casino sin KYC puedes acceder desde tu paГs sin restricciones. No importa si estГЎ bloqueado por la DGOJ. AquГ mandas tГє.
Si quieres evitar lГmites geogrГЎficos, estos casinos son la clave. Accesibles desde cualquier IP. https://casinosinkyc.guru/
casino sin kyc sin lГmites ni registros — п»їhttps://casinosinkyc.guru/
¡Que tengas maravillosas logros sorprendentes !
биржа аккаунтов https://akkaunt-magazin.online
покупка аккаунтов https://akkaunty-optom.live
магазин аккаунтов online-akkaunty-magazin.xyz
Create vivid images with Promptchan AI — a powerful neural network for generating art based on text description. Support for SFW and NSFW modes, style customization, quick creation of visual content.
Недвижимость в Болгарии у моря https://byalahome.ru квартиры, дома, апартаменты в курортных городах. Продажа от застройщиков и собственников. Юридическое сопровождение, помощь в оформлении ВНЖ, консультации по инвестициям.
купить аккаунт https://kupit-akkaunt.online/
Срочный выкуп квартир https://proday-kvarti.ru за сутки — решим ваш жилищный или финансовый вопрос быстро. Гарантия законности сделки, юридическое сопровождение, помощь на всех этапах. Оценка — бесплатно, оформление — за наш счёт. Обращайтесь — мы всегда на связи и готовы выкупить квартиру.
buy facebook account https://buy-ad-accounts.click/
buy fb ad account facebook ads accounts
buy fb account https://buy-ads-account.click/
fb account for sale buy facebook ads account
facebook accounts for sale https://buy-ads-account.work
buy aged fb account https://ad-account-for-sale.top
buy a facebook account cheap facebook account
установка натяжных потолков https://natyazhnye-potolki-moskva1.ru
черный натяжной потолок сколько стоит натяжной потолок
buy a facebook ad account https://ad-accounts-for-sale.work/
buy google ads threshold account google ads reseller
buy verified google ads account https://buy-ads-accounts.click
buy old facebook account for ads https://buy-accounts.click
buy google ad threshold account https://ads-account-for-sale.top
google ads account seller https://ads-account-buy.work
рефераты на заказ сколько стоит написать реферат
buy google ads buy google ads threshold account
google ads reseller google ads agency account buy
buy google ads threshold accounts https://buy-ads-agency-account.top
buy verified google ads accounts https://ads-agency-account-buy.click
buy verified business manager buy-business-manager.org
buy old google ads account buy google ad threshold account
buy facebook business managers buy facebook ads accounts and business managers
buy fb bm buy-verified-business-manager.org
цена натяжного потолка за квадратный купить натяжной потолок
facebook bm buy https://business-manager-for-sale.org
buy facebook business account buy facebook business manager verified
verified bm for sale verified-business-manager-for-sale.org
buy tiktok ad account https://buy-tiktok-ads-account.org
обзорная экскурсия калининград где купить https://ehkskursii-v-kaliningrade.ru
buy tiktok business account https://tiktok-ads-account-for-sale.org
tiktok ads account for sale https://tiktok-agency-account-for-sale.org
tiktok agency account for sale https://buy-tiktok-ad-account.org
buy tiktok ads account https://buy-tiktok-ads-accounts.org
buy tiktok business account https://buy-tiktok-business-account.org
tiktok ads agency account https://buy-tiktok-ads.org
разработка сайтов минск цены разработка сайта магазина минск
изготовление шильдиков на заказ изготовление шильдов на заказ москва
изготовить шильдик на металле изготовление металлических шильдов
¡Saludos, aventureros de la fortuna !
Con solo unos clics puedes registrarte y comenzar a apostar. Muchos casinos incluso ofrecen bonos por hacerlo.
Mejores casinos online chile con plataformas confiables — https://www.youtube.com/watch?v=CRuk1wy6nA0&list=PLX0Xt4gdc3aJG7y03Wh5Qf0JrapCEgMFH
CГіmo cobrar ganancias en casinos online es una de las preguntas mГЎs comunes entre los jugadores. Es importante verificar tu cuenta y cumplir los requisitos de apuesta. Una vez hecho esto, puedes retirar fГЎcilmente.
¡Que disfrutes de ganancias sorprendentes !
seo сайта цена seo сайта цена москва
шильды из латуни изготовление шильдиков из металла
изготовление нагрудных бейджей сделать бейдж на заказ
значки из металла на заказ металлические значки москва
заказать seo продвижение сайтов москва
корпоративные значки на заказ https://izgotovit-znachki-metalicheskie.ru
типография производство типография заказ
типография полиграфия цифровая типография
стоимость печати визиток печать визиток спб
Нужна печать наклеек на заказ? Закажите стикеры любых форм и размеров с доставкой. Яркие, прочные, влагостойкие наклейки на пленке и бумаге — для рекламы, декора, маркировки и упаковки.
Профессиональная типография срочно. Изготовим любые печатные материалы — от визиток до каталогов. Качественно, быстро, с гарантией. Закажите онлайн или приезжайте в офис в СПб.
Профессиональная https://lazernaya-epilyaciya11.ru. Эффективное удаление волос на любом участке тела, подход к любому фототипу. Сертифицированные специалисты, стерильность, скидки. Запишитесь прямо сейчас!
https://biotpharm.shop/# Over the counter antibiotics pills
Безболезненная лазерная эпиляция удаление Удаление волос на любом участке тела. Работаем с чувствительной кожей, используем новейшие лазеры. Акции, абонементы, индивидуальный подход.
https://pharmau24.com/# Pharm Au 24
программное обеспечение компьютера лицензионное https://internet-magazin-soft.kz
Избавьтесь от волос сколько стоит лазерная эпиляция навсегда — с помощью лазерной эпиляции. Эффективные процедуры на любом участке тела, минимальный дискомфорт, заметный результат уже после первого сеанса.
Избавьтесь от волос лазерная эпиляция цена навсегда — с помощью лазерной эпиляции. Эффективные процедуры на любом участке тела, минимальный дискомфорт, заметный результат уже после первого сеанса.
медицинский центр абакан сайт медицинский центр
дерматолог абакан платный дерматолог
частная клиника клиника диагностика
https://eropharmfast.shop/# erectile dysfunction pills online
https://pharmau24.com/# Medications online Australia
http://pharmau24.com/# Online medication store Australia
https://eropharmfast.shop/# Ero Pharm Fast
http://pharmau24.com/# Medications online Australia
http://biotpharm.com/# get antibiotics without seeing a doctor
https://eropharmfast.shop/# ed online prescription
http://biotpharm.com/# buy antibiotics
https://eropharmfast.shop/# Ero Pharm Fast
https://eropharmfast.com/# low cost ed meds online
http://biotpharm.com/# buy antibiotics over the counter
https://eropharmfast.com/# order ed meds online
https://kampascher.shop/# kamagra en ligne
https://pharmsansordonnance.shop/# Pharmacie sans ordonnance
https://viasansordonnance.shop/# Viagra generique en pharmacie
https://viasansordonnance.com/# commander Viagra discretement
http://pharmsansordonnance.com/# Pharmacie en ligne livraison Europe
https://kampascher.com/# achat kamagra
http://viasansordonnance.com/# Viagra homme prix en pharmacie
http://ciasansordonnance.com/# acheter mГ©dicament en ligne sans ordonnance
https://kampascher.shop/# kamagra gel
http://ciasansordonnance.com/# Acheter Cialis
https://kampascher.shop/# acheter Kamagra sans ordonnance
http://pharmsansordonnance.com/# pharmacie en ligne fiable
https://viasansordonnance.shop/# acheter Viagra sans ordonnance
http://ciasansordonnance.com/# pharmacie en ligne avec ordonnance
http://ciasansordonnance.com/# commander Cialis en ligne sans prescription
http://pharmsansordonnance.com/# pharmacie en ligne france pas cher
http://ciasansordonnance.com/# Acheter Cialis 20 mg pas cher
https://viasansordonnance.com/# Acheter du Viagra sans ordonnance
https://pharmsansordonnance.shop/# pharmacie en ligne france fiable
http://pharmsansordonnance.com/# pharmacie en ligne livraison europe
https://pharmsansordonnance.com/# pharmacie en ligne france livraison belgique
https://kampascher.shop/# pharmacie en ligne france fiable
https://ciasansordonnance.shop/# cialis prix
Пролетни рокли в романтичен стил за разходки и срещи
дамски рокли дамски рокли .
http://farmaciasubito.com/# soldesam 4 mg fiale intramuscolo prezzo
https://pharmacieexpress.shop/# peut on acheter des antibiotiques sans ordonnance
https://farmaciasubito.shop/# menaderm simplex crema a cosa serve
https://farmaciasubito.shop/# enstilar schiuma prezzo
Дамски тениски с щампи и надписи, които подчертават стила ти през целия сезон
елегантни дамски тениски http://www.teniski-damski.com/ .
Инвестирай в качество с дълготрайни и стилни дамски блузи
официални дамски блузи https://bluzi-damski.com/ .
https://confiapharma.com/# venta productos farmacia online
https://pharmacieexpress.com/# fluocaril bi-fluorГ© 2500 ppm
Выбор фундамента и технологии при строительстве деревянного дома
построить деревянный дом под ключ https://www.stroitelstvo-derevyannyh-domov78.ru/ .
Услуги клининга с выездом в день обращения по доступной цене
услуги клининга в москве цены на услуги https://www.kliningovaya-kompaniya0.ru/ .
https://confiapharma.shop/# fortasec se puede comprar sin receta
Каталог шин с актуальными ценами и фото в онлайн-магазине
магазин шины http://www.kupit-shiny0-spb.ru .
https://pharmacieexpress.com/# hydrocortisone sans ordonnance
https://farmaciasubito.com/# oki bustine 80 mg prezzo
Сувенирная продукция с логотипом компании — производство под ключ
изготовление сувениров на заказ https://suvenirnaya-produktsiya-s-logotipom-1.ru .
https://confiapharma.com/# buscapina se puede comprar sin receta
resume for engineering internship no experience resume for engineering jobs
https://pharmacieexpress.com/# equivalent tramadol sans ordonnance
resume for engineering jobs resume backend engineer
https://pharmmex.shop/# mexican medicine names
https://inpharm24.shop/# cialis india pharmacy
Прогулки на яхте в Сочи: аренда с маршрутом под ваши желания
яхта аренда сочи https://www.arenda-yahty-sochi23.ru .
¡Hola, fanáticos de las apuestas en línea!
Esto puede ser Гєtil si usas billeteras extranjeras. Tienes mГЎs libertad financiera.
Casinos fuera de espaГ±a para jugar en vivo y ganar real — п»їhttps://casinofueradeespana.xyz/
Si te gusta el pГіker, fuera de EspaГ±a encontrarГЎs mГЎs variantes: chino, caribeГ±o, three card. Esto amplГa tu repertorio. Siempre hay algo nuevo por descubrir.
¡Que disfrutes de logros impresionantes !
https://pharmmex.com/# can you buy tramadol in mexico
http://pharmexpress24.com/# sildenafil citrate
https://pharmexpress24.com/# cialis pharmacy australia
http://pharmmex.com/# mexican drug stores
http://inpharm24.com/# e pharmacy india
http://pharmmex.com/# online pharmacy mexico
https://vgrsources.com/# generic viagra soft tabs
Сравнение кормов: почему Jarvi — лучший выбор для вашего питомца
jarvi корм отзывы http://www.ozon.ru/category/suhie-korma-dlya-koshek-12349/jarvi-elaman-100175853/review .
https://vgrsources.com/# viagra soft gel capsules
https://vgrsources.com/# viagra soft generic
https://vgrsources.com/# cheap viagra online uk
https://vgrsources.com/# sildenafil sale uk
https://vgrsources.com/# viagra price list
https://vgrsources.com/# sildenafil online canada
https://vgrsources.com/# viagra 1998
Уютные квартиры и дома у моря — отдых в Гаграх для всей семьи
снять жилье в гаграх otdyh-gagry.ru .
https://vgrsources.com/# best female viagra over the counter
Film izleme keyfini yeni boyuta taşıyan full hd film önerileri
hd film izle, https://www.filmizlehd.co .
https://vgrsources.com/# buy viagra australia
https://vgrsources.com/# femail viagra
https://vgrsources.com/# viagra price comparison canada
https://vgrsources.com/# female viagra pills in south africa
https://vgrsources.com/# cheap generic viagra
https://semaglupharm.com/# how to get semaglutide without insurance
https://lipipharm.com/# LipiPharm
https://semaglupharm.com/# Semaglu Pharm
https://semaglupharm.com/# Semaglu Pharm
https://prednipharm.shop/# PredniPharm
https://prednipharm.shop/# 10mg prednisone daily
http://lipipharm.com/# FDA-approved generic statins online
¡Hola, aventureros del azar !
Muchos casinos fuera de espaГ±a aceptan jugadores sin exigir residencia ni documentaciГіn nacional.Esto los hace accesibles desde cualquier parte del mundo, incluyendo EspaГ±a.Los mГ©todos de pago son variados y seguros.
El soporte suele estar disponible las 24 horas del dГa.
Casinos fuera de espaГ±a con mГ©todos de pago seguros — https://www.casinoporfuera.xyz/
¡Que disfrutes de premios extraordinarios
Алкоголь на заказ с доставкой — быстро, легально, удобно
алкоголь круглосуточно рядом со мной купить заказ алкоголя на дом москва круглосуточно .
https://crestorpharm.com/# ezetimibe rosuvastatin
https://crestorpharm.com/# Crestor Pharm
http://lipipharm.com/# LipiPharm
https://lipipharm.shop/# LipiPharm
https://semaglupharm.shop/# weight watchers semaglutide reviews
Лучшие подарочные наборы бокалов для вина в каталоге магазина
бокалы для вина 2 шт https://www.bokaly-dlya-vina.neocities.org .
https://lipipharm.com/# Lipi Pharm
https://crestorpharm.shop/# Crestor mail order USA
https://lipipharm.shop/# atorvastatin overdose amount
https://prednipharm.shop/# prednisone in canada
¡Bienvenidos, participantes del desafío !
Los lГmites de retiro en casinos extranjeros suelen ser mГЎs altos que en los nacionales.
ВЎRegГstrate ya en casinoextranjeros.es! — п»їhttps://casinoextranjeros.es/
Revisa casinosextranjerosespana.es para encontrar casinos que aceptan apuestas desde 0,10€. Esto permite jugar con presupuestos reducidos sin dejar de tener opciones divertidas. Accesibilidad total.
¡Que vivas asombrosas premios extraordinarios !
Императорский фарфор: изделия ручной работы с уникальным стилем
ифз imperatorskiy-farfor.kesug.com .
http://crestorpharm.com/# CrestorPharm