Все статьиHardware

Метеостанция на Arduino: температура, влажность, давление и освещённость

БА
Бексултан Айтен
CTO, Alashed
20 мая 2025 г.
9 мин чтения
Метеостанция на Arduino: температура, влажность, давление и освещённость

Собираем многофункциональную метеостанцию на Arduino с датчиками BMP280, DHT22 и фоторезистором. OLED-дисплей, переключение режимов кнопкой и полный код с объяснениями.

Введение

Профессиональные метеостанции стоят десятки тысяч рублей и содержат сложное оборудование. Однако четыре ключевых параметра окружающей среды -- температуру, влажность, атмосферное давление и уровень освещённости -- можно измерять недорогими датчиками, подключёнными к Arduino. Получается полноценная станция мониторинга окружающей среды, полезная и дома, и в школьной лаборатории.

В этом проекте мы соберём метеостанцию с тремя датчиками и OLED-дисплеем. DHT22 измеряет температуру и влажность воздуха, BMP280 -- атмосферное давление, а фоторезистор оценивает уровень освещённости. Кнопка переключает режимы отображения на экране: все данные сразу, только температура крупным шрифтом или график давления. Показания обновляются каждые 5 секунд. Проект рассчитан на учеников 7-10 классов.

Чему вы научитесь:

  • Подключать несколько I2C-устройств к одной шине
  • Работать с датчиками давления, влажности и освещённости
  • Выводить данные на графический OLED-дисплей
  • Переключать режимы отображения кнопкой
  • Использовать неблокирующие таймеры вместо delay

Необходимые компоненты

КомпонентКоличествоНазначение
Arduino Uno1Управляющий контроллер
Датчик BMP2801Измерение давления и температуры
Датчик DHT221Измерение влажности и температуры
Фоторезистор (LDR)1Измерение освещённости
Резистор 10 кОм2Делитель для фоторезистора + подтяжка DHT22
OLED-дисплей 0.96" 128x64 (I2C)1Отображение показаний
Тактовая кнопка1Переключение режимов
Макетная плата1Сборка схемы
Провода-перемычки12-15 шт.Соединение компонентов
USB-кабель1Питание и загрузка программы

Схема подключения

Набор компонентов метеостанции на Arduino
Набор компонентов метеостанции на Arduino

Шина I2C: BMP280 и OLED-дисплей

Оба устройства работают по протоколу I2C и подключаются к одним и тем же проводам, но имеют разные адреса. Arduino различает их по адресу при инициализации.

Общие линии I2C:

  • SDA -- пин A4 на Arduino Uno
  • SCL -- пин A5 на Arduino Uno

Подключение BMP280

  • VCC -- шина 3.3V (многие модули имеют стабилизатор и принимают 5V)
  • GND -- шина GND
  • SDA -- пин A4 (параллельно с OLED)
  • SCL -- пин A5 (параллельно с OLED)
  • I2C-адрес по умолчанию: 0x76 (иногда 0x77)

Подключение OLED 128x64

  • VCC -- шина 3.3V или 5V
  • GND -- шина GND
  • SDA -- пин A4
  • SCL -- пин A5
  • I2C-адрес по умолчанию: 0x3C

Подключение DHT22

  • VCC -- шина 5V
  • DATA -- пин D2
  • GND -- шина GND
  • Между VCC и DATA -- подтягивающий резистор 10 кОм (если нет на модуле)

Фоторезистор (делитель напряжения)

  • Один вывод фоторезистора -- к 5V
  • Другой вывод -- к пину A0 и через резистор 10 кОм к GND

Чем больше света падает на фоторезистор, тем ниже его сопротивление и тем выше напряжение на пине A0.

Кнопка переключения режимов

  • Один контакт -- к пину D3
  • Другой контакт -- к GND

Мы используем встроенный подтягивающий резистор Arduino (INPUT_PULLUP), поэтому внешний резистор не нужен.

Модуль датчика температуры для метеостанции
Модуль датчика температуры для метеостанции

Код программы

Установите библиотеки через менеджер библиотек Arduino IDE: Adafruit BMP280, Adafruit SSD1306, Adafruit GFX и DHT sensor library.

```cpp

// Метеостанция на Arduino

// Датчики: BMP280 + DHT22 + фоторезистор

// Дисплей: OLED 128x64

// Кнопка переключения режимов

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include <Adafruit_BMP280.h>

#include <DHT.h>

// Настройки OLED-дисплея

#define SCREEN_WIDTH 128

#define SCREEN_HEIGHT 64

#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Настройки датчиков

#define DHT_PIN 2

#define DHT_TYPE DHT22

#define LDR_PIN A0 // Фоторезистор на аналоговом входе

#define BUTTON_PIN 3 // Кнопка переключения режимов

DHT dht(DHT_PIN, DHT_TYPE);

Adafruit_BMP280 bmp;

// Интервал обновления показаний (мс)

#define UPDATE_INTERVAL 5000

unsigned long lastUpdate = 0;

// Текущий режим отображения (0, 1, 2)

int displayMode = 0;

bool lastButtonState = HIGH;

// Переменные для хранения показаний

float temperature = 0;

float humidity = 0;

float pressureMmHg = 0;

int lightLevel = 0;

void setup() {

Serial.begin(9600);

// Кнопка с внутренней подтяжкой

pinMode(BUTTON_PIN, INPUT_PULLUP);

// Инициализация OLED-дисплея

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

Serial.println("Ошибка: OLED не найден!");

while (true); // Останавливаемся при ошибке

}

// Заставка

display.clearDisplay();

display.setTextSize(1);

display.setTextColor(SSD1306_WHITE);

display.setCursor(15, 20);

display.println("METEOSTANTSIYA");

display.setCursor(25, 40);

display.println("Zapusk...");

display.display();

// Инициализация BMP280

if (!bmp.begin(0x76)) {

Serial.println("Ошибка: BMP280 не найден!");

Serial.println("Попробуйте адрес 0x77");

}

// Настройка BMP280 для метеонаблюдений

bmp.setSampling(

Adafruit_BMP280::MODE_NORMAL,

Adafruit_BMP280::SAMPLING_X2, // Температура: x2

Adafruit_BMP280::SAMPLING_X16, // Давление: x16 (максимальная точность)

Adafruit_BMP280::FILTER_X16, // Сглаживание: x16

Adafruit_BMP280::STANDBY_MS_500

);

// Инициализация DHT22

dht.begin();

delay(2000); // Даём датчикам прогреться

Serial.println("Метеостанция запущена!");

}

void loop() {

// Обработка нажатия кнопки

bool buttonState = digitalRead(BUTTON_PIN);

if (buttonState == LOW && lastButtonState == HIGH) {

// Кнопка нажата -- переключаем режим

displayMode = (displayMode + 1) % 3;

Serial.print("Режим: ");

Serial.println(displayMode);

delay(200); // Защита от дребезга

}

lastButtonState = buttonState;

// Обновляем показания каждые 5 секунд

unsigned long currentTime = millis();

if (currentTime - lastUpdate >= UPDATE_INTERVAL) {

lastUpdate = currentTime;

readSensors();

printToSerial();

}

// Обновляем дисплей при каждой итерации

// (для быстрой реакции на смену режима)

updateDisplay();

}

// Считывание данных со всех датчиков

void readSensors() {

// DHT22: влажность и температура

float h = dht.readHumidity();

float tDHT = dht.readTemperature();

// BMP280: давление и температура

float pressure = bmp.readPressure() / 100.0; // Паскали в гПа

float tBMP = bmp.readTemperature();

// Усредняем температуру с двух датчиков

if (isnan(tDHT)) {

temperature = tBMP;

} else {

temperature = (tDHT + tBMP) / 2.0;

}

// Влажность

humidity = isnan(h) ? 0 : h;

// Давление в мм ртутного столба

pressureMmHg = pressure * 0.750062;

// Освещённость (0-1023, пересчитываем в проценты)

lightLevel = map(analogRead(LDR_PIN), 0, 1023, 0, 100);

}

// Вывод данных в Serial Monitor

void printToSerial() {

Serial.print("Темп: ");

Serial.print(temperature, 1);

Serial.print("C | Влажн: ");

Serial.print(humidity, 1);

Serial.print("% | Давл: ");

Serial.print(pressureMmHg, 1);

Serial.print(" mmHg | Свет: ");

Serial.print(lightLevel);

Serial.println("%");

}

// Обновление дисплея в зависимости от текущего режима

void updateDisplay() {

display.clearDisplay();

switch (displayMode) {

case 0:

drawAllData(); // Все параметры на одном экране

break;

case 1:

drawBigTemp(); // Температура крупным шрифтом

break;

case 2:

drawLightMeter(); // Индикатор освещённости

break;

}

display.display();

}

// Режим 0: все данные компактно

void drawAllData() {

// Заголовок

display.setTextSize(1);

display.setCursor(10, 0);

display.println("= METEOSTANTSIYA =");

display.drawLine(0, 10, 127, 10, SSD1306_WHITE);

// Температура

display.setCursor(0, 14);

display.print("Temp: ");

display.print(temperature, 1);

display.print(" ");

display.print((char)247);

display.println("C");

// Влажность

display.setCursor(0, 26);

display.print("Vlazh: ");

display.print(humidity, 1);

display.println(" %");

// Давление

display.setCursor(0, 38);

display.print("Davl: ");

display.print(pressureMmHg, 0);

display.println(" mmHg");

// Освещённость

display.setCursor(0, 50);

display.print("Svet: ");

display.print(lightLevel);

display.println(" %");

}

// Режим 1: температура крупно

void drawBigTemp() {

display.setTextSize(1);

display.setCursor(30, 0);

display.println("TEMPERATURA");

display.drawLine(0, 10, 127, 10, SSD1306_WHITE);

// Крупная температура по центру

display.setTextSize(3);

display.setCursor(10, 22);

display.print(temperature, 1);

display.setTextSize(2);

display.print((char)247);

display.println("C");

// Мелким шрифтом -- влажность

display.setTextSize(1);

display.setCursor(20, 55);

display.print("Vlazhnost: ");

display.print(humidity, 0);

display.print("%");

}

// Режим 2: графический индикатор освещённости

void drawLightMeter() {

display.setTextSize(1);

display.setCursor(20, 0);

display.println("OSVESCHENNOST");

display.drawLine(0, 10, 127, 10, SSD1306_WHITE);

// Числовое значение

display.setTextSize(2);

display.setCursor(35, 16);

display.print(lightLevel);

display.println(" %");

// Графическая полоса-индикатор

display.drawRect(10, 40, 108, 16, SSD1306_WHITE);

int barWidth = map(lightLevel, 0, 100, 0, 104);

display.fillRect(12, 42, barWidth, 12, SSD1306_WHITE);

}

`

Разбор кода

Шина I2C и адресация. BMP280 и OLED подключены к одной паре проводов (A4/A5), но имеют разные адреса: дисплей откликается на 0x3C, а датчик давления -- на 0x76. Библиотеки автоматически адресуют запросы нужному устройству.

Два источника температуры. И BMP280, и DHT22 измеряют температуру. Мы усредняем их показания для повышения точности. Если один из датчиков недоступен, программа использует данные второго.

Фоторезистор и делитель напряжения. Фоторезистор образует делитель напряжения с постоянным резистором 10 кОм. Функция analogRead() возвращает значение 0-1023, которое мы пересчитываем в проценты через map(). Чем ярче свет, тем выше процент.

Единицы давления. BMP280 возвращает давление в паскалях. Мы делим на 100 для получения гектопаскалей, а затем умножаем на 0.750062 для перевода в миллиметры ртутного столба -- привычную единицу для повседневного использования.

Три режима отображения. Кнопка на пине D3 переключает режимы по кругу. Режим 0 показывает все параметры на одном экране. Режим 1 -- температуру крупным шрифтом с влажностью мелко внизу. Режим 2 -- графический индикатор освещённости с полосой-прогрессом.

Неблокирующие таймеры. Вместо delay(5000) мы используем millis() и проверку интервала. Это позволяет кнопке реагировать мгновенно, даже между обновлениями датчиков.

Возможные проблемы

  • BMP280 не обнаружен -- попробуйте адрес 0x77 вместо 0x76. Запустите скетч I2C Scanner для диагностики.
  • OLED показывает мусор -- убедитесь, что у вас дисплей на чипе SSD1306, а не SH1106 (для SH1106 нужна другая библиотека).
  • DHT22 возвращает NaN -- проверьте подтягивающий резистор и длину проводов (не более 20 см без экранировки).
  • Фоторезистор показывает 0 или 100 -- проверьте правильность делителя напряжения. Резистор 10 кОм должен быть между пином A0 и GND.

Советы для учителей

1. Калибровка освещённости. Значения фоторезистора зависят от конкретного экземпляра. Попросите учеников измерить значения при полной темноте и ярком свете, а затем подобрать диапазон в функции map().

2. Научный эксперимент. Подключите SD-карту и записывайте показания каждые 5 минут в течение суток. На следующем уроке постройте графики в Excel и обсудите зависимости: как меняется температура от освещённости? Как давление связано с погодой?

3. Прогноз погоды. Объясните ученикам, что быстрое падение давления (более 1 гПа за час) обычно предвещает ухудшение погоды. Предложите добавить простой алгоритм прогноза.

4. Расширение. Замените Arduino на ESP32, добавьте WiFi и публикуйте данные на платформу ThingSpeak для удалённого мониторинга.

Как Alashed помогает

Alashed Hardware предлагает наборы с датчиками BMP280, DHT22, OLED-дисплеями и фоторезисторами -- всё необходимое для сборки метеостанции в одной коробке. В Alashed CodeStudio учитель может подготовить шаблон проекта с пустыми функциями и раздать его ученикам, чтобы каждый самостоятельно реализовал считывание датчиков и отображение на экране, развивая навыки программирования поэтапно.

Попробуйте Alashed бесплатно

Подключите школу к пилоту. Генерируйте КМЖ за 2 минуты, ведите CodeStudio уроки, заказывайте оборудование — всё в одном месте.

Попробовать бесплатноДемо