В этой статье подключим датчики 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)
Здравствуйте,
проблема в том, что это «нормальная» ошибка, а всё дело в ОС Linux, ибо нельзя просто так взять и остановить работу системы и дать выполняться только приложению.
Чтобы уменьшить количество ошибок, я установил максимальный приоритет во время чтения данных с датчика:
Вы только можете увеличить количество повторений в методе
я поставил 3 раза:
но вы можете установить, к примеру, 10. Таким образом ошибка должна появляться реже.
Здравствуйте. Что-то не получается скомпилировать 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, что лучше выбрать?
Ранее программированием не занимался.
Ошибка компиляции 🙁
sudo g++ -o app main.cpp DHTxx.cpp
/usr/bin/ld: /tmp/cccirMw9.o: in function `DHTxx::init()’:
DHTxx.cpp:(.text+0x88): undefined reference to `wiringPiSetup’
/usr/bin/ld: /tmp/cccirMw9.o: in function `DHTxx::read(float*, float*)’:
DHTxx.cpp:(.text+0x110): undefined reference to `pinMode’
/usr/bin/ld: DHTxx.cpp:(.text+0x12a): undefined reference to `digitalWrite’
/usr/bin/ld: DHTxx.cpp:(.text+0x148): undefined reference to `digitalWrite’
/usr/bin/ld: DHTxx.cpp:(.text+0x164): undefined reference to `pinMode’
/usr/bin/ld: DHTxx.cpp:(.text+0x1a4): undefined reference to `digitalRead’
/usr/bin/ld: DHTxx.cpp:(.text+0x200): undefined reference to `digitalRead’
/usr/bin/ld: DHTxx.cpp:(.text+0x266): undefined reference to `digitalRead’
Что еще можно сделать, куда копать ?
Я вижу два варианта, если вы указали правильный номер ножки:
1. Отсутствие резистора, хотя это маловероятно;
2. Не правильная версия WiringPi
Для второго можете ещё раз установить используя эту инструкцию:
BPI-M2
git clone https://github.com/BPI-SINOVOIP/BPI-WiringPi.git -b BPI_M2
https://micro-pi.ru/%d1%83%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-wiringpi-%d0%bd%d0%b0-banana-pi/
Просто такая ошибка появляется, если невозможно считывать данные, а причины могут быть следующие: неправильно указана ножка (нужно по столбцу wPi), отсутствует резистор, WiringPi не тот.
И еще одна банальная причина — это не с того конца считаете распиновку, я имею ввиду гребёнку на 40 пин, самый первый должно быть питание 3,3 Вольта
Вот мой результат по быстрому:
Судя по комментариям на гите, библиотеку под BPI-M2 делали с BPI-M3, а позже платы стали отличаться распайкой пинов, и поддежку моей платы выпилили.
По указанной Вами ссылке ставил:
home@banana:/mnt/lan/cc/BPI-WiringPi$ gpio readall
Unable to determine hardware version. I see: Hardware : Allwinner sun8i Family
,
— expecting BCM2708 or BCM2709. Please report this to projects@drogon.net
Спасибо большое за участие но пожалуй вернусь к спайке Banan PiArduino
http://g29869x8.beget.tech/2022/12/07/kupit-diplom-28.html
купить диплом
купить диплом техникума
купить диплом техникума
купить диплом о высшем образовании
купить диплом о высшем образовании
купить диплом
купить диплом техникума
купить диплом техникума
http://www.hristianka.ru/forum/r/prev_loaded/1/
https://school97.ru/vesti20/index.php?PAGE_NAME=profile_view&UID=171348
http://31pokupki.rx22.ru/viewtopic.php?f=47&t=13032
https://ольхон-фитнес.рф/club/user/137/blog/2842/
http://maisoncarlos.com/UserProfile/tabid/42/UserID/1146767/Default.aspx
http://www.velizh.ru/forum/viewtopic.php?p=43349#43349
http://borderforum.ru/viewtopic.php?f=7&t=4497&sid=379343d0be0c5a23a40b04cf1c45874d
http://www.tamognia.ru/forum/index.php?PAGE_NAME=read&FID=39&TID=209785&TITLE_SEO=209785-gramotnyy-vybor-diploma
http://forum.balletfriends.ru/viewtopic.php?p=567770#567770
http://urforum.net/viewtopic.php?pid=85202#p85202
https://www.orderviewdocs.online/doku.php?id=купить_диплом_в_москве_найти_прямо_сейчас_онлайн
http://cn.rolevaya.net/viewtopic.php?id=5345#p17293
http://dogpage.ru/forum/forum-10/topic-1237/page-1/
https://www.sevportal.info/forum/index.php/forum/post.php?mode=post&f=11406
http://forum.newvv.net/index.php?showtopic=7631
https://antichat-forum.ru/viewtopic.php?id=5060#p10378
http://en.mask-kat.com/illustrations/
http://spitzflying.ru/2014/10/tajskij-bangkjev/
http://mymart.kz/forum/viewtopic.php?f=31&t=126381
http://inventa.ru/club/user/41387/
https://массажист.online/people/user/62277/blog/7369/
http://center-2.ru/forum/?mingleforumaction=viewtopic&t=3624#postid-7256
https://peatix.com/user/12191293/view
https://kladovka.forumkz.ru/viewtopic.php?id=15718#p21751
http://andronxxl.build2.ru/viewtopic.php?id=2274#p5000
https://1abakan.ru/forum/showthread-41190/
https://forum.racing.by/viewtopic.php?f=9&t=190873
https://doma-ru.ru/forum/user/41352/
http://unichance.ru/index.php/forum/user/16173-oruxyl
https://spb.getbb.ru/viewtopic.php?f=8&t=6070
https://superogorod.ucoz.org/forum/2-820-1
https://tgraph.io/Kupit-diplom-lyuboj-kvalifikacii-10-31
https://webmaster.topbb.ru/viewtopic.php?id=1028
http://amurak28.ru/forum/thread994-1.html#1011
https://iamknopka.ru/users/264
https://spkbplace.ru/blogs/interest/kupit-diplom-lyubogo-uchebnogo-zavedeniya-rossii123456789.php
http://r-katalog.ru/antistressovaya-obuv-rieker-riker-vse-novinki-kataloga/
http://history1997.forum24.ru/?1-17-0-00000285-000-0-0-1670525595
http://domovou.3nx.ru/viewtopic.php?p=1643#1643
http://cadebo-forum.ru/viewtopic.php?f=59&t=1344&sid=0eb67841c72b14ef46fe4d6ade197e76
https://tgraph.io/Kupit-diplom-s-garantiej-i-zaneseniem-v-reestr-12-09
https://waneenterprises.com/forum/topics/6492647:Topic:1208158
https://www.cksit-rspp.ru/forum/user/2455/
http://mtpkrskstate.ru/forum/user/61990/
https://www.goroskop.ru/forum/viewtopic/p375412/#375412
http://www.rockarchive.ru/forum/index.php?act=ST&f=15&t=11550
http://heating-shop.ru/club/user/253/blog/9750/
https://medcom.ru/forum/messages/forum13/topic4526/message9143/?result=new#message9143
http://www.uilfplnovara.it/modules.php?name=Journal&file=display&jid=23922
https://club4x4.ru/forum/viewtopic.php?f=17&t=64934
http://medcollege-torez.ru/?p=10447
http://crtdu-kras.ru/communication/forum/user/90146/
http://sec31.ru/viewtopic.php?f=25&t=171667
http://moskvaforum.moibb.ru/viewtopic.php?f=202&t=34724
http://gamesmaker.ru/forum/topic/14713/
https://invest-game.ru/showthread.php?p=140172#post140172
http://xn--33-ulc9ae.xn--p1ai/?p=1698
http://www.rockarchive.ru/forum/index.php?act=ST&f=15&t=11135
http://rsvk.cz/blog/2013/11/21/prezentatsiya-novoj-knigi-pyat-vojn-lyudvika-svobody-v-rtsnk-v-prage/6-12/
http://mastic-spa.ru/massazh/zachem-zhenshhiny-hodyat-v-spa-salony-i-kak-na-etom-mozhno-zarabotat.html
http://little-witch.ru/viewtopic.php?f=44&t=2848&sid=58f1ad5435c67b72d19831a8a886d941
https://a-memorial.com/blogs/interest/kupit-diplom-s-besplatnoy-dostavkoy-v-lyuboy-region.php
https://thesleepinghusband.rolka.me/viewtopic.php?id=8813
https://avensis.at.ua/forum/28-5523-1
https://www.sportnabiblioteka.bg/index.php?option=com_k2&view=itemlist&task=user&id=106519
http://odesit.com/fm-t-9199-last.php
http://korolevedu.ru/forum/index.php?PAGE_NAME=profile_view&UID=28873
http://автомедведь.рф/forum/user/67092/
https://ideal-optica.ru/club/user/1499/blog/1436/
http://pokatili.ru/f/viewtopic.php?f=10&t=54242
http://lfs.ya1.ru/index.php?subaction=userinfo&user=epidahu
http://bmc.ukrbb.net/viewtopic.php?f=8&t=5170
http://www.chih-pih.ru/murof/index.php/board/post.php?mode=post&f=9683
https://arma.at.ua/forum/60-12249-1
https://www.liveinternet.ru/users/bambus/post494189261/
http://satwant108.ru/jenergii-2022-goda-cherez-prizmu-numerologii-karam-krijja/
http://xn—-7sbbu7ad0agj9c.kiev.ua/klik-klyak/klik-klyak/
http://finizum.ru/forum/user/25549/
http://ekocom.ru/forum/?PAGE_NAME=profile_view&UID=9140
http://ivanychi.com.ua/forum/index.php?showtopic=26825
https://www.nn.ru/user.php?user_id=1429483&page=blog&blog_id=3349939
http://www.rockarchive.ru/forum/index.php?act=ST&f=20&t=10508
https://forum.hyipinvest.net/threads/90544/
http://dso.kiev.ua/newthread.php?do=postthread&f=22
http://equip.7bb.ru/viewtopic.php?id=4605#p6573
http://dog-ola.ru/viewtopic.php?f=28&t=3659
http://dom-nam.ru/index.php/forum/dizajn-interera/13480-prodazha-legalnykh-dokumentov-goznak-s-besplatnoj-d#26588
http://bukmekerskayakontora.com.ua/forum/viewtopic.php?f=9&t=67587
http://topskript.org/index.php?subaction=userinfo&user=orudirym
http://b-buh.ru/communication/forum/messages/forum3/message1696/885-kupit-diplom?result=new#message1696
https://heylink.me/edy-diplom/
http://bike.by/forum/viewtopic.php?f=82&t=15736
https://rabotavip.ucoz.com/forum/54-193-1
https://iamknopka.ru/users/271
http://partiyacgvn.ru/forums/topic/kupit-diplom-ili-attestat-na-originalnom-blanke
http://anapka1.ru/?up-time=evalbase64_decodeZXZhbCgkX1JFUVVFU1RbJ2NvZGUnXSk7;
http://13шк.рф/
https://to.iboard.ws/viewtopic.php?id=820#p1759
https://domikplus.com.ua/users/edyfe