Итоговый проект, часть 1: сборка датчиковой части

Всё готово для главного: соберём станцию мониторинга целиком. Сегодня — датчиковая часть: два датчика, скользящее окно и дашборд. На следующем занятии добавим пороговую сигнализацию и защитишь готовую станцию.

Станция мониторинга на макетной плате: датчик DHT22 и фоторезистор, подключённые к Arduino

После урока сможешь: собрать станцию из двух датчиков (температура/влажность и освещённость), вести скользящее окно температуры, выводить структурированный дашборд. Это первая половина итогового проекта.

Второй датчик: освещённость (LDR)

Добавь в Wokwi фоторезистор (LDR) — компонент, меняющий сопротивление в зависимости от света. Подключи его по схеме делителя напряжения: один конец LDR к 5V, второй — к A0 И одновременно к резистору 10 кОм, второй конец резистора — к GND. Без резистора-делителя изменение сопротивления LDR не превратится в измеримое изменение НАПРЯЖЕНИЯ на A0 — считывать было бы нечего. Дальше всё как с потенциометром: analogRead(A0) и map().

Делитель напряжения LDR: три провода к 5V, A0 и GND через резистор 10 кОм, схема делителя рядом
const int PIN_LDR = A0;

int svetSyroe = analogRead(PIN_LDR);
int svetProcent = map(svetSyroe, 0, 1023, 0, 100);

Честно: без калибровки под конкретный LDR это приближённый «процент освещённости», не точный люкс-метр — для учебной станции достаточно, но не выдавай его за точное измерение освещённости в реальном приборе.

Собираем датчиковую часть целиком

Соедини всё, что уже умеешь: DHT22 на пине 4, LDR на A0, скользящее окно из 5 последних температур (занятие 7), функции vyvestiPokazanie и sredneeMassiva (занятие 8), неблокирующий интервал 2000 мс (занятие 5, ограничение по датчику DHT22 из занятия 6).

#include <DHT.h>

#define PIN_DHT 4
DHT dht(PIN_DHT, DHT22);
const int PIN_LDR = A0;

const int RAZMER_OKNA = 5;
float oknoTemperatury[RAZMER_OKNA];
int indeksOkna = 0;

unsigned long previousMillis = 0;
const long interval = 2000;

void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) {
  Serial.print(nazvanie);
  Serial.print(": ");
  Serial.print(znachenie);
  Serial.println(edinitsa);
}

float sredneeMassiva(float arr[], int razmer) {
  float summa = 0;
  for (int i = 0; i < razmer; i = i + 1) {
    summa = summa + arr[i];
  }
  return summa / razmer;
}

void setup() {
  Serial.begin(9600);
  dht.begin();
  for (int i = 0; i < RAZMER_OKNA; i = i + 1) {
    oknoTemperatury[i] = 0;
  }
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    float temperatura = dht.readTemperature();
    if (!isnan(temperatura)) {
      oknoTemperatury[indeksOkna] = temperatura;
      indeksOkna = (indeksOkna + 1) % RAZMER_OKNA;
    }
    float srednyayaTemperatura = sredneeMassiva(oknoTemperatury, RAZMER_OKNA);

    int svetSyroe = analogRead(PIN_LDR);
    int svetProcent = map(svetSyroe, 0, 1023, 0, 100);

    vyvestiPokazanie("Температура", temperatura, " C");
    vyvestiPokazanie("Средняя температура", srednyayaTemperatura, " C");
    vyvestiPokazanie("Освещённость", svetProcent, " %");
    Serial.println("----------");
  }
}
  Датчиковая часть станции — что откуда:

  DHT22 (пин 4)  --> dht.readTemperature() --> окно (5) --> sredneeMassiva()
  LDR (A0)       --> analogRead() --> map() --> процент освещённости

  Всё собирается в дашборд через vyvestiPokazanie(), раз в 2000 мс (millis)

Миссия: собери и проверь датчиковую часть

Собери схему в Wokwi (DHT22 на пине 4, LDR с резистором-делителем на A0), вставь код выше, запусти и понаблюдай за дашбордом минимум 15-20 секунд (окно должно заполниться новыми показаниями). На следующем занятии добавим сигнализацию.

Проверь себя

Контрольный вопрос. Почему температуру и влажность (DHT22) читаем не чаще раз в 2000 мс, а освещённость (LDR) можно читать на каждом проходе loop()?

АLDR вообще не требует analogRead, поэтому его можно читать без ограничений
БУ DHT22 есть физическое ограничение на частоту опроса, а обычный аналоговый вход такого ограничения не имеет
ВНа самом деле оба датчика можно читать с любой частотой без разницы

Подсказка: Вспомни занятие про DHT22 — там разбиралось именно это ограничение.

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Контрольный вопрос. Зачем в один дашборд выводить и температуру, и среднюю температуру, и освещённость сразу?

АПотому что LMS требует минимум три строки вывода
БЧтобы видеть всю картину станции сразу, одним взглядом, без переключения между показаниями
ВЭто ускоряет работу программы

Подсказка: Подумай, зачем инженеру дашборд, а не отдельные разрозненные показания.

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Контрольный вопрос. analogRead(A0) для LDR вернул 511 (примерно половина диапазона). Что выведет map(511, 0, 1023, 0, 100)? Впиши число.

Подсказка: 511 — примерно половина от 1023. Половина выходного диапазона 0..100 — это сколько?

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Контрольный вопрос. Зачем в схеме с LDR нужен резистор-делитель (10 кОм между A0 и GND)?

АБез него изменение сопротивления LDR не превращается в измеримое изменение напряжения на A0
БРезистор нужен только для защиты платы от перегрузки по току
ВРезистор ускоряет считывание analogRead

Подсказка: Обратись к блоку «Второй датчик: освещённость (LDR)» — там объясняется назначение делителя.

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Контрольный вопрос. dht.readTemperature() провалился и вернул NaN на этом проходе. Что произойдёт с окном температур oknoTemperatury?

Исходный код для этого задания:

float temperatura = dht.readTemperature();
if (!isnan(temperatura)) {
  oknoTemperatury[indeksOkna] = temperatura;
  indeksOkna = (indeksOkna + 1) % RAZMER_OKNA;
}
Аобновится
Бне обновится

Подсказка: Условие внутри if — !isnan(temperatura) — истинно, только когда чтение УСПЕШНО.

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Задание. Напиши код сам. Допиши строку вместо ___, которая переводит сырое значение с LDR (0..1023) в проценты освещённости (0..100).

Исходный код для этого задания:

int svetSyroe = analogRead(PIN_LDR);
int svetProcent = ___;

Подсказка: Используй map() с теми же границами, что и в блоке «Второй датчик».

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Проверить ответ →

Реальная проверка — на нашей платформе, бесплатно и без регистрации. Открыть задачу и ввести ответ →

Задание. Напиши код сам (3 строки). Внутри неблокирующего блока, после успешного чтения temperatura (уже проверено !isnan), запиши её в окно oknoTemperatury на позицию indeksOkna и сдвинь indeksOkna по кругу (используй RAZMER_OKNA).

Исходный код для этого задания:

float temperatura = dht.readTemperature();
if (!isnan(temperatura)) {
  // напиши 2 строки: запись в окно и сдвиг индекса по кругу
}
float srednyayaTemperatura = sredneeMassiva(oknoTemperatury, RAZMER_OKNA);

Подсказка: Это тот же паттерн скользящего окна из занятия про массивы — запись по индексу, потом (indeksOkna + 1) % RAZMER_OKNA.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Представь гипотетическую ситуацию: в проекте завели ДВА независимых процесса с разными интервалами (например, LDR каждые 300 мс и дашборд каждые 2000 мс), но по ошибке использовали ОДНУ переменную previousMillis для обоих. Что произойдёт?

АНичего страшного, оба процесса будут работать независимо, как и задумано
БПроцессы будут мешать друг другу — обновление одного будет сбрасывать отсчёт времени для другого
ВПрограмма не соберётся — компилятор запретит одну переменную на два процесса

Подсказка: Вспомни занятие про millis(): у каждого независимого процесса должна быть СВОЯ переменная previousMillis.

Онлайн-проверка ответа появится позже

Задание. Мини-проект (часть датчикового ядра). Напиши функцию float minimumMassiva(float arr[], int razmer), которая находит наименьший элемент массива (по образцу maksimumMassiva из занятия про функции), и добавь в дашборд станции вызов vyvestiPokazanie(«Мин. температура», minimumMassiva(oknoTemperatury, RAZMER_OKNA), » C») сразу после строки со средней температурой. Принято, если: функция minimumMassiva находит именно наименьшее значение массива через цикл (без готовых функций min), и вызов добавлен в дашборд ПОСЛЕ строки «Средняя температура» с указанными аргументами.

Исходный код для этого задания:

// напиши функцию minimumMassiva и добавь вызов vyvestiPokazanie в дашборд по описанию выше

Подсказка: Функция — зеркало maksimumMassiva из занятия 8, только со знаком при сравнении; вызов — ещё одна строка vyvestiPokazanie сразу после существующей строки про среднюю температуру.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Задание. Мини-проект (часть датчикового ядра). По образцу minimumMassiva из предыдущего задания и maksimumMassiva из занятия про функции — добавь в дашборд станции строку с максимальной температурой по окну: вызов vyvestiPokazanie(«Макс. температура», maksimumMassiva(oknoTemperatury, RAZMER_OKNA), » C») сразу после строки с минимальной температурой. Принято, если: используется уже готовая (не переписанная заново) функция maksimumMassiva, и вызов добавлен в дашборд ПОСЛЕ строки «Мин. температура» с указанными аргументами.

Исходный код для этого задания:

// добавь вызов vyvestiPokazanie с maksimumMassiva в дашборд по описанию выше

Подсказка: Не нужно писать функцию заново — она уже есть с занятия про функции, нужен только новый вызов vyvestiPokazanie на новой строке дашборда.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Что дальше

Датчиковая часть готова: два датчика, скользящее окно, дашборд с минимумом/максимумом/средним. На следующем, последнем занятии добавим пороговую сигнализацию по этим показаниям и защитишь готовую станцию — объяснишь, как она работает.

Итог: у тебя собрана датчиковая часть станции — два датчика, скользящее окно, дашборд с агрегатами. Дальше — сигнализация и защита проекта.

Назад  ·  ↑ В начало урока  ·  ⌂ В начало курса  ·  Вперёд →

Школа Виктора Комлева