01 | На заметку: |
|
|
02 |
В статье показывается работа с датчиком температуры и влажности DHT11 в модульном исполнении: |
|
03 |
|
Проверено — автор рекомендует: http://ali.pub/n73p9 DHT11 на AliexpressВидео-инструкция о покупке со скидками на Aliexpress |
04 |
Отличие в исполнениях заключается лишь в том, что в модуле линия данных уже притянута подтягивающим резистором к линии питания: |
|
05 |
Сопротивление на фото 5,1 кОм (512 — 51*102 = 5100 Ом = 5,1 кОм)
|
Даташиты:
|
07 |
А если использовать только датчик, то резистор придется устанавливать самостоятельно — номинал резистора 5 кОм: |
|
09 |
И пусть вас не смущает тот факт, что у модуля 3 выходных пина, а у самостоятельного датчика 4 пина — один пин (на схеме NC) не используется. |
|
10 |
В силу своей дешевизны он обладает невпечатляющими техническими характеристиками, и вполне пригоден в ознакомительных целях, либо проектах, непритязательных к прецизионности данных. |
|
11 |
Датчики температуры и влажности DHT11 и DHT22 практически идентичны за исключением некоторых технических характеристик: |
|
12 |
|
|
13 |
Как видно из таблицы более дорогой датчик DHT22 обладает улучшенными по сравнению с DHT11 характеристиками. |
|
14 |
Взаимодействие с датчиком. Процесс получения информации с датчика DHT11 очень прост и подробно описан в даташите (842 KB). Чтобы начать получать данные с датчика микроконтроллер должен отправить датчику запрос и дождаться ответа от датчика о том, что датчик готов передавать информацию. Происходит это следующим образом. |
|
15 |
Когда микроконтроллер собрался принимать данные, он должен притянуть линию данных к нулю на 18 мс, и после отпустить её обратно к 1. Микроконтроллер переходит в режим ожидания и следит за тем, что происходит с линией данных. Через 20-40 мкс, если все в порядке, датчик отвечает притягиванием уже со своей стороны линии данных к нулю на 80 мкс, и отпускает её на 80 мкс. Таким образом датчик дает понять микроконтроллеру, что с ним все в порядке и он начинает передачу данных. Данные передаются побитно. |
|
17 |
Перед передачей каждого нового бита датчик притягивает линию данных к нулю на 50 мкс, после этого отпускает её к 1. В зависимости от того на сколько датчик отпускает дата-линию к 1 микроконтроллер распознает какой бит был передан. Если длительность временного промежутка до следующего притягивания к нулю — 26-28 мкс, то передан 0, если 70 мкс — передана 1. |
|
18 |
Передаваемые данные содержат как целую, так и дробную часть цифровых данных о температуре/влажности. Общий объем переданной информации составляет 40 бит: 1 и 2 байт содержат соответственно целую и дробную часть информации о влажности, 3 и 4 байт содержат целую и дробную часть информации о температуре и в 5 байте передается контрольная хеш-сумма, которая представляет из себя последние 8 бит от сложения предыдущих 4 байт. |
|
19 |
После передачи пакета данных датчик переходит в спящий режим, до следующего запроса со стороны микроконтроллера. |
|
20 |
Библиотека dht.h и принцип работы. Для того, чтобы понять устройство библиотек по работе с датчиком DHT11 — напишем свой фрагмент кода, который без библиотеки сможет получать данные с датчика. Код прокомментирован очень детально: |
|
21 | Arduino (C++) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 // Определяем флаги состояний
#define DHT_OK 0
#define DHT_ERROR_CHECKSUM -1 // Ошибка контрольной суммы
#define DHT_ERROR_TIMEOUT -2 // Ошибка таймаут
int pinData = 12;
// Объявляем переменные для хранения данных
int humidity; // Влажность
int temperature; // Температура
void setup() {
Serial.begin(9600);
}
void loop() {
int result = getTempDate(pinData);
if (result == DHT_OK) {
Serial.print("Temperature: "); Serial.print((int)temperature); Serial.print(" *C, ");
Serial.print("Humidity: "); Serial.print((int)humidity); Serial.print(" %");
Serial.println("");
}
else if (result == DHT_ERROR_CHECKSUM) {
Serial.println("Error data checksum");
}
else if (result == DHT_ERROR_TIMEOUT) {
Serial.println("Error data timeout");
}
delay(3000);
}
int getTempDate(int pin) {
String mydata = "";
byte data[40];
pinMode(pinData, OUTPUT); // Включаем режим управления линией данных
// Подаем сигнал датчику о том, что хотим получить данные
digitalWrite(pinData, LOW); // Притягиваем к нулю линию данных
delay(18); // Ждем 18 мс
digitalWrite(pinData, HIGH); // Отпускаем к единице
delayMicroseconds(40); // Ждем 40 мкс
pinMode(pinData, INPUT); // Переключаемся в режим приема и начинаем слушать
unsigned int timeoutInt = 10000; // Создаем переменную, отслеживающую таймаут
// Датчик должен притянуть линию данных к 0 и...
while (digitalRead(pin) == LOW)
if (timeoutInt-- == 0) return DHT_ERROR_TIMEOUT; // Если прошло 10000 итераций, а датчик не отреагировал, то ошибка!
// ... потом отпустить её
timeoutInt = 10000;
while (digitalRead(pin) == HIGH)
if (timeoutInt-- == 0) return DHT_ERROR_TIMEOUT;
// Если дошли до этого места, значит все нормально - начинаем принимать данные
// Нам нужно принять 40 бит
for (int i = 0; i < 40; i++)
{
timeoutInt = 10000;
// Датчик притянул линию данных к нулю, ждем, когда отпустит
while (digitalRead(pin) == LOW)
if (timeoutInt-- == 0) return DHT_ERROR_TIMEOUT;
// Засекаем, когда датчик отпустит линию данных к единице
unsigned long t = micros();
timeoutInt = 10000;
// Ждем когда датчик снова притянет линию данных к нулю
while (digitalRead(pin) == HIGH)
if (timeoutInt-- == 0) return DHT_ERROR_TIMEOUT;
// По интервалу определяем, какой бит был передан
// Если больше 40 (нам нужно 70 мкс) - значит 1, если меньше 40 (27 мкс) - значит 0
if ((micros() - t) > 40) data[i] = 1;
else data[i] = 0; // Инициализация нулевого значения
}
// Собираем байты из битов
byte bytes[5] = {0, 0, 0, 0, 0}; // Инициализируем байты для хранения полученных данных
int byteindex = 0; // Индекс байта
int posindex = 7; // Индекс бита в байте. Данные приходят в порядке: первым приходит старший бит
for (int i = 0; i < 40; i++) {
if (data[i] == 1) bytes[byteindex] |= (1 << posindex); // Задаем бит при помощи побитового ИЛИ
posindex--;
if (posindex < 0) {
posindex = 7;
byteindex++; // Переходим к следующему байту
}
}
uint8_t sum = bytes[0] + bytes[2];
// Проверяем контрольную сумму
if (bytes[4] != sum) return DHT_ERROR_CHECKSUM; // Контрольная сумма не совпадает - возвращаем ошибку
// Все проверки прошли нормально
// Присваиваем полученные данные переменным температуры и влажности
humidity = bytes[0];
temperature = bytes[2];
// Возвращаем положительный ответ
return DHT_OK;
} |
|
22 |
Библиотеку, реализующую схожий функционал можно скачать здесь — dht11.zip (2,58 KB) (источник http://playground.arduino.cc/Main/DHT11Lib). |
|
23 |
Подключение к устройствам вывода. Получать информацию мы научились, теперь эту информацию можно куда-либо вывести. Рассмотрим на примере 4-разрядного 7-сегментного идикатора 3641BS. |
|
24 |
Так как необходимо отображать данные и температуры и влажности, будем менять значения на дисплее, к примеру, каждые 2 сек. А поскольку значения обоих показателей не будет превышать 2 цифр, будем подставлять в начало и конец отображаемых данных символы, позволяющие их идентифицировать — t (temperature) и h (humidity) в начале, и с и % в конце. И для ещё большего удобства перевернем индикатор вверх ногами, чтобы точка (разделитель разрядов, который не используется из-за отображения целых чисел) была вверху и зажигалась, имитируя значок градуса: |
|
26 |
Добавим на схему из статьи Arduino UNO + 4-разрядный 7-сегментный индикатор (12 pin, 3641BS, red) датчик температуры и влажности DHT11. После сборки и загрузки скетча, не забудьте перевернуть дисплей на 180 градусов: |
|
27 |
Снова обращаю внимание, что если используется датчик на модуле, то резистор не нужен, и наоборот, если только датчик, то резистор обязателен!
|
Скетч для Fritzing — 4x7 Led _new 02_with_DHT11.fzz (69,0 KB)
|
28 |
Так как необходимо отображать данные и температуры и влажности, будем менять значения на дисплее каждые 2 сек. А поскольку значения обоих показателей не будет превышать 2 цифр, будем подставлять в начало и конец отображаемых данных символы, позволяющие их идентифицировать — t и h в начале, и с и % в конце. |
|
31 | Arduino (C++) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 #include <dht11.h>
dht11 DHT;
#define PIN_DATA 3
int anodPins[] = {A1, A2, A3, A4}; // Задаем пины для кажого разряда
int segmentsPins[] = {5, 6, 7, 8, 9, 10, 11, 12}; //Задаем пины для каждого сегмента (из 7 + 1(точка))
int state; // Переменная статуса запроса данных с датчика
unsigned long ms_mode = 0; // Счетчик для смены режима отображения
unsigned long ms_dht = 0; // Счетчик для обновления данных с датчика
void setup() {
for (int i = 0; i < 4; i++) pinMode(anodPins[i], OUTPUT);
for (int i = 0; i < 8; i++) pinMode(segmentsPins[i], OUTPUT);
//pinMode(pinIn, INPUT);
ms_mode = millis(); // Засекаем начало работы
ms_dht = millis(); // Засекаем начало работы
// Первый запрос данных сделаем отсюда
state = DHT.read(PIN_DATA);
getDigits(); // Получаем данные для отображения и записываем их в переменную arr[]
}
// Для экономии памяти будем хранить данные в байтах
//{A, B, C, D, E, F, G,DP} - дисплей перевернутый, поэтому все цифры перевернуты!
byte seg[15] = {
B11111100, //Цифра 0 не меняется
B00001100, //Цифра 1
B11011010, //Цифра 2 не меняется
B10011110, //Цифра 3
B00101110, //Цифра 4
B10110110, //Цифра 5 не меняется
B11110110, //Цифра 6 меняется с 9
B00011100, //Цифра 7
B11111110, //Цифра 8 не меняется
B10111110, //Цифра 9 меняется с 6
B11110001, //знак *C (Цельсия)
B11100010, //знак t
B00100100, //знак %
B01100110, //знак h
B00000000 //Пустой разряд
};
int err[4] = {
B00000000, //Пусто
B11110010, //E
B01000010, //r
B01000010, //r
};
static byte arr[4]; // Переменная-массив для хранения данных, которые не нужно каждый раз пересчитывать
int mode = 0; // Режим отображения данных 0-температура, 1-влажность
int changemodeperiod = 2000; // Период смены режимов, в мс. 1000 - смена каждую секунду
int refreshdataperiod = 10000; // Период обновления данных с датчика, в мс. 3000 - обновление каждые 3 секунды
void loop() {
// Блок смены режима отображения ==============================
if ((millis() - ms_mode) > changemodeperiod) {
ms_mode = millis(); // Обнуляем счетчик
mode = mode == 1 ? 0 : 1; // Меняем режим
// Блок обновления данных =====================================
// Лучше обновлять данные в момент переключения режима
if ((millis() - ms_dht) > refreshdataperiod) {
ms_dht = millis(); // Обнуляем счетчик
state = DHT.read(PIN_DATA);
}
getDigits(); // Получаем данные для отображения и записываем их в переменную arr[]
}
displayMessage(arr);
}
void getDigits () { // Получаем массив с данными для каждого индикатора
if (state == DHTLIB_OK) {
if (mode == 0) { //0-температура
arr[0] = seg[11]; arr[3] = seg[10];
arr[2] = seg[DHT.temperature % 10];
if (DHT.temperature > 9)
arr[1] = seg[(int)(DHT.temperature / 10)];
else arr[1] = seg[14];
arr[0] = seg[11]; arr[3] = seg[10];
}
else if (mode == 1) { // 1-влажность
arr[0] = seg[11]; arr[3] = seg[10];
arr[2] = seg[DHT.humidity % 10];
if (DHT.humidity > 9)
arr[1] = seg[(int)(DHT.humidity / 10)];
else arr[1] = seg[14];
arr[0] = seg[13]; arr[3] = seg[12];
}
}
else {
for (int i = 0; i < 4; i++)
arr[i] = err[i];
}
}
void displayMessage(byte dig[4]) {
for (int i = 0; i < 4; i++) { // Каждый разряд по очереди
//Serial.println(dig[4], BIN);
for (int k = 0; k < 8; k++) {// Каждый сегмент по очереди - исходя из заданной карты
digitalWrite(segmentsPins[k], ((bitRead(dig[i], 7 - k) == 1) ? LOW : HIGH));
}
digitalWrite(anodPins[3 - i], HIGH); // 3-i - при перевороте инвертируем порядок пинов
delay(1);
digitalWrite(anodPins[3 - i], LOW); // 3-i - при перевороте инвертируем порядок пинов
}
//Serial.println("==========");
} |
|
32 |
Демонстрация работы: |
|
33 |
Подписывайтесь на канал
, чтобы быть в курсе обновлений! |
|
34 |
Что почитать:
|
|
35 |
Похожие запросы:
|
|