В этой статье подключим датчики 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, что лучше выбрать?
Ранее программированием не занимался.
Ошибка компиляции 🙁
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’
Что еще можно сделать, куда копать ?
Судя по комментариям на гите, библиотеку под 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