#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Stepper.h>
//! Пин фоторезистора.
#define LDR_PIN A0
//! Пин термистора.
#define NTC_PIN A1
//! Пин датчика задымленнсоти.
#define MQ2_PIN A2
//! Пин сервомотора.
const int servoPin = 3;
//! Пин красного цвета.
const int pinR = 11;
//! Пин зелёного цвета.
const int pinG = 10;
//! Пин синего цвета.
const int pinB = 9;
//! Пин реле.
const int pinRelay = 8;
//! Бетта коэффициент для термистора.
const float BETA = 3950;
//! Позиция сервомотора, град.
int servoPos = 0;
//! Шагов за оборот.
const int stepsPerRevolution = 200;
//! ЖК-экран (I2C);
LiquidCrystal_I2C lcd(0x27, 20, 4);
//! Cервомотор (для закрытия штор).
Servo servo;
//! ДПТ.
Stepper stepper(stepsPerRevolution, 4, 5, 6, 7);
//! Состояние датчика.
enum SensorState {
SensorState_Normal, //!< В норме.
SensorState_Below, //!< Ниже нормы.
SensorState_Above //!< Выше нормы.
};
//! Пороговые значения.
#define LIGHT_LOW 30 //!< <30% изкая освещенность.
#define LIGHT_HIGH 70 //!< >70% - высокая освещенность.
#define TEMP_LOW 20 //!< <20°C - холодно.
#define TEMP_HIGH 30 //!< >30°C - жарко.
#define SMOKE_THRESHOLD 50 //!< >50% - задымленность.
//! Предварительная установка параметров.
void setup() {
lcd.init();
lcd.backlight();
servo.attach(servoPin);
stepper.setSpeed(60);
pinMode(pinR, OUTPUT);
pinMode(pinG, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(pinRelay, OUTPUT);
Serial.begin(115200);
}
//! Основной цикл симуляции проекта.
void loop() {
lcd.setCursor(0, 0);
lcd.print("Room: ");
const SensorState ldrState = handleLDR();
const SensorState ntcState = handleNTC();
const SensorState mq2State = handleMQ2();
handleLED(ldrState, ntcState, mq2State);
delay(100);
}
//! Обработать данные от фоторезистора.
SensorState handleLDR() {
const int analogValue = analogRead(LDR_PIN);
const float analogValueHandled = 100 - (analogValue / 1023. * 100);
lcd.setCursor(0, 1);
lcd.print("LDR, %: ");
lcd.print(analogValueHandled);
servo.write(90);
SensorState state = SensorState_Normal;
if (analogValueHandled > LIGHT_HIGH) {
servo.write(180);
state = SensorState_Above;
} else if (analogValueHandled < LIGHT_LOW) {
state = SensorState_Below;
servo.write(0);
}
return state;
}
//! Обработать данные от термистора.
SensorState handleNTC() {
digitalWrite(pinRelay, LOW);
//! Рассчёт параметров по Wokwi-Docs.
const int analogValue = analogRead(NTC_PIN);
const float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
lcd.setCursor(0, 2);
lcd.print("NTC, C: ");
lcd.print(celsius);
SensorState state = SensorState_Normal;
if (celsius > TEMP_HIGH) {
state = SensorState_Above;
stepper.step(stepsPerRevolution);
} else if (celsius < TEMP_LOW) {
state = SensorState_Below;
digitalWrite(pinRelay, HIGH);
}
return state;
}
//! Обработать данные от датчика задымленности.
SensorState handleMQ2() {
const int analogValue = analogRead(MQ2_PIN);
const float analogValueHandled = analogValue / 1023. * 100;
lcd.setCursor(0, 3);
lcd.print("MQ2, %: ");
lcd.print(analogValueHandled);
SensorState state = SensorState_Normal;
if (analogValueHandled > SMOKE_THRESHOLD) {
state = SensorState_Above;
stepper.step(-stepsPerRevolution);
}
return state;
}
//! Обработать данные о состоянии датчиков.
int handleLED(const SensorState& ldrState, const SensorState& ntcState, const SensorState& mq2State) {
digitalWrite(pinR, LOW);
digitalWrite(pinG, LOW);
digitalWrite(pinB, LOW);
if ((ldrState == SensorState_Above) || (ntcState == SensorState_Above) || (mq2State == SensorState_Above)) {
digitalWrite(pinR, HIGH);
} else if ((ldrState == SensorState_Below) || (ntcState == SensorState_Below) || (mq2State == SensorState_Below)) {
digitalWrite(pinB, HIGH);
} else {
digitalWrite(pinG, HIGH);
}
}