Модуль 8 — Финальный проект (курс для начинающих)
Цель модуля: применить все полученные знания и навыки для создания законченного проекта на Arduino, который включает как минимум один датчик, одно исполнительное устройство и систему вывода информации.
Задача
Необходимо собрать устройство, которое использует:
- Минимум 1 датчик (температуры, влажности, освещенности, движения и т.д.)
- Минимум 1 исполнительное устройство (светодиод, мотор, реле)
- Вывод информации (светодиоды или дисплей)
Возможные проекты
1. Мини-метеостанция
Датчик: DHT11 или DHT22 (температура и влажность)
Вывод информации: LCD 1602 или OLED дисплей
Исполнительное устройство: светодиод, загорающийся при превышении температуры
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
DHT dht(2, DHT11);
LiquidCrystal_I2C lcd(0x27, 16, 2);
int ledPin = 7;
void setup() {
dht.begin();
lcd.init();
lcd.backlight();
pinMode(ledPin, OUTPUT);
}
void loop() {
float t = dht.readTemperature();
float h = dht.readHumidity();
lcd.setCursor(0,0);
lcd.print("Temp: "); lcd.print(t); lcd.print("C");
lcd.setCursor(0,1);
lcd.print("Hum: "); lcd.print(h); lcd.print("%");
if (t > 28) digitalWrite(ledPin, HIGH);
else digitalWrite(ledPin, LOW);
delay(2000);
}
2. Автоматическая кормушка
Идея: устройство раз в заданное время открывает крышку кормового отсека с помощью сервопривода. DS3231 отвечает за точное время, LED или LCD показывает статус и ближайшую кормёжку.
Комплектующие
| Компонент | Примечание |
|---|---|
| Arduino Uno/Nano | Контроллер |
| RTC DS3231 (I2C) | Точные часы; адрес I2C обычно 0x68 |
| Сервопривод SG90/МG90S | Открывание крышки/заслонки |
| LED + резистор 220–330 Ω | Индикация выдачи |
| (Опционально) LCD 1602 I2C | Вывод времени и статуса |
| Отдельный БП 5 В ≥ 1 А | Питание сервопривода (общая земля!) |
| Провода, макетная плата, крепёж | Монтаж |
Подключение
- DS3231: VCC → 5V, GND → GND, SDA → A4, SCL → A5 (для Uno/Nano).
- Сервопривод: красный → +5V БП, коричневый/чёрный → GND (общий с Arduino), оранжевый/жёлтый (сигнал) → D9.
- LED: через резистор к D7, второй вывод на GND.
- LCD 1602 I2C (опц.): VCC → 5V, GND → GND, SDA → A4, SCL → A5.
Важно: питание сервопривода — от отдельного 5В‑источника. GND БП сервопривода и GND Arduino должны быть соединены.
Логика работы
- На старте устройство считывает текущее время с DS3231.
- В массиве заданы несколько ежедневных кормёжек (например, 08:00 и 19:30).
- Каждую минуту устройство сравнивает время; при совпадении:
- включается LED-индикация,
- серво плавно открывает заслонку, выдерживает паузу, закрывает,
- на LCD обновляется «След. кормёжка».
Скетч Arduino
#include <Wire.h>
#include <RTClib.h> // библиотека для DS3231
#include <Servo.h>
#include <LiquidCrystal_I2C.h> // закомментируйте, если без дисплея
// ===== НАСТРОЙКИ =====
const int SERVO_PIN = 9;
const int LED_PIN = 7;
const int OPEN_ANGLE = 100; // угол открытия заслонки
const int CLOSE_ANGLE = 0; // угол закрытия
const int OPEN_MS = 1500; // сколько держать открытой, мс
// Время кормёжек (24-часовой формат)
const uint8_t FEEDS = 2;
uint8_t feedHour[FEEDS] = {8, 19};
uint8_t feedMinute[FEEDS] = {0, 30};
// ===== ОБЪЕКТЫ =====
RTC_DS3231 rtc;
Servo gate;
LiquidCrystal_I2C lcd(0x27, 16, 2); // если без LCD, закомментируйте все строки с lcd
// Чтобы не кормить дважды в одну минуту
bool fedThisMinute[FEEDS] = {false, false};
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
gate.attach(SERVO_PIN);
gate.write(CLOSE_ANGLE);
Wire.begin();
rtc.begin();
// *** Однократно раскомментируйте для установки времени по ПК:
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
lcd.init(); lcd.backlight();
lcd.setCursor(0,0); lcd.print("Auto Feeder");
lcd.setCursor(0,1); lcd.print("Init...");
delay(800);
updateNextFeedOnLCD();
}
void loop() {
DateTime now = rtc.now();
// Сброс маркеров "кормление было в минуту X" при смене минуты
static int lastMinute = -1;
if (now.minute() != lastMinute) {
lastMinute = now.minute();
for (uint8_t i = 0; i < FEEDS; i++) fedThisMinute[i] = false;
updateNextFeedOnLCD(now); // реже обновляем LCD
}
// Проверка расписания (точность до минуты)
for (uint8_t i = 0; i < FEEDS; i++) {
if (!fedThisMinute[i] &&
now.hour() == feedHour[i] &&
now.minute() == feedMinute[i]) {
performFeeding(i);
fedThisMinute[i] = true;
}
}
delay(200); // экономим CPU, достаточно опроса несколько раз в секунду
}
void performFeeding(uint8_t idx) {
// Индикация
digitalWrite(LED_PIN, HIGH);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Feeding #"); lcd.print(idx+1);
lcd.setCursor(0,1); lcd.print("Opening...");
// Плавное открытие
for (int a = CLOSE_ANGLE; a <= OPEN_ANGLE; a += 3) {
gate.write(a);
delay(15);
}
delay(OPEN_MS);
// Плавное закрытие
for (int a = OPEN_ANGLE; a >= CLOSE_ANGLE; a -= 3) {
gate.write(a);
delay(15);
}
digitalWrite(LED_PIN, LOW);
updateNextFeedOnLCD(); // показать следующее время
}
void updateNextFeedOnLCD() {
updateNextFeedOnLCD(rtc.now());
}
void updateNextFeedOnLCD(const DateTime &now) {
// Найти ближайшую будущую кормёжку
int best = -1;
long bestDelta = 24L*60L + 1;
long curMin = now.hour()*60L + now.minute();
for (uint8_t i = 0; i < FEEDS; i++) {
long t = feedHour[i]*60L + feedMinute[i];
long delta = t - curMin;
if (delta < 0) delta += 24L*60L; // на следующий день
if (delta < bestDelta) { bestDelta = delta; best = i; }
}
char buf[6];
sprintf(buf, "%02d:%02d", feedHour[best], feedMinute[best]);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Next feed:");
lcd.setCursor(0,1); lcd.print(buf);
}
Как изменить расписание
Вверху скетча отредактируйте массивы feedHour[] и feedMinute[]. Количество кормёжек задаётся константой FEEDS. Например, три раза в день: 07:30, 13:00, 21:15.
Механика и калибровка
- Используйте заслонку/шибер с минимальным трением. Для тяжёлых заслонок лучше сервопривод металлизированный (MG90S) или редукторный.
- Подберите углы
OPEN_ANGLE/CLOSE_ANGLEтак, чтобы отверстие открывалось полностью, но серво не упирался в ограничители. - При первой настройке уменьшайте
OPEN_MSи постепенно увеличивайте до нужной порции корма.
Безопасность и надёжность
- Сервопривод запитывайте от отдельного 5В блока ≥ 1 А. Обязательно общий GND с Arduino.
- Провода питания серво делайте короткими и толстыми; при длинных — добавьте электролит 470–1000 мкФ у серво.
- Продумайте «ручной режим»: дополнительная кнопка на пине D4 может вызывать
performFeeding()для тестов. - Защитите механизм от заклинивания: лёгкая пружина на закрытие уменьшит нагрузку на серво.
Типичные ошибки
- Дёргается дисплей/перезагрузка Arduino: недостаток тока у БП, общая линия 5 В для серво и платы — разнесите питание, соедините только GND.
- Время «плавает»: не инициализирован DS3231. Однократно раскомментируйте строку
rtc.adjust(...)вsetup()для установки времени. - Серво не движется: перепутан сигнальный провод, неверный пин, неверные углы.
Расширения
- Меню на LCD для изменения времени без перепрошивки (кнопки «вверх/вниз/ок» на A1–A3).
- Логика «кормить N грамм»: ставим весовой датчик HX711 и подбираем длительность открытия до целевого веса.
- Уведомления в Telegram/MQTT при выдаче корма (ESP8266/ESP32).
3. Сигнализация на движение
Идея: при обнаружении движения PIR‑датчиком (например, HC‑SR501) устройство включает сирену (или лампу через реле), мигает светодиодом и выводит предупреждение на дисплей.
Комплектующие
| Компонент | Назначение / примечание |
|---|---|
| Arduino Uno/Nano | Контроллер системы |
| PIR HC‑SR501 | Выход OUT — цифровой сигнал HIGH при движении; на плате есть регуляторы чувствительности и времени удержания |
| Модуль реле 5 В | Управление лампой/сиреной. Лучше взять реле‑модуль с оптронами |
| Светодиод + резистор 220–330 Ω | Индикация тревоги |
| (Опц.) LCD 1602 I2C | Текстовые сообщения: «Охрана», «Движение», «Тревога» |
| БЗ 5 В ≥ 1 А | Стабильное питание, общая земля для всех модулей |
| Провода, макетная плата/корпус | Монтаж та безопасное размещение |
Схема подключения
- PIR: VCC → 5V, GND → GND, OUT → D2.
- Реле: IN → D8, VCC → 5V, GND → GND. НО/НЗ контакты реле подключаются к вашей нагрузке (сирена/лампа). С сетевым напряжением работайте только при наличии навыков и соблюдая ПУЭ!
- LED: через резистор к D13 (или другой пин), второй вывод → GND.
- LCD 1602 I2C (опц.): VCC → 5V, GND → GND, SDA → A4, SCL → A5.
Совет: на PIR‑модуле выставьте режим H (повторный) для стабильной работы тревоги и подберите регуляторами чувствительность и время удержания.
Логика работы
- Система имеет два состояния: Охрана включена (ARMED) и выключена (DISARMED). Для простоты стартуем в ARMED.
- Фиксация движения (OUT=HIGH) → задержка фильтрации (дребезг/ложные) → Тревога: включить реле/сирену, мигать LED, показать предупреждение.
- После тревоги — охлаждение (cooldown), чтобы не «дребезжать» тревогами подряд.
- (Опц.) Кнопкой можно переключать ARMED/DISARMED; здесь опустим для краткости.
Базовый скетч (с поддержкой LCD по флагу)
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // если дисплея нет, установите USE_LCD false
// ====== НАСТРОЙКИ ======
const bool USE_LCD = true; // поставить false, если LCD нет
const uint8_t PIR_PIN = 2; // вход PIR
const uint8_t RELAY_PIN = 8; // выход на реле
const uint8_t LED_PIN = 13; // индикация тревоги
// задержки, мс
const unsigned long TRIGGER_FILTER_MS = 80; // антиложный фильтр
const unsigned long ALARM_DURATION_MS = 10000; // длительность тревоги
const unsigned long COOLDOWN_MS = 5000; // пауза после тревоги
LiquidCrystal_I2C lcd(0x27, 16, 2);
enum State { ARMED, ALARM, COOLDOWN };
State state = ARMED;
unsigned long tState = 0; // таймер текущего состояния
unsigned long tMotionStart = 0; // таймер подтверждения движения
void lcdInitIfUsed() {
if (!USE_LCD) return;
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0); lcd.print("PIR Security");
lcd.setCursor(0,1); lcd.print("ARMED");
}
void lcdShow(const char* l1, const char* l2) {
if (!USE_LCD) return;
lcd.clear();
lcd.setCursor(0,0); lcd.print(l1);
lcd.setCursor(0,1); lcd.print(l2);
}
void setup() {
pinMode(PIR_PIN, INPUT); // у HC-SR501 уже своя подтяжка
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
lcdInitIfUsed();
}
void loop() {
bool motion = digitalRead(PIR_PIN) == HIGH;
unsigned long now = millis();
switch (state) {
case ARMED:
if (motion) {
if (tMotionStart == 0) tMotionStart = now;
// подтверждаем движение по истечении фильтра
if (now - tMotionStart >= TRIGGER_FILTER_MS) {
// Тревога
digitalWrite(RELAY_PIN, HIGH); // включить сирену/лампу
lcdShow("ALARM!", "Motion detect"); // текст
tState = now;
state = ALARM;
}
} else {
tMotionStart = 0;
// моргаем LED редким миганием — "охрана активна"
digitalWrite(LED_PIN, (now/500)%2);
if (USE_LCD && (now/2000)%2==0) lcdShow("ARMED", "Waiting motion");
}
break;
case ALARM:
// быстрое мигание LED во время тревоги
digitalWrite(LED_PIN, (now/150)%2);
if (now - tState >= ALARM_DURATION_MS) {
// Выключить сирену/лампу и перейти в охлаждение
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
lcdShow("COOLDOWN", "Please wait...");
tState = now;
state = COOLDOWN;
}
break;
case COOLDOWN:
// блокируем повторные срабатывания на время "охлаждения"
if (now - tState >= COOLDOWN_MS) {
state = ARMED;
tMotionStart = 0;
lcdShow("ARMED", "Ready");
}
break;
}
}
Как добавить дисплей позже
Если хотите сначала протестировать без экрана, установите USE_LCD = false — сообщения просто не будут выводиться, остальная логика сохранится.
Рекомендации по настройке PIR
- Перемычку установите в режим H (Repeatable) — выход остаётся HIGH при непрерывном движении.
- Регулятор TIME (на плате) задаёт длительность удержания OUT=HIGH после срабатывания. Для системы с программным таймером ставьте среднее значение.
- Регулятор SENS — чувствительность. Уменьшите при ложных срабатываниях.
Безопасность
- При работе с сетевым напряжением подключайте лампу/сирену только через реле‑модуль, соблюдая изоляцию и расстояния. Корпус — негорючий.
- Обеспечьте общую землю для Arduino, PIR и реле. Питание берите с запасом по току.
- Если вместо реле используется транзисторная схема для 12 В сирены — ставьте обратный диод параллельно катушке/нагрузке.
Расширения
- Кнопка «Охрана»: переключение ARMED/DISARMED (например, пин D4 с
INPUT_PULLUP). - Запись событий: метка времени с DS3231, вывод на LCD или в Serial.
- Тихая тревога: вместо сирены — только подсветка/сообщение.
- Уведомления: отправка в Telegram/MQTT (ESP8266/ESP32).
Типичные ошибки
- Сирена «дребезжит»: уменьшите чувствительность PIR, увеличьте
TRIGGER_FILTER_MSи/илиALARM_DURATION_MS. - LCD пустой: неверный адрес I2C. Просканируйте шину (часто 0x27 или 0x3F).
- Реле щёлкает при старте: инициализируйте пин как
OUTPUTи сразу ставьтеLOW.
План работы
- Выберите идею проекта.
- Составьте список необходимых компонентов.
- Соберите схему на макетной плате.
- Напишите и загрузите программу в Arduino.
- Протестируйте и устраните ошибки.
- При желании — соберите проект в корпусе.
Советы
- Старайтесь использовать уже изученные модули и команды.
- Для финального проекта можно комбинировать несколько датчиков.
- Обязательно подумайте о питании и безопасности устройства.
Контрольные вопросы
- Какие три обязательные части должен содержать финальный проект?
- Как можно улучшить проект в будущем?
- Чем полезна отладка в процессе сборки?
Авторский курс по Arduino для начинающих. Использование материалов на коммерческих сайтах допускается с указанием источника.





