//Прога симуляции микроволновой печи
//Библиотеки
#include <EasyButton.h>
#include <LiquidCrystal.h>
//Месточисления для статуса
#define Off 0
#define On 1
#define Done 2
#define Stop 3
//Объявим константы
//Константы пинов
const byte Door_b_pin = 8; // кнопка двери (зеленая)
const byte Control_b_pin = 9; // кнопка управления (красная)
const byte Time_b_pin = 10; //кнопка добавления времени (желтая)
const byte Bulb_pin = 13; // светодиод освещения (зеленый светодиод)
const byte Mag_pin = 12; // магнетрон (синий светодиод)
const byte Motor_pin = 11; // мотор тарелки (красный светодиод)
//const byte Buzzer_pin = 0; //звук (не испольуется так как не хватило пинов)
LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //пины экрана
//Константа стандартного таймера
const unsigned long tmr_main_st = (6L * 1000L); //стандартная длина таймера
const unsigned long t_time_print_l = (1000); //время, через которое будет выводиться текущее время
//Объявим переменные
//Переменные текущих статусов
byte Status = Off; //Общая переменная статуса 0 = выкл, 1 = вкл, 2 = готово, 3 = остановлено
byte Status_pre = Off; //Предыдущий статус
bool is_open = 0; //Статус двери
//Переменная счётчика (для отладки, сейчас не используется)
byte i = 0;
//Создание классов кнопок (по умолчанию антидребезг 35мс, а также подтяжка pullup)
EasyButton Door_b(Door_b_pin); //Создаём кнопку двери Door_b
EasyButton Control_b(Control_b_pin); //Создаем кнопку управления Control_b
EasyButton Time_b(Time_b_pin); //Создаем кнопку добавления времени
/*В слассе имеются следующие функции:
1. Старт таймера (принимает на вход период)
2. Старт таймера (без данных на входе просто перезагружает таймер)
2. Стоп таймера (не реализовано так как не используется)
3. Пауза
4. Продолжение после паузы
5. Продолжение после паузы с аргументом на услучай перезапуска
6. Функция срабатывания (ничего не принимает на вход, возвращает кончился таймер или нет)
7. Функция срабатывания (принимает на вход bool на случай если при срабатывании требуется сразу перезапустить таймер)
8. Функция оставшегося времени (ничего не принимает, возвращает сколько времени осталось в мс)
Класс должен быть полностью самодостаточным. Все операции со временем должны производиться через него.*/
//Класс таймера
class Timer {
public:
Timer () {}
void start (unsigned long length_in) { //Процедура старта таймера с указанием времени
_length_st = length_in;
start();
}
void start () { //Процедура старта таймера с сохранившимся временем последнего старта
_length = _length_st;
_stop_t = millis() + _length;
_is_pause = 0;
}
//void stop () {}
void pause () { //Функция паузы
if (!_is_pause && !ready()) {
_is_pause = 1;
_length = _stop_t - millis();
}
}
void go () { //Функция продолжения после паузы
if (_is_pause) {
_is_pause = 0;
_stop_t = millis() + _length;
} else start();
}
void go (unsigned long length_in_go) { //Функция продолжения после паузы c аргументом на случай старта
if (_is_pause) {
_is_pause = 0;
_stop_t = millis() + _length;
} else start(length_in_go);
}
bool ready () { //Функция срабатывания без перезапуска
if (!length()) {
return 1;
}
return 0;
}
bool ready (bool restart) { //Функция срабатывания с перезапуском
if (!length()) {
if (restart) start();
return 1;
}
return 0;
}
unsigned long length () { //Функция вычисления оставшегося времени (главнее функции срабатывания)
if (!_is_pause) {if (millis() >= _stop_t) {return 0;} else {return (_stop_t - millis());}} else return _length;
}
void add (unsigned long length_add, bool restart_add) {
pause();
_length = _length + (length_add);
if (restart_add) go();
}
private:
//Приватные переменные
unsigned long _length_st = (5L * 60L * 1000L); //Стандартная длина таймера
unsigned long _length = _length_st; //Текущая длина таймера и оставшееся время
unsigned long _stop_t = 0; //время предполагаемого окончания (расчитывается от длины и времени начала, которое не хранится)
bool _is_pause = 0; //Переменная статуса паузы
};
//Создание таймеров
Timer tmr_main; //Основной таймер микроволновки
Timer tmr_1; //Таймер на 1 секунду для выводы логов на экран
//Процедуры кнопок
//Процедра открытия дверцы
void Door_b_press() {
if (is_open) {
is_open = 0;
if (Status == On) tmr_main.go();
} else {
is_open = 1;
if (Status == On) tmr_main.pause();
}
}
//Процедура кнопки управления
void Control_b_press() {
if (!is_open) {
switch (Status) {
case Off:
tmr_main.start(tmr_main_st); //Старт таймера
Status = On;
break;
case On:
tmr_main.pause(); //Пауза таймера
Status = Stop;
break;
case Done:
tmr_main.start(tmr_main_st); //Старт таймера
Status = On;
break;
case Stop:
tmr_main.go();
Status = On;
break;
}
} else {
tmr_main.start(tmr_main_st);
tmr_main.pause();
Status = Stop;
}
}
//Процедура кнопки добавления времени
void Time_b_press() {
if (!is_open) {
tmr_main.add(15000, 1);
Status = On;
} else tmr_main.add(15000, 0);
}
//Установка пинов в соответствие текущему статусу и изменение статуса согласно таймеру
void Status_check() {
if (!is_open) {
if (Status != Status_pre) {
switch (Status) {
case Off:
digitalWrite(Bulb_pin, LOW);
digitalWrite(Mag_pin, LOW);
digitalWrite(Motor_pin, LOW);
break;
case On:
digitalWrite(Bulb_pin, HIGH);
digitalWrite(Mag_pin, HIGH);
digitalWrite(Motor_pin, HIGH);
break;
case Done:
digitalWrite(Bulb_pin, LOW);
digitalWrite(Mag_pin, LOW);
digitalWrite(Motor_pin, LOW);
//tone(Buzzer_pin, 450, 200);
break;
case Stop:
digitalWrite(Bulb_pin, LOW);
digitalWrite(Mag_pin, LOW);
digitalWrite(Motor_pin, LOW);
break;
}
Status_pre = Status;
}
} else {
digitalWrite(Bulb_pin, HIGH);
digitalWrite(Mag_pin, LOW);
digitalWrite(Motor_pin, LOW);
Status_pre = 5; //Изменяю эту переменную на невероятное значение чтобы при закрытии дверцы заново прошла установка пинов
}
if (tmr_main.ready()) Status = Done;
}
//Функция вывода информации в консоль
void Current_time_print() {
unsigned long t_print = tmr_main.length();
unsigned long s = t_print / 1000L;
unsigned long m = s / 60L;
s = s % 60;
/*Serial.print(Status); Serial.print(is_open); */ Serial.print("Left "); Serial.print(m); Serial.print(":"); Serial.print(s); Serial.print("; Current Status is: ");
if (!is_open) {
switch (Status) {
case Off:
Serial.println("Off");
break;
case On:
Serial.println("On");
break;
case Done:
Serial.println("Done!");
break;
case Stop:
Serial.println("Stop");
break;
}
} else {
Serial.println("Door is open");
}
}
//Функция вывода информации на экран
void Current_time_display() {
unsigned long t_print = tmr_main.length();
unsigned long s = t_print / 1000L;
unsigned long m = s / 60L;
s = s % 60;
/*
lcd.setCursor(0, 0);
lcd.print("Left ");
lcd.print(m); lcd.print(":"); lcd.println(s);
lcd.setCursor(0, 1);
lcd.print("MW is: "); */
lcd.setCursor(5, 0);
lcd.print(m); lcd.print(":"); lcd.println(s);
lcd.setCursor(7, 1);
if (!is_open) {
switch (Status) {
case Off:
lcd.println("Off");
break;
case On:
lcd.println("On ");
break;
case Done:
lcd.println("Done!");
break;
case Stop:
lcd.println("Stop");
break;
}
} else {
lcd.println("Open");
}
}
//Настройка
void setup() {
Serial.begin(9600); //Инициализация консоли
lcd.begin(16, 2); //Инициализация экрана
tmr_1.start(t_time_print_l); //Старт таймера вывода в консоль и в экран
tmr_main.start(tmr_main_st); //Старт основного таймера и постановка его на паузу
tmr_main.pause();
//Инициализация кнопок
Door_b.begin();
Control_b.begin();
//Задание пинов переферии
pinMode(Bulb_pin, OUTPUT);
pinMode(Mag_pin, OUTPUT);
pinMode(Motor_pin, OUTPUT);
//pinMode(Buzzer_pin, OUTPUT); не используется
//tone(Buzzer_pin, 450, 200); не используется
//Задание функций кнопок
Door_b.onPressed(Door_b_press);
Control_b.onPressed(Control_b_press);
Time_b.onPressed(Time_b_press);
//Приветственное сообщение
Serial.println("Микроволновка готова к работе!");
/* (Приветствие от которого пришлось отказаться ради оптимизации)
lcd.print("Microwave is");
lcd.setCursor(0, 1);
lcd.print("available");
*/
//Задание статичного текста на экране
lcd.setCursor(0, 0);
lcd.print("Left ");
lcd.setCursor(0, 1);
lcd.print("MW is: ");
}
//Суперцикл
void loop() {
Door_b.read();
Control_b.read();
Time_b.read();
Status_check();
if (tmr_1.ready(1) && (Status != Off)) { //Вывод информации в консоль и на экран
Current_time_print();
Current_time_display();
}
}