В данном уроке мы напишем код для подключения датчика температуры и влажности DHT-22 (так же данный код подойдет и для датчика DTH-11) к нашему микроконтроллеру STM32f103:
Необходимую ножку для подключения датчика (DATA) настраиваем в программе как выход, подключать будем к выводу GPIOA12. Питание подаем 3,3В (Сам датчик может работать как с 3,3В так и 5В).
Алгоритм работы датчика:
Начала работы датчика начинается с импульса низкого уровня не менее 18ms. После необходимо отпустить шину (перейти в режим входа) и ждать ответ от датчика. Датчик в этот момент устанавливает низкий, а после высокий уровень длительностью каждого 80мкс. После этого датчик выдает 5 байтов в которых содержатся данные о влажности и температуре: сначала идет старший байт влажности, после младший байт, далее старший байт температуры и младший байт температуры и последний байт контрольная сумма. Полученные данные как температуры так и влажности необходимо поделить на 10. При измерении отрицательной температуры старший бит в первом байте температуры будет установлен в 1.
Биты данных передаются в виде последовательности логического нуля и единицы. Таким образом логический ноль представляет из себя последовательность низкого уровня 50мкс и высокого 27мкс, а логическая единица последовательность низкого уровня 50мкс и высокого 70 мкс.
Минимальное время чтения данных с датчика составляет 2 секунды.
Используя выше описанный алгоритм , напишем программный код (библиотеку):
Для проверки работы нашей программы мы выведем данные с датчика DHT22 используя функцию printf с Урока №15.
Программный код:
#include "DTH22.h" #include "stdio.h" #define lineDown() HAL_GPIO_WritePin(DHT_Port, DHT_Pin, GPIO_PIN_RESET) #define lineUp() HAL_GPIO_WritePin(DHT_Port, DHT_Pin, GPIO_PIN_SET) #define getLine() (HAL_GPIO_ReadPin(DHT_Port, DHT_Pin) == GPIO_PIN_SET) #define Delay(d) HAL_Delay(d) static void pinOutput(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; //По умолчанию на линии высокий уровень HAL_GPIO_WritePin(DHT_Port, DHT_Pin, GPIO_PIN_SET); //Настройка порта на выход GPIO_InitStruct.Pin = DHT_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; //Открытый сток #if DHT_PullUp == 1 GPIO_InitStruct.Pull = GPIO_PULLUP; //Подтяжка к питанию #else GPIO_InitStruct.Pull = GPIO_NOPULL; //Без подтяжки #endif GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //Высокая скорость работы порта HAL_GPIO_Init(DHT_Port, &GPIO_InitStruct); } static void pinInput(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; //Настройка порта на вход GPIO_InitStruct.Pin = DHT_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; #if DHT_PullUp == 1 GPIO_InitStruct.Pull = GPIO_PULLUP; //Подтяжка к питанию #else GPIO_InitStruct.Pull = GPIO_NOPULL; //Без подтяжки #endif HAL_GPIO_Init(DHT_Port, &GPIO_InitStruct); } DHT_data DHT_getData(DHT_type t) { DHT_data data = {0.0f, 0.0f}; /* Запрос данных у датчика */ //Перевод пина “на выход” pinOutput(); //Опускание линии данных на 15 мс lineDown(); Delay(15); //Подъём линии, перевод порта “на вход” lineUp(); pinInput(); /* Ожидание ответа от датчика */ uint16_t timeout = 0; //Ожидание спада while(getLine()) { timeout++; if (timeout > DHT_timeout) return data; } timeout = 0; //Ожидание подъёма while(!getLine()) { timeout++; if (timeout > DHT_timeout) return data; } timeout = 0; //Ожидание спада while(getLine()) { timeout++; if (timeout > DHT_timeout) return data; } /* Чтение ответа от датчика */ uint8_t rawData[5] = {0,0,0,0,0}; for(uint8_t a = 0; a < 5; a++) { for(uint8_t b = 7; b != 255; b--) { uint32_t hT = 0, lT = 0; //Пока линия в низком уровне, инкремент переменной lT while(!getLine()) lT++; //Пока линия в высоком уровне, инкремент переменной hT while(getLine()) hT++; //Если hT больше lT, то пришла единица if(hT > lT) rawData[a] |= (1<<b); } } /* Проверка целостности данных */ if((uint8_t)(rawData[0] + rawData[1] + rawData[2] + rawData[3]) == rawData[4]) { //Если контрольная сумма совпадает, то конвертация и возврат полученных значений if (t == DHT22) { data.hum = (float)(((uint16_t)rawData[0]<<8) | rawData[1])*0.1f; //Проверка на отрицательность температуры if(!(rawData[2] & (1<<7))) { data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*0.1f; } else { rawData[2] &= ~(1<<7); data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*-0.1f; } } if (t == DHT11) { data.hum = (float)rawData[0]; data.temp = (float)rawData[2];; } } return data; }
Заголовочный файл библиотеки DHT22
#ifndef __DHT22_H #define __DHT22_H #include "main.h" /* Структура возвращаемых датчиком данных */ typedef struct { float hum; float temp; } DHT_data; /* Тип используемого датчика */ typedef enum { DHT11, DHT22 } DHT_type; /* Настройки */ #define DHT_Port GPIOA //Группа линии данных #define DHT_Pin GPIO_PIN_12 //Пин линии данных #define DHT_PullUp 0 //Нужно ли включать внутреннюю подтяжку пина к питанию #define DHT_timeout 10000 //Количество итераций, после которых функция вернёт пустые значения /* Прототипы функций */ DHT_data DHT_getData(DHT_type t); //Получить данные с датчика #endif /* DHT22_H_ * /
/* DHT22_H_ */
Для проверки работы нашей программы мы выведем данные с датчика DHT22 используя функцию printf с Урока №15.
/* USER CODE BEGIN PTD */ char LCD_Char[4]={'0','0','0','0'}; /* USER CODE END PTD */ /* USER CODE BEGIN 0 */ void num_to_str(unsigned int value){ LCD_Char[3]=((value/1000)%10); LCD_Char[2]=((value/100)%10); LCD_Char[1]=((value/10)%10); LCD_Char[0]=(value%10); } /* USER CODE END 0 */ /* USER CODE BEGIN 3 */ DHT_data d = DHT_getData(DHT22); printf (" T = %f \r \n", d.temp); printf (" H = %f \r \n", d.hum); } /* USER CODE END 3 */
/* КОД ПОЛЬЗОВАТЕЛЯ КОНЕЦ 3 */
Запустив данную программу, Вы увидите данные:
Программный код