25 мая 2016
Кравченко Виктор

Arduino Uno: Датчик температуры и влажности DHT11 (DHT22)

Цифровые устройства Arduino Arduino Lang
01 На заметку:
У данной статьи есть видеоверсия!
Подписывайтесь на канал, чтобы быть в курсе обновлений!

02

В статье показывается работа с датчиком температуры и влажности DHT11 в модульном исполнении:

04

Отличие в исполнениях заключается лишь в том, что в модуле линия данных уже притянута подтягивающим резистором к линии питания:

05
Сопротивление на фото 5,1 кОм (512 — 51*10sup2/sup = 5100 Ом = 5,1 кОм)
Сопротивление на фото 5,1 кОм (512 — 51*102 = 5100 Ом = 5,1 кОм)
Даташиты: Может пригодиться:
06
07

А если использовать только датчик, то резистор придется устанавливать самостоятельно — номинал резистора 5 кОм:

08
09

И пусть вас не смущает тот факт, что у модуля 3 выходных пина, а у самостоятельного датчика 4 пина — один пин (на схеме NC) не используется.

10

В силу своей дешевизны он обладает невпечатляющими техническими характеристиками, и вполне пригоден в ознакомительных целях, либо проектах, непритязательных к прецизионности данных.

11

Датчики температуры и влажности DHT11 и DHT22 практически идентичны за исключением некоторых технических характеристик:

12
DHT11 DHT22
Измеряемый диапазон влажности (погрешность) 20-95% (±5%) 0-100% (±5%)
Измеряемый диапазон температуры (погрешность) 0°C — 50°C (±2°C) -40°C — 125°C (±2°C)
Частота опроса 1 раз/сек 0,5 раз/сек
Одинаковые характеристики
Рабочее напряжение 3,3 — 5,5 В
Максимально потребляемый ток 2.5 мА (в режиме передачи данных),
100 мкА (в режиме ожидания)
13

Как видно из таблицы более дорогой датчик DHT22 обладает улучшенными по сравнению с DHT11 характеристиками.

14

Взаимодействие с датчиком.

Процесс получения информации с датчика DHT11 очень прост и подробно описан в даташите (842 KB). Чтобы начать получать данные с датчика микроконтроллер должен отправить датчику запрос и дождаться ответа от датчика о том, что датчик готов передавать информацию. Происходит это следующим образом.

15

Когда микроконтроллер собрался принимать данные, он должен притянуть линию данных к нулю на 18 мс, и после отпустить её обратно к 1. Микроконтроллер переходит в режим ожидания и следит за тем, что происходит с линией данных. Через 20-40 мкс, если все в порядке, датчик отвечает притягиванием уже со своей стороны линии данных к нулю на 80 мкс, и отпускает её на 80 мкс. Таким образом датчик дает понять микроконтроллеру, что с ним все в порядке и он начинает передачу данных. Данные передаются побитно.

16
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) в начале, и с и % в конце. И для ещё большего удобства перевернем индикатор вверх ногами, чтобы точка (разделитель разрядов, который не используется из-за отображения целых чисел) была вверху и зажигалась, имитируя значок градуса:

25
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 в начале, и с и % в конце.

29
30

Код (будем использовать библиотеку dht11.zip (2,58 KB)):

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

Похожие запросы:

  • DHT11 temperature and humidity sensor
  • DHT11 /DHT22 Temperature Sensor
  • Чем отличаются датчики DHT11 и DHT22?
  • Датчики температуры и влажности DHT11 и DHT22 и Arduino
  • Подключение датчика температуры и влажности DHT11 и DHT22
  • Модуль DHT11 подключение к Arduino
  • Подключение датчика DHT11 к Arduino UNO
  • Выводим температуру и влажность помещения с датчика DHT11 на Arduino UNO
comments powered by HyperComments