Измерение температуры и влажности окружающего воздуха в настоящее время востребовано во многих проектах: системах умного дома, мониторинга окружающей среды, станциях погоды и т.д. Одним из самых популярных датчиков температуры является LM35, но он аналоговый, а в ряде случаев необходимо иметь цифровой датчик температуры – на эту роль отлично подходит датчик DHT11. В данной статье мы рассмотрим его подключение к микроконтроллеру PIC16F877A. Измеряемые значения температуры и влажности мы будем выводить на экран ЖК дисплея 16х2.
Также на нашем сайте мы рассматривали подключение датчика температуры и влажности DHT11 к другим микроконтроллерам (платам):
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Датчик температуры и влажности DHT11 (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Конденсаторы 33 пФ (2шт.) (купить на AliExpress).
- Резистор 4,7 кОм – 2 шт. (купить на AliExpress).
- Источник питания 5V 500mA.
- Макетная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Принципы работы датчика DHT11
Датчик DHT11 можно приобрести как в форме модуля, так и в форме датчика. Отличие между ними заключается лишь в том, что в форме модуля датчик содержит фильтрующий конденсатор и подтягивающий резистор, подключенные к выходному контакту датчика. Если же вы купили его в форме датчика, то их можно добавить внешним способом. Внешний вид датчика температуры и влажности DHT11 показан на следующем рисунке.
Датчик DHT11 поставляется в корпусе синего или белого цвета. Внутри корпуса находятся два компонента, которые используются для измерения температуры и влажности. Одним из этих компонентов является пара электродов – их электрическое сопротивление зависит от состояния влажного вещества, помещенного между ними. Таким образом, их сопротивление обратно пропорционально влажности окружающего воздуха. Чем больше относительная влажность, тем меньше значение сопротивления проводников, и наоборот. Но помните о том, что относительная влажность и фактическая влажность – это не одно и тоже. Относительная влажность показывает содержание воды в воздухе по отношению к его температуре.
Вторым компонентом датчика является терморезистор (термистор) NTC датчика. Термин NTC (Negative temperature coefficient) означает отрицательный температурный коэффициент, то есть повышение температуры приводит к уменьшению сопротивления терморезистора. Более подробно про принципы измерения температуры с помощью терморезистора можно прочитать в этой статье.
Выход датчика DHT11 откалиброван на его заводе изготовителе, поэтому нам в программе не стоит беспокоиться о его калибровке. На выход датчика информация передается по протоколу 1-Wire. Распиновка и схема подключения датчика DHT11 к микроконтроллеру показаны на следующем рисунке.
Всего у датчика DHT11 4 контакта. 1-й контакт (VDD) используется для подачи питания на датчик, 4-й контакт используется для подключения к общему проводу схемы/земле (GND). 2-й контакт является контактом данных, для его подключения необходим подтягивающий резистор сопротивлением 5 кОм, однако резисторы сопротивлением 4,7 и 10 кОм также подойдут. 3-й контакт датчика никуда не подключается – его мы просто игнорируем.
Технические характеристики датчика DHT11 можно узнать в даташите на него.
Как видно из представленной таблицы, датчик DHT11 может измерять температуру в диапазоне 0-50 градусов Цельсия с точностью +/- градуса и относительную влажность (RH) в диапазоне 20-90% с точностью +/- 5%RH. Более подробные технические характеристики датчика DHT11 приведены в следующей таблице.
Обмен данными с датчиком DHT11
Как уже было указано, для обмена данными между датчиком DHT11 и микроконтроллером PIC нам необходимо использовать протокол 1-Wire. Более детально эти процессы показаны на следующем рисунке.
Первым делом датчику DHT11 от микроконтроллера необходим сигнал начала передачи (start signal) чтобы начать процесс обмена данными. Этот сигнал начала передачи микроконтроллер должен передавать на датчик DHT11 каждый раз когда ему необходимо запросить данные температуры и влажности. После завершения этого сигнала датчик DHT11 передает сигнал ответа (response signal), который включает в себя информацию о температуре и влажности. Все данные передаются по одной линии (проводу). Полная длина данных составляет 40 бит, первыми передаются старшие биты.
Из-за наличия подтягивающего резистора уровень напряжения на линии данных всегда находится на уровне VCC в течение холостого/незанятого режима (idle mode). Микроконтроллеру необходимо опустить этот уровень напряжения с high до low на промежуток как минимум 18 мс. В течение этого времени датчик DHT11 обнаруживает сигнал начала передачи и микроконтроллер подает уровень high на линию на 20-40 мкс. Эти 20-40 мкс называются периодом ожидания, после которого датчик DHT11 начинает передачу данных.
Формат данных датчика DHT11
Данные датчика DHT11 состоят из десятичной и интегральной частей, объединенных вместе. Формат этих данных выглядит следующим образом:
1 |
8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit checksum. |
На приеме можно проверить корректность принятых данных с помощью проверки значения контрольной суммы (checksum value). В случае успешной передачи значение контрольной суммы должно представлять собой сумму слагаемых “8bit integral RH data+8bit decimal RHdata+8bit integral T data+8bit decimal T data”.
Схема проекта
Схема подключения датчика DHT11 к микроконтроллеру PIC16F877A представлена на следующем рисунке.
Внешний вид собранной конструкции проекта (без ЖК дисплея) показан на следующем рисунке.
После сборки программы и загрузки программы (ее код приведен далее) в микроконтроллер PIC вы можете приступить к тестированию работы проекта. Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Код программы мы разработали с помощью среды MPLABX IDE и скомпилировали ее с помощью компилятора XC8. Оба эти программных инструмента поставляются компанией Microchip совершенно бесплатно. Более подробно об их использовании вы можете прочитать в этой статье. Для работы с датчиком DHT11 нам необходимо будет запрограммировать следующие три функции:
1 2 3 |
void dht11_init(); void find_response(); char read_dht11(); |
Первая функция будет заключаться в подаче сигнала начала передачи (start signal) на датчик DHT11 – как мы рассматривали ранее, с него должен начинаться любой процесс обмена данными с датчиком DHT11. В этой функции нам сначала необходимо сконфигурировать контакт RD0 для работы на вывод данных. Затем на линию данных подается уровень low на время 18 мс. Затем на линию снова подается уровень high и в этом состоянии микроконтроллер удерживает данную линию в течение 30 мкс. После этого времени ожидания контакт RD0 конфигурируется в режим работы на ввод данных.
1 2 3 4 5 6 7 8 |
void dht11_init(){ DHT11_Data_Pin_Direction= 0; //Configure RD0 as output DHT11_Data_Pin = 0; //RD0 sends 0 to the sensor __delay_ms(18); DHT11_Data_Pin = 1; //RD0 sends 1 to the sensor __delay_us(30); DHT11_Data_Pin_Direction = 1; //Configure RD0 as input } |
Функция find_response() используется для установки бита проверки (check bit) в зависимости от состояния контакта данных. Это используется для обнаружения ответа от датчика DHT11.
1 2 3 4 5 6 7 8 9 10 |
void find_response(){ Check_bit = 0; __delay_us(40); if (DHT11_Data_Pin == 0){ __delay_us(80); if (DHT11_Data_Pin == 1){ Check_bit = 1; } __delay_us(50);} } |
И, наконец, в функции read_dht11() мы будем считывать данные от датчика в 8-битном формате с помощью операции сдвига.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
char read_dht11(){ char data, for_count; for(for_count = 0; for_count < 8; for_count++){ while(!DHT11_Data_Pin); __delay_us(30); if(DHT11_Data_Pin == 0){ data&= ~(1<<(7 - for_count)); //Clear bit (7-b) } else{ data|= (1 << (7 - for_count)); //Set bit (7-b) while(DHT11_Data_Pin); } } return data; } |
В основной функции программы main мы сначала будем вызывать функцию инициализации, в которой будет инициализироваться ЖК дисплей и режим работы контактов для обмена данными с ним будет устанавливаться на вывод данных. После этого мы будем считывать данные температуры и влажности с датчика DHT11 и выводить их на экран ЖК дисплея 16х2.
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 |
void main() { system_init(); while(1){ __delay_ms(800); dht11_init(); find_response(); if(Check_bit == 1){ RH_byte_1 = read_dht11(); RH_byte_2 = read_dht11(); Temp_byte_1 = read_dht11(); Temp_byte_2 = read_dht11(); Summation = read_dht11(); if(Summation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){ Humidity = Temp_byte_1; RH = RH_byte_1; lcd_com (0x80); lcd_puts("Temp: "); //lcd_puts(" "); lcd_data(48 + ((Humidity / 10) % 10)); lcd_data(48 + (Humidity % 10)); lcd_data(0xDF); lcd_puts("C "); lcd_com (0xC0); lcd_puts("Humidity: "); //lcd_puts(" "); lcd_data(48 + ((RH / 10) % 10)); lcd_data(48 + (RH % 10)); lcd_puts("% "); } else{ lcd_puts("Checksum error"); } } else { clear_screen(); lcd_com (0x80); lcd_puts("Error!!!"); lcd_com (0xC0); lcd_puts("No Response."); } __delay_ms(1000); } } |
Сначала в цикле мы будем подавать сигнал начала передачи данных на датчик, после этого вызывать функцию find_response. Если Check_bit равен 1, то начинается процесс считывания данных температуры и влажности с датчика.
Поскольку длина данных у нас составляет 40 бит, то функция read_dht11 будет вызываться 5 раз (5 раз х 8 бит = 40 бит). Считываемые данные будут сохраняться в соответствующих переменных. Также будет проверяться значение контрольной суммы (checksum) и при обнаружении ошибки передачи будет выводиться соответствующее сообщение на экран ЖК дисплея.
Исходный код программы
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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
#include <xc.h> #include <stdint.h> #include "supporing_cfile/lcd.h" #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) /* Program Flow related definition */ #define DHT11_Data_Pin PORTDbits.RD5 #define DHT11_Data_Pin_Direction TRISDbits.TRISD5 #define FIRST_LINE 0x80 #define SECOND_LINE 0xC0 #define _XTAL_FREQ 20000000 //20 Mhz unsigned char Check_bit, Temp_byte_1, Temp_byte_2, RH_byte_1, RH_byte_2; unsigned char Himudity, RH, Sumation ; //Dht11 related definition void dht11_init(); void find_response(); char read_dht11(); // System related definitions void system_init(void); void introduction_screen(void); void clear_screen(void); void main() { system_init(); while(1){ __delay_ms(800); dht11_init(); find_response(); if(Check_bit == 1){ RH_byte_1 = read_dht11(); RH_byte_2 = read_dht11(); Temp_byte_1 = read_dht11(); Temp_byte_2 = read_dht11(); Sumation = read_dht11(); if(Sumation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){ Himudity = Temp_byte_1; RH = RH_byte_1; lcd_com (0x80); lcd_puts("Temp: "); //lcd_puts(" "); lcd_data(48 + ((Himudity / 10) % 10)); lcd_data(48 + (Himudity % 10)); lcd_data(0xDF); lcd_puts("C "); lcd_com (0xC0); lcd_puts("Humidity: "); //lcd_puts(" "); lcd_data(48 + ((RH / 10) % 10)); lcd_data(48 + (RH % 10)); lcd_puts("% "); } else{ lcd_puts("Check sum error"); } } else { clear_screen(); lcd_com (0x80); lcd_puts("Error!!!"); lcd_com (0xC0); lcd_puts("No Response."); } __delay_ms(1000); } } /* * Функция для инициализации датчика dht11. */ void dht11_init(){ DHT11_Data_Pin_Direction= 0; //конфигурируем контакт RD0 на вывод данных DHT11_Data_Pin = 0; //RD0 подает 0 на датчик __delay_ms(18); DHT11_Data_Pin = 1; //RD0 подает 1 на датчик __delay_us(30); DHT11_Data_Pin_Direction = 1; // конфигурируем контакт RD0 на ввод данных } /* * Эта функция будет проверять работает ли датчик dht11 или нет */ void find_response(){ Check_bit = 0; __delay_us(40); if (DHT11_Data_Pin == 0){ __delay_us(80); if (DHT11_Data_Pin == 1){ Check_bit = 1; } __delay_us(50);} } /* Эта функция будет считывать данные с dht11. */ char read_dht11(){ char data, for_count; for(for_count = 0; for_count < 8; for_count++){ while(!DHT11_Data_Pin); __delay_us(30); if(DHT11_Data_Pin == 0){ data&= ~(1<<(7 - for_count)); //Clear bit (7-b) } else{ data|= (1 << (7 - for_count)); //Set bit (7-b) while(DHT11_Data_Pin); } //ждем пока на PORTD.F0 не будет уровень LOW } return data; } void system_init(){ TRISB = 0; // контакты для работы с ЖК дисплеем устанавливаются на вывод данных lcd_init(); introduction_screen(); //dht11_init(); } /* Функция для очистки экрана ЖК дисплея */ void clear_screen(void){ lcd_com(FIRST_LINE); lcd_puts(" "); lcd_com(SECOND_LINE); lcd_puts(" "); } /* Функция для вывода приветственного сообщения на экран ЖК дисплея */ void introduction_screen(void){ lcd_com(FIRST_LINE); lcd_puts("Welcome to"); lcd_com(SECOND_LINE); lcd_puts("circuit Digest"); __delay_ms(1000); __delay_ms(1000); clear_screen(); lcd_com(FIRST_LINE); lcd_puts("DHT11 Sensor"); lcd_com(SECOND_LINE); lcd_puts("with PIC16F877A"); __delay_ms(1000); __delay_ms(1000); } |