1. Введение
Данный проект представляет собой компактную метеостанцию на базе микроконтроллера Arduino, способную измерять температуру окружающей среды и уровень освещенности. Полученные данные выводятся на ЖК-дисплей, а в случае превышения заданного температурного порога система оповещает пользователя звуковым сигналом.
Проект может использоваться в бытовых условиях для мониторинга микроклимата в помещении или на улице, а также в образовательных целях для изучения основ программирования микроконтроллеров и работы с аналоговыми датчиками.
2. Цель программы
Разработать автоматизированную систему, которая:
- Измеряет температуру с помощью аналогового датчика (LM35 или аналогичного).
- Определяет уровень освещенности с помощью фоторезистора.
- Выводит данные на 16×2 символьный ЖК-дисплей с графическими символами.
- Генерирует звуковые оповещения при превышении температурного порога (20°C).
- Воспроизводит мелодию в нормальном режиме работы.
3. Описание компонентов
3.1. Аппаратная часть
- Микроконтроллер Arduino (любая совместимая плата, например, Arduino Uno).
- Датчик температуры (LM35 или аналогичный), подключенный к аналоговому входу
A1
. - Фоторезистор для измерения освещенности, подключенный к аналоговому входу
A0
. - Пьезоизлучатель (buzzer) для звуковых оповещений, подключенный к цифровому выходу
9
. - ЖК-дисплей 16×2 с управлением через библиотеку
LiquidCrystal
(подключен к пинам12,
11, 5, 4, 3, 2
).
3.2. Программная часть
- Библиотека
LiquidCrystal
– для управления ЖК-дисплеем. - Аналоговые входы – считывание данных с датчиков.
- Генерация звука – с помощью функции
tone()
. - Пользовательские символы – отображение графических элементов (солнце, дождь, смайлы и др.).
4. Структура программы

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int temperaturePin = A1;
const int lightPin = A0;
const int buzzerPin = 9;
float voltage, degreesC;
char* tempText[] = {
"Cold weather!", // < 15
"Nice weather!", // 15–25
"Heat rising!", // 25–30
"Hot! Drink water!" // >30
};
char* lightText[] = {
"Sunny", // < 85
"Cloudy", // 85–170
"Rainy" // >170
};
byte smile[8] = {
0b00000, 0b01010, 0b01010, 0b00000,
0b10001, 0b01110, 0b00000, 0b00000
};
byte rain[8] = {
0b00100, 0b00100, 0b01010, 0b01010,
0b10001, 0b10001, 0b10001, 0b01110
};
byte degrees[8] = {
0b01110, 0b01010, 0b01110, 0b00000,
0b00000, 0b00000, 0b00000, 0b00000
};
byte sun[8] = {
0b00100, 0b01010, 0b11111, 0b11111,
0b00100, 0b00100, 0b00000, 0b00000
};
byte sad[8] = {
0b00000, 0b01010, 0b01010, 0b00000,
0b01110, 0b10001, 0b00000, 0b00000
};
const int songLength = 18;
char notes[] = "cdfda ag cdfdg gf ";
int beats[] = {1,1,1,1,1,1,4,4,2,1,1,1,1,1,1,4,4,2};
int tempo = 150;
void setup() {
Serial.begin(9600);
pinMode(buzzerPin, OUTPUT);
lcd.begin(16, 2);
lcd.createChar(1, degrees);
lcd.createChar(2, smile);
lcd.createChar(3, rain);
lcd.createChar(4, sun);
lcd.createChar(5, sad);
lcd.setCursor(0, 0);
lcd.print("Weather Station");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(1000);
}
void loop() {
// Считываем температуру (предполагаем LM35 или аналогичный)
voltage = analogRead(temperaturePin) * 0.004882814;
degreesC = (voltage - 0.5) * 100.0;
// Считываем освещенность
int lightLevel = analogRead(lightPin);
lightLevel = map(lightLevel, 300, 800, 0, 255);
lightLevel = constrain(lightLevel, 0, 255);
Serial.print("Temp: ");
Serial.print(degreesC);
Serial.print(" C | Light: ");
Serial.println(lightLevel);
// Проверка тревоги: температура > 25 °C
if (degreesC > 20) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("!!! ALARM !!!");
lcd.setCursor(0, 1);
lcd.print("Temp:");
lcd.print(degreesC, 1);
lcd.write(byte(1)); // значок градуса
lcd.print("C");
tone(buzzerPin, 1000); // Постоянный тон
delay(500);
noTone(buzzerPin);
delay(200);
} else {
noTone(buzzerPin);
displayData(degreesC, lightLevel);
playMelody();
}
}
void displayData(float temp, int light) {
char* tempTextToDisplay;
if (temp < 15) tempTextToDisplay = tempText[0];
else if (temp < 20) tempTextToDisplay = tempText[1];
else if (temp < 30) tempTextToDisplay = tempText[2];
else tempTextToDisplay = tempText[3];
char* lightTextToDisplay;
byte lightIcon;
if (light > 170) {
lightTextToDisplay = lightText[2];
lightIcon = 3;
} else if (light > 85) {
lightTextToDisplay = lightText[1];
lightIcon = 4;
} else {
lightTextToDisplay = lightText[0];
lightIcon = 2;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(tempTextToDisplay);
lcd.setCursor(14, 0);
lcd.write(byte(1)); // значок градуса
lcd.setCursor(0, 1);
lcd.print(lightTextToDisplay);
lcd.setCursor(strlen(lightTextToDisplay) + 1, 1);
lcd.write(lightIcon);
delay(2000);
}
void playMelody() {
for (int i = 0; i < songLength; i++) {
int duration = beats[i] * tempo;
if (notes[i] == ' ') {
delay(duration);
} else {
tone(buzzerPin, frequency(notes[i]), duration);
delay(duration);
}
delay(tempo / 10);
}
}
int frequency(char note) {
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int freqs[] = {262, 294, 330, 349, 392, 440, 494, 523};
for (int i = 0; i < 8; i++) {
if (names[i] == note) return freqs[i];
}
return 0;
}
4.1. Подключение библиотеки и инициализация дисплея
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LiquidCrystal.h
– библиотека для управления ЖК-дисплеем.lcd(12, 11, 5, 4, 3, 2)
– указываем пины Arduino, к которым подключён дисплей (RS, E, D4, D5, D6, D7).
4.2. Определение пинов и переменных
const int temperaturePin = A1; // Пин датчика температуры (LM35)
const int lightPin = A0; // Пин фоторезистора
const int buzzerPin = 9; // Пин пьезопищалки
float voltage, degreesC; // Для хранения напряжения и температуры
- Датчики подключены к аналоговым входам
A0
(освещённость) иA1
(температура). buzzerPin
– цифровой выход для звука.voltage
иdegreesC
– переменные для расчёта температуры.
4.3. Текстовые сообщения
char* tempText[] = {
"Cold weather!", // < 15°C
"Nice weather!", // 15–25°C
"Heat rising!", // 25–30°C
"Hot! Drink water!" // >30°C
};
char* lightText[] = {
"Sunny", // < 85
"Cloudy", // 85–170
"Rainy" // >170
};
tempText
– сообщения в зависимости от температуры.lightText
– сообщения в зависимости от освещённости.
4.4. Пользовательские символы для дисплея
byte smile[8] = { ... }; // Улыбающийся смайл
byte rain[8] = { ... }; // Дождь
byte degrees[8] = { ... };// Знак градуса
byte sun[8] = { ... }; // Солнце
byte sad[8] = { ... }; // Грустный смайл
Каждый символ задаётся в виде 8-битного массива (8 строк по 5 пикселей).
4.5. Мелодия для бузера
const int songLength = 18;
char notes[] = "cdfda ag cdfdg gf "; // Ноты
int beats[] = {1,1,1,1,1,1,4,4,2,1,1,1,1,1,1,4,4,2}; // Длительности
int tempo = 150; // Скорость воспроизведения
- Мелодия задаётся нотами (
c
,d
,f
и т. д.) и их длительностями. tempo
– скорость (чем больше, тем медленнее).
4.6. Функция setup()
– начальная настройка
void setup() {
Serial.begin(9600); // Инициализация Serial-порта
pinMode(buzzerPin, OUTPUT); // Настройка пина бузера
lcd.begin(16, 2); // Инициализация дисплея (16x2)
// Создание пользовательских символов
lcd.createChar(1, degrees);
lcd.createChar(2, smile);
lcd.createChar(3, rain);
lcd.createChar(4, sun);
lcd.createChar(5, sad);
// Приветственное сообщение
lcd.setCursor(0, 0);
lcd.print("Weather Station");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
delay(1000);
}
- Настраивается связь с компьютером (
Serial
). - Пин бузера переводится в режим выхода.
- Дисплей инициализируется, создаются кастомные символы.
- Выводится заставка.
4.7. Функция loop()
– основной цикл
void loop() {
// 1. Чтение температуры
voltage = analogRead(temperaturePin) * 0.004882814; // Пересчёт в вольты
degreesC = (voltage - 0.5) * 100.0; // Пересчёт в градусы
// 2. Чтение освещённости
int lightLevel = analogRead(lightPin);
lightLevel = map(lightLevel, 300, 800, 0, 255); // Нормализация
lightLevel = constrain(lightLevel, 0, 255); // Ограничение 0–255
// 3. Вывод в Serial-монитор
Serial.print("Temp: ");
Serial.print(degreesC);
Serial.print(" C | Light: ");
Serial.println(lightLevel);
// 4. Проверка аварийного режима (температура > 20°C)
if (degreesC > 20) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("!!! ALARM !!!");
lcd.setCursor(0, 1);
lcd.print("Temp:");
lcd.print(degreesC, 1);
lcd.write(byte(1)); // Символ градуса
lcd.print("C");
tone(buzzerPin, 1000); // Включение бузера
delay(500);
noTone(buzzerPin);
delay(200);
} else {
noTone(buzzerPin); // Выключение бузера
displayData(degreesC, lightLevel); // Вывод данных
playMelody(); // Проигрывание мелодии
}
}
- Чтение температуры:
analogRead()
считывает значение (0–1023).- Пересчитывается в вольты (
* 0.004882814
– шаг АЦП для 5В). - Формула
(voltage - 0.5) * 100.0
преобразует в °C (для LM35).
- Чтение освещённости:
analogRead(lightPin)
получает сырое значение.map()
нормализует его в диапазон 0–255.constrain()
ограничивает возможные значения.
- Аварийный режим:
- Если температура > 20°C, выводится предупреждение.
- Бузер издаёт прерывистый звук.
- Нормальный режим:
- Данные выводятся на дисплей (
displayData()
). - Проигрывается мелодия (
playMelody()
).
- Данные выводятся на дисплей (
4.8. Функция displayData()
– вывод на дисплей
void displayData(float temp, int light) {
// Выбор текста для температуры
char* tempTextToDisplay;
if (temp < 15) tempTextToDisplay = tempText[0];
else if (temp < 20) tempTextToDisplay = tempText[1];
else if (temp < 30) tempTextToDisplay = tempText[2];
else tempTextToDisplay = tempText[3];
// Выбор текста и иконки для освещённости
char* lightTextToDisplay;
byte lightIcon;
if (light > 170) {
lightTextToDisplay = lightText[2];
lightIcon = 3; // Дождь
} else if (light > 85) {
lightTextToDisplay = lightText[1];
lightIcon = 4; // Солнце
} else {
lightTextToDisplay = lightText[0];
lightIcon = 2; // Смайл
}
// Вывод на дисплей
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(tempTextToDisplay);
lcd.setCursor(14, 0);
lcd.write(byte(1)); // Символ градуса
lcd.setCursor(0, 1);
lcd.print(lightTextToDisplay);
lcd.setCursor(strlen(lightTextToDisplay) + 1, 1);
lcd.write(lightIcon); // Иконка погоды
delay(2000);
}
- В зависимости от температуры и освещённости выбираются текст и иконка.
- Данные выводятся на две строки дисплея.
4.9. Функции для работы со звуком
playMelody()
– проигрывание мелодии
void playMelody() {
for (int i = 0; i < songLength; i++) {
int duration = beats[i] * tempo;
if (notes[i] == ' ') {
delay(duration); // Пауза
} else {
tone(buzzerPin, frequency(notes[i]), duration); // Включение ноты
delay(duration);
}
delay(tempo / 10);
}
}
- Перебирает ноты из массива
notes
. - Для каждой ноты вычисляется длительность (
beats[i] * tempo
). - Если символ пробел – пауза, иначе – звук.
frequency()
– получение частоты ноты
int frequency(char note) {
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int freqs[] = {262, 294, 330, 349, 392, 440, 494, 523};
for (int i = 0; i < 8; i++) {
if (names[i] == note) return freqs[i];
}
return 0;
}
- Сопоставляет ноту (
c
,d
, …) с частотой (в Гц).
5. Возможные улучшения
- Добавление датчика влажности (DHT11/DHT22).
- Логирование данных на SD-карту.
- Передача данных по Wi-Fi (ESP8266/ESP32).
- Настройка пороговых значений через потенциометр.
6. Заключение
Данная метеостанция демонстрирует базовые принципы работы с аналоговыми датчиками, ЖК-дисплеем и звуковой индикацией на Arduino. Проект может быть расширен для более сложных сценариев использования, таких как умный дом или системы мониторинга окружающей среды.
Код хорошо структурирован, содержит комментарии и может служить учебным примером для начинающих разработчиков.