Подключаем датчик температуры и влажности DHT22 к микроконтроллеру STM32f103.

В данном уроке мы напишем код для подключения датчика температуры и влажности 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 */

 

Запустив данную программу, Вы увидите данные:

Программный код