// Подключаем библиотеку для работы с жидкокристаллическим // экраном (англ. Liquid Crystal Display или просто LCD) #include // Объявляем объект, для управления дисплеем. Для его создания // необходимо указать номера пинов, к которым он подключен в // порядке: RS E DB4 DB5 DB6 DB7 LiquidCrystal lcd(PIN_LCD_RS, PIN_LCD_E, PIN_LCD_DB4, PIN_LCD_DB5, PIN_LCD_DB6, PIN_LCD_DB7); // Вспомогательные переменные // - Состояние нажатий клавиш, по умолчанию не нажаты boolean button_state[3] = { false, false, false }; // - Определение открытого резервуара byte open_servo_id = 0; // Состояние системы int currentState = STATE_INIT; boolean isFirstCall = true; // true если состояние проходит первый цикл // Заданные величины int levelOne = 0; int levelRes = 0; int timeSeconds = 0; // Функция установки запускается один раз при нажатии reset или включения питания на плате void setup() { // Инициализация пинов как Input, Output // Светодиоды pinMode(PIN_LED_POWER, OUTPUT); // ... // Кнопки pinMode(PIN_BUTTON_PLUS, INPUT); // ... // Сервоприводы pinMode(PIN_SERVO_1, OUTPUT); pinMode(PIN_SERVO_2, OUTPUT); // Мотор pinMode(PIN_MIX, OUTPUT); // Датчики уровня воды pinMode(PIN_WATER_LEVEL_1, INPUT); // ... // начинаем работу с экраном. Сообщаем объекту количество // строк и столбцов. Опять же, вызывать pinMode не требуется: // функция begin сделает всё за нас lcd.begin(16, 2); } // Функция loop выполняется снова и снова void loop() { // На всякий случай проверяем переполнение резервуара if (isWaterLevel(PIN_WATER_LEVEL_DANGER)) { changeStatus(STATE_DANGER); // устанавливаем соответствующее состояние } switch (currentState) { case STATE_INIT: // инициализации stateInit(); break; case STATE_ENTER_FIRST_LEVEL: // ввод первого уровня жидкости stateEnterFirstLevel(); break; case STATE_ENTER_SECOND_LEVEL: // ввод результирующего уровня stateEnterSecondLevel(); break; case STATE_ENTER_TIME_MIX: // ввод времени перемешивания stateEnterTimeMix(); break; case STATE_FILL: // заливаем stateFill(); break; case STATE_MIX: // мешаем stateMix(); break; case STATE_DANGER: // жидкости слишком много stateDanger(); break; } isFirstCall = false; } void stateInit() { lcd.clear(); lcd.print("Загрузка..."); // включаем светодиод, что устройство работает digitalWrite(PIN_LED_POWER, HIGH); delay(2000); // 2 sec changeStatus(STATE_ENTER_FIRST_LEVEL); } void stateEnterFirstLevel() { if (isFirstCall) { lcd.clear(); lcd.print("Ввод ур 1 ж"); } if (isClicked(BUTTON_PLUS)) { levelOne++; } else if (isClicked(BUTTON_MINUS)) { levelOne--; } if (levelOne < 1) levelOne = 1; if (levelOne > 10) levelOne = 10; lcd.setCursor(0, 1); lcd.print(levelOne); if (isClicked(BUTTON_ACCEPT)) { changeStatus(STATE_ENTER_SECOND_LEVEL); } } void stateEnterSecondLevel() { ... } void stateEnterTimeMix() { ... } void stateFill() { if (isFirstCall) { lcd.clear(); lcd.print("Подача жидкости"); // включаем светодиод подачи воды digitalWrite(PIN_LED_FILL, HIGH); // открываем 1 клапон digitalWrite(PIN_SERVO_1, HIGH); open_servo_id = 1; } if (open_servo_id == 1 && isWaterLevel(getPinFromLevel(levelOne))) { // закрываем 1 клапон digitalWrite(PIN_SERVO_1, LOW); // открываем 2 клапон digitalWrite(PIN_SERVO_2, HIGH); open_servo_id = 2; } else if (open_servo_id == 2 && isWaterLevel(getPinFromLevel(levelOne))) { // закрываем 2 клапон digitalWrite(PIN_SERVO_2, LOW); open_servo_id = 0; // выключаем светодиод подачи воды digitalWrite(PIN_LED_FILL, LOW); changeStatus(STATE_MIX); // мешаем } } void stateMix() { if (isFirstCall) { lcd.clear(); lcd.print("Перемешивание"); lcd.setCursor(0, 1); // включаем светодиод перемешивания digitalWrite(PIN_LED_MIX, HIGH); // включаем мотор digitalWrite(PIN_MIX, HIGH); } lcd.setCursor(0, 1); lcd.print(timeSeconds); delay(1000); // 1 sec timeSeconds--; if (timeSeconds < 0) { // выключаем мотор digitalWrite(PIN_MIX, LOW); // выключаем светодиод перемешивания digitalWrite(PIN_LED_MIX, LOW); changeStatus(STATE_INIT); } } void stateDanger() { lcd.clear(); lcd.print("Превышен уровень жидкости"); lcd.setCursor(0, 1); lcd.print("Устройство будет переведено в начальное состояние"); // выключаем светодиоды и мотор, а также закрываем сервоприводы digitalWrite(PIN_LED_POWER, LOW); digitalWrite(PIN_LED_FILL, LOW); digitalWrite(PIN_LED_MIX, LOW); digitalWrite(PIN_SERVO_1, LOW); digitalWrite(PIN_SERVO_2, LOW); digitalWrite(PIN_MIX, LOW); delay(3000); // 3 sec changeStatus(STATE_INIT); } void changeStatus(int status) { currentState = status; isFirstCall = true; } // возвращает пин в соответствии с уровнем int getPinFromLevel(int level) { ... } // Функция возвращает true, если уровень жидкости превысил заданный уровень boolean isWaterLevel(int pinLevel) { return digitalRead(pinLevel) == HIGH; } // Функция возвращает true, если пользователь отпустил кнопку boolean isClicked(byte buttonId) { ... }