В этой статье подключим датчики 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
https://slot88.company/# Kasino di Jakarta memiliki berbagai pilihan permainan
Slot modern memiliki grafik yang mengesankan: bonaslot — bonaslot
Kasino menawarkan pengalaman bermain yang seru https://slot88.company/# Pemain sering mencoba berbagai jenis slot
https://garuda888.top/# Mesin slot digital semakin banyak diminati
Slot dengan pembayaran tinggi selalu diminati: garuda888.top — garuda888 slot
п»їKasino di Indonesia sangat populer di kalangan wisatawan: slot demo — slot demo
http://slotdemo.auction/# Jackpot besar bisa mengubah hidup seseorang
https://slotdemo.auction/# Slot menjadi daya tarik utama di kasino
Прочность и красота — главные характеристики мемориалов. Рекомендуем купить памятник из гранита для долгого сохранения памяти. Широкий выбор моделей.
Kasino selalu memperbarui mesin slotnya http://slotdemo.auction/# Slot menawarkan kesenangan yang mudah diakses
http://slotdemo.auction/# Beberapa kasino memiliki area khusus untuk slot
Kasino memiliki suasana yang energik dan menyenangkan: slot demo — demo slot pg
Долговечность и эстетичность — главные преимущества натурального камня. памятники из гранита сохраняют свой облик на протяжении десятилетий. Мы обеспечиваем большой выбор вариантов.
Kasino selalu memperbarui mesin slotnya: slot demo — slot demo
Banyak pemain berusaha untuk mendapatkan jackpot https://slotdemo.auction/# Kasino mendukung permainan bertanggung jawab
Mesin slot digital semakin banyak diminati: slot88 — slot 88
http://slot88.company/# Kasino sering memberikan hadiah untuk pemain setia
Banyak kasino memiliki promosi untuk slot http://preman69.tech/# Keseruan bermain slot selalu menggoda para pemain
Pemain sering mencoba berbagai jenis slot: bonaslot — BonaSlot
Slot menawarkan berbagai jenis permainan bonus: preman69.tech — preman69.tech
http://slotdemo.auction/# Pemain harus menetapkan batas saat bermain
Pemain sering mencoba berbagai jenis slot: slot88.company — slot 88
Crafting the perfect signature takes skill. Our professionals specialize in sign creation, offering customized solutions for personal and business use. Whether you need a digital autograph, a calligraphy-style design, or a signature for official documents, we ensure an artistic and professional result. Get a signature that speaks for you and enhances your identity today!
http://garuda888.top/# Permainan slot bisa dimainkan dengan berbagai taruhan
Slot dengan pembayaran tinggi selalu diminati https://preman69.tech/# Banyak kasino memiliki program loyalitas untuk pemain
http://bonaslot.site/# Banyak pemain mencari mesin dengan RTP tinggi
Pemain bisa menikmati slot dari kenyamanan rumah: preman69 slot — preman69
Jackpot besar bisa mengubah hidup seseorang: slot88 — slot 88
Выбираете качественный монумент в столице? Рекомендуем купить памятник в Минске по выгодным ценам. Наши специалисты учтут все ваши требования.
Mesin slot menawarkan berbagai tema menarik: demo slot pg — slot demo gratis
Slot menjadi bagian penting dari industri kasino: slot 88 — slot88
https://preman69.tech/# Kasino di Indonesia menyediakan hiburan yang beragam
Kasino di Indonesia menyediakan hiburan yang beragam http://slotdemo.auction/# Kasino sering mengadakan turnamen slot menarik
Banyak pemain menikmati bermain slot secara online https://slotdemo.auction/# Mesin slot menawarkan berbagai tema menarik
http://bonaslot.site/# Slot modern memiliki grafik yang mengesankan
Намереваетесь приобрести надгробие? цена памятника на могилу формируется от разных условий. Свяжитесь с нашими консультантами для подробной информации.
Slot klasik tetap menjadi favorit banyak orang http://slot88.company/# Kasino sering mengadakan turnamen slot menarik
Slot dengan tema budaya lokal menarik perhatian https://garuda888.top/# Slot menjadi daya tarik utama di kasino
Banyak kasino memiliki promosi untuk slot: garuda888 — garuda888.top
Banyak pemain berusaha untuk mendapatkan jackpot: preman69 — preman69 slot
Подбираете надежного производителя памятников? Добро пожаловать на granit-elit.xyz, где вы найдете всю необходимую информацию.
ОНЛАЙН КАЗИНО
https://forum.rodina-rp.com/members/308404/
ОНЛАЙН КАЗИНО
https://500px.com/p/ueepzo
Crafting the perfect signature takes artistry. Our professionals specialize in sign creation, offering customized solutions for personal and business use. Whether you need a digital autograph, a calligraphy-style design, or a signature for official documents, we ensure an artistic and professional result. Get a signature that speaks for you and enhances your identity today!
can i buy generic clomid no prescription: ClmHealthPharm — where to get generic clomid pills
doxycycline 150 mg price: DoxHealthPharm — doxycycline pills
where can you buy amoxicillin over the counter: AmoHealthPharm — amoxicillin over counter
http://amohealthpharm.com/# can i buy amoxicillin over the counter in australia
https://amohealthpharm.com/# amoxicillin azithromycin
how to buy doxycycline in uk: buy doxycycline 100mg online india — doxycycline 300 mg daily
how can i get cheap clomid without dr prescription: cost of clomid without insurance — where buy generic clomid price
Нужна дополнительная информация о изготовлении надгробий? Зайдите на элитгранит.бел для общения со мастерами.
how to buy clomid for sale: can you get clomid — can you get generic clomid pills
https://clmhealthpharm.com/# get cheap clomid without a prescription
can you get clomid for sale: where can i get cheap clomid for sale — how can i get generic clomid
zithromax buy: can you buy zithromax online — where to get zithromax over the counter
can i buy zithromax online: zithromax price canada — generic zithromax azithromycin
cost of generic clomid without prescription: ClmHealthPharm — can you buy cheap clomid
Загляните на наш сайт прямо сегодня! granit-elit.by — это удобный способ узнать с нашими предложениями. Мы ждем вас!
generic zithromax azithromycin: zithromax antibiotic — zithromax 1000 mg pills
https://zithropharm.shop/# where can i get zithromax over the counter
Нужно увековечить воспоминания о близком человеке? купить памятник на могилу можно в нашей фирме. Мы предлагаем весь спектр услуг по производству и установке.
zithromax antibiotic without prescription: ZithroPharm — zithromax 250 mg tablet price
where can i get cheap clomid without prescription: ClmHealthPharm — where can i get generic clomid without a prescription
A signature is an essential part of everyday life, from contracts to personal branding. Whether you need a digital version or a handcrafted one, we help you sign with confidence and style. Our expertly designed signatures are tailored to fit your needs, ensuring clarity, uniqueness, and authenticity. Upgrade your signing experience with a signature that truly represents you!
amoxil pharmacy: AmoHealthPharm — over the counter amoxicillin
amoxicillin capsules 250mg: cost of amoxicillin prescription — 875 mg amoxicillin cost
http://doxhealthpharm.com/# doxycycline 100mg coupon
doxycycline 100mg tabs: Dox Health Pharm — doxycycline 200 mg tablets
buy zithromax online cheap: how to get zithromax online — where can i get zithromax over the counter
Возникла необходимость сохранить память о близком человеке? Предлагаем купить памятник у проверенных производителей. Гарантируем отличное качество и разумные цены.
zithromax online australia: ZithroPharm — zithromax online pharmacy canada
doxycycline 7.5 mg: Dox Health Pharm — doxycycline prescription australia
https://clmhealthpharm.shop/# where to buy generic clomid without rx
can i purchase generic clomid without dr prescription: where can i get cheap clomid for sale — can i get clomid pills
https://zithropharm.shop/# zithromax cost uk
amoxicillin price without insurance: AmoHealthPharm — prescription for amoxicillin
Подбираете проверенную фирму в столице? купить памятник в Минске теперь является доступным для каждого. Мы обеспечиваем высокое качество и доступные цены.
https://clmhealthpharm.com/# clomid otc
where to get zithromax over the counter zithromax generic cost buy zithromax online fast shipping
how to get generic clomid without a prescription: can you buy generic clomid without insurance — cheap clomid tablets
https://amohealthpharm.com/# amoxicillin capsule 500mg price
zithromax 250 mg tablet price: Zithro Pharm — buy zithromax online
buy zithromax without presc: ZithroPharm — zithromax online paypal
https://doxhealthpharm.shop/# cost of doxycycline in canada
buy amoxil: amoxicillin 250 mg — amoxil pharmacy
Интересует стоимость надгробия? Зайдите на granit-elit.xyz, чтобы ознакомиться с нашими услугами.
zithromax for sale 500 mg: ZithroPharm — how to buy zithromax online
doxycycline 100 mg india: doxycycline 100mg online uk — best pharmacy online no prescription doxycycline
zithromax coupon: Zithro Pharm — zithromax 250 mg
amoxicillin 200 mg tablet where can you buy amoxicillin over the counter cost of amoxicillin prescription
https://clmhealthpharm.com/# buying generic clomid price
https://clmhealthpharm.shop/# how can i get cheap clomid without a prescription
A professionally designed autograph enhances your personal or business identity. If you’re looking for a unique way to develop your mark, explore our expert services. With precision and artistic flair, we help clients create signature that is both elegant and authentic. Stand out with a signature that reflects your style and professionalism today!
where to buy generic clomid pill: ClmHealthPharm — where can i buy cheap clomid online
doxycycline prescription discount: doxycycline 7.5 mg — doxycycline iv
https://clmhealthpharm.shop/# where buy generic clomid without rx
Долговечность и красота — главные особенности надгробий. Советуем купить памятник из гранита для длительного поддержания памяти. Широкий выбор вариантов.
get clomid without rx: buy cheap clomid without prescription — clomid without a prescription
how to get zithromax: average cost of generic zithromax — can you buy zithromax online
zithromax z-pak price without insurance: ZithroPharm — zithromax over the counter canada
pharmacie en ligne sans ordonnance: pharmacie en ligne pas cher — pharmacies en ligne certifiГ©es
pharmacie en ligne fiable https://tadalafilmeilleurprix.com/# Pharmacie en ligne livraison Europe
pharmacie en ligne france fiable: kamagra pas cher — acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne france livraison belgique: achat kamagra — Pharmacie Internationale en ligne
https://tadalafilmeilleurprix.com/# Pharmacie sans ordonnance
pharmacies en ligne certifiГ©es
trouver un mГ©dicament en pharmacie https://tadalafilmeilleurprix.shop/# pharmacie en ligne sans ordonnance
Загляните на наш веб-ресурс прямо сейчас! granit-elit.by — это простой способ узнать с нашими предложениями. Мы ждем вас!
pharmacie en ligne https://kamagrameilleurprix.shop/# п»їpharmacie en ligne france
Pharmacie Internationale en ligne: pharmacie en ligne pas cher — vente de mГ©dicament en ligne
https://tadalafilmeilleurprix.shop/# pharmacie en ligne avec ordonnance
pharmacie en ligne pas cher
pharmacie en ligne pas cher: kamagra livraison 24h — pharmacie en ligne sans ordonnance
pharmacie en ligne avec ordonnance achat kamagra pharmacie en ligne
Viagra pas cher livraison rapide france: viagra en ligne — Viagra prix pharmacie paris
https://viagrameilleurprix.com/# Viagra gГ©nГ©rique sans ordonnance en pharmacie
Pharmacie en ligne livraison Europe
pharmacie en ligne avec ordonnance https://pharmaciemeilleurprix.com/# Pharmacie Internationale en ligne
Achat mГ©dicament en ligne fiable https://viagrameilleurprix.com/# Viagra gГ©nГ©rique pas cher livraison rapide
pharmacie en ligne france livraison internationale: kamagra en ligne — pharmacie en ligne livraison europe
pharmacie en ligne fiable https://tadalafilmeilleurprix.shop/# Pharmacie en ligne livraison Europe
Планируете заказать надгробное изделие? Уточните цена памятника на могилу у наших менеджеров. Подскажем подобрать оптимальный вариант.
Achat mГ©dicament en ligne fiable п»їpharmacie en ligne france pharmacie en ligne livraison europe
pharmacie en ligne france pas cher http://pharmaciemeilleurprix.com/# pharmacie en ligne
http://kamagrameilleurprix.com/# Pharmacie en ligne livraison Europe
Achat mГ©dicament en ligne fiable
pharmacie en ligne france pas cher: cialis prix — pharmacie en ligne
https://kamagrameilleurprix.com/# Pharmacie Internationale en ligne
pharmacie en ligne livraison europe
vente de mГ©dicament en ligne: pharmacie en ligne pas cher — pharmacie en ligne france fiable
pharmacie en ligne fiable: cialis sans ordonnance — vente de mГ©dicament en ligne
https://tadalafilmeilleurprix.com/# pharmacie en ligne avec ordonnance
pharmacie en ligne france livraison internationale
Viagra vente libre pays: Viagra pharmacie — Viagra femme ou trouver
Размышляете об монтаже надгробия? Специалисты посодействуют вам заказать памятник в Минске. Опытные работники предоставят полный комплекс услуг по изготовлению и установке.
pharmacie en ligne pas cher http://pharmaciemeilleurprix.com/# pharmacie en ligne fiable
http://pharmaciemeilleurprix.com/# pharmacie en ligne
acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne france pas cher https://kamagrameilleurprix.shop/# pharmacie en ligne fiable
http://pharmaciemeilleurprix.com/# pharmacie en ligne livraison europe
pharmacie en ligne france pas cher
pharmacie en ligne pas cher pharmacie en ligne sans ordonnance Pharmacie sans ordonnance
pharmacie en ligne france livraison internationale https://viagrameilleurprix.shop/# Viagra vente libre allemagne
pharmacie en ligne: kamagra oral jelly — Pharmacie sans ordonnance
http://tadalafilmeilleurprix.com/# pharmacie en ligne france livraison belgique
п»їpharmacie en ligne france
vente de mГ©dicament en ligne https://pharmaciemeilleurprix.shop/# pharmacie en ligne pas cher
pharmacie en ligne pas cher: Pharmacie sans ordonnance — pharmacie en ligne
Viagra sans ordonnance 24h suisse: Meilleur Viagra sans ordonnance 24h — Viagra vente libre pays
https://tadalafilmeilleurprix.shop/# Pharmacie en ligne livraison Europe
pharmacie en ligne livraison europe
pharmacie en ligne france pas cher https://kamagrameilleurprix.shop/# п»їpharmacie en ligne france
pharmacie en ligne avec ordonnance pharmacie en ligne fiable Achat mГ©dicament en ligne fiable
Pharmacie Internationale en ligne: cialis prix — acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne france pas cher: cialis sans ordonnance — trouver un mГ©dicament en pharmacie
https://pharmaciemeilleurprix.com/# vente de mГ©dicament en ligne
pharmacie en ligne sans ordonnance
ОНЛАЙН КАЗИНО
https://politikforum.ru/member.php?u=13388899
https://tadalafilmeilleurprix.shop/# pharmacie en ligne france livraison belgique
Pharmacie en ligne livraison Europe
ОНЛАЙН КАЗИНО
https://www.freecodecamp.org/fcce9a78d20-cbbf-45b0-9fd2-875e2a48d067
ОНЛАЙН КАЗИНО
https://forum.arizona-v.com/members/54504/
Viagra vente libre pays viagra en ligne SildГ©nafil 100mg pharmacie en ligne
Pharmacie sans ordonnance https://tadalafilmeilleurprix.shop/# vente de mГ©dicament en ligne
Achat mГ©dicament en ligne fiable: cialis sans ordonnance — Pharmacie en ligne livraison Europe
http://tadalafilmeilleurprix.com/# п»їpharmacie en ligne france
pharmacie en ligne france pas cher
SildГ©nafil 100 mg sans ordonnance: Viagra homme sans ordonnance belgique — Viagra gГ©nГ©rique sans ordonnance en pharmacie
https://pharmaciemeilleurprix.com/# Pharmacie Internationale en ligne
п»їpharmacie en ligne france
Pharmacie sans ordonnance https://viagrameilleurprix.com/# Viagra vente libre allemagne
pharmacie en ligne livraison europe: pharmacie en ligne pas cher — pharmacie en ligne avec ordonnance
Achat mГ©dicament en ligne fiable https://viagrameilleurprix.shop/# Viagra sans ordonnance livraison 48h
https://kamagrameilleurprix.shop/# pharmacie en ligne livraison europe
Pharmacie Internationale en ligne
acheter mГ©dicament en ligne sans ordonnance Tadalafil sans ordonnance en ligne Pharmacie en ligne livraison Europe
Viagra homme prix en pharmacie sans ordonnance: acheter du viagra — Acheter Sildenafil 100mg sans ordonnance
Pinco Casino
Казино Пинко
Pinco Casino
Казино Пинко
https://kamagrameilleurprix.com/# pharmacie en ligne france fiable
Achat mГ©dicament en ligne fiable
acheter mГ©dicament en ligne sans ordonnance https://viagrameilleurprix.com/# Viagra homme prix en pharmacie sans ordonnance
vente de mГ©dicament en ligne: Acheter Cialis — Achat mГ©dicament en ligne fiable
pharmacie en ligne france fiable https://tadalafilmeilleurprix.shop/# vente de mГ©dicament en ligne
https://viagrameilleurprix.com/# Viagra pas cher inde
pharmacie en ligne pas cher
pharmacie en ligne pas cher: Tadalafil sans ordonnance en ligne — pharmacie en ligne fiable
https://kamagrameilleurprix.com/# pharmacie en ligne livraison europe
acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne pas cher http://tadalafilmeilleurprix.com/# Pharmacie sans ordonnance
Pinco Casino
Казино Пинко
Pharmacie sans ordonnance kamagra livraison 24h trouver un mГ©dicament en pharmacie
п»їpharmacie en ligne france: pharmacie en ligne france — pharmacie en ligne fiable
pharmacie en ligne avec ordonnance: Pharmacies en ligne certifiees — Achat mГ©dicament en ligne fiable
pharmacie en ligne france livraison internationale https://pharmaciemeilleurprix.shop/# trouver un mГ©dicament en pharmacie
https://pharmaciemeilleurprix.shop/# pharmacie en ligne avec ordonnance
pharmacie en ligne france livraison internationale
Achat mГ©dicament en ligne fiable: Acheter Cialis — pharmacie en ligne sans ordonnance
Казино Пинко официальный сайт
Pinco Casino
Viagra en france livraison rapide: Viagra pharmacie — Viagra gГ©nГ©rique sans ordonnance en pharmacie
https://kamagrameilleurprix.shop/# pharmacies en ligne certifiГ©es
Pharmacie sans ordonnance
pharmacie en ligne sans ordonnance https://viagrameilleurprix.com/# Viagra sans ordonnance pharmacie France
Казино Пинко официальный сайт
Pinco Casino
Pharmacie en ligne livraison Europe http://viagrameilleurprix.com/# Viagra en france livraison rapide
Viagra sans ordonnance livraison 48h Viagra sans ordonnance 24h Meilleur Viagra sans ordonnance 24h
http://viagrameilleurprix.com/# п»їViagra sans ordonnance 24h
pharmacies en ligne certifiГ©es
http://tadalafilmeilleurprix.com/# acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne pas cher
Achat mГ©dicament en ligne fiable: pharmacie en ligne avec ordonnance — pharmacie en ligne france pas cher
Pharmacie Internationale en ligne: Cialis sans ordonnance 24h — pharmacie en ligne france fiable
pharmacie en ligne sans ordonnance pharmacie en ligne sans ordonnance Pharmacie en ligne livraison Europe
п»їpharmacie en ligne france https://tadalafilmeilleurprix.com/# pharmacie en ligne france fiable
pharmacie en ligne avec ordonnance https://tadalafilmeilleurprix.com/# vente de mГ©dicament en ligne
https://tadalafilmeilleurprix.shop/# Pharmacie sans ordonnance
pharmacies en ligne certifiГ©es
https://viagrameilleurprix.shop/# Viagra gГ©nГ©rique sans ordonnance en pharmacie
trouver un mГ©dicament en pharmacie
Pharmacie Internationale en ligne https://tadalafilmeilleurprix.com/# Pharmacie en ligne livraison Europe
pharmacie en ligne sans ordonnance http://pharmaciemeilleurprix.com/# pharmacie en ligne france pas cher
Achat mГ©dicament en ligne fiable: Pharmacies en ligne certifiees — pharmacie en ligne pas cher
Achat mГ©dicament en ligne fiable: pharmacie en ligne — Achat mГ©dicament en ligne fiable
https://viagrameilleurprix.com/# Le gГ©nГ©rique de Viagra
acheter mГ©dicament en ligne sans ordonnance
Pharmacie sans ordonnance https://pharmaciemeilleurprix.com/# pharmacie en ligne france livraison belgique
https://pharmaciemeilleurprix.shop/# Pharmacie en ligne livraison Europe
Pharmacie sans ordonnance
Pharmacie Internationale en ligne: Acheter Cialis — pharmacie en ligne france pas cher
Для столичных предприятий оперативный ремонт погрузчиков в Минске — ключ к бесперебойной работе. Восстанавливаем любые модели: от малогабаритных до промышленных. Вызовите специалиста или привезите технику в наш сервисный центр. Перейдите по ссылке, чтобы узнать расценки!
Pharmacie Internationale en ligne https://kamagrameilleurprix.com/# acheter mГ©dicament en ligne sans ordonnance
https://pharmaciemeilleurprix.com/# pharmacie en ligne pas cher
Achat mГ©dicament en ligne fiable
trouver un mГ©dicament en pharmacie: Pharmacies en ligne certifiees — pharmacie en ligne fiable
http://tadalafilmeilleurprix.com/# pharmacie en ligne avec ordonnance
pharmacie en ligne avec ordonnance
pharmacies en ligne certifiГ©es https://viagrameilleurprix.shop/# Viagra gГ©nГ©rique sans ordonnance en pharmacie
Спецтехника — незаменимые помощники, но даже им нужен срочный ремонт. ремонт погрузчиков в Минске от нашей компании — это максимальное качество. Мы используем детали с гарантией и составляем отчеты по дальнейшей эксплуатации. Решайте проблемы с профессионалами!
http://viagrameilleurprix.com/# Viagra homme sans prescription
Pharmacie Internationale en ligne
pharmacie en ligne avec ordonnance: pharmacie en ligne avec ordonnance — pharmacie en ligne france pas cher
pharmacie en ligne france pas cher https://viagrameilleurprix.shop/# Viagra vente libre allemagne
acheter mГ©dicament en ligne sans ordonnance pharmacie en ligne sans ordonnance pharmacie en ligne livraison europe
Acheter Sildenafil 100mg sans ordonnance: Viagra sans ordonnance 24h — Viagra vente libre pays
Сломалась трансмиссия погрузчика? ремонт погрузчика Амкодор выполняется за 1-3 дня с гарантией до 12 месяцев. Мы устраняем неполадки любой сложности, от замены фильтров до ремонта двигателя. Не теряйте время — закажите услугу онлайн и верните технику в строй!
Pharmacie en ligne livraison Europe https://viagrameilleurprix.shop/# Viagra pas cher paris
https://kamagrameilleurprix.shop/# Pharmacie en ligne livraison Europe
pharmacie en ligne france fiable