#include <PinChangeInterrupt.h>
#include <EEPROM.h>
const int mosfet = 3;
const int forcedStartButton = 4;
const int timerButton = 5;
const int floaterInterraption = 6;
const int oilOKLed = 7;
const int oilEMPTYLed = 8;
const unsigned long MOTOR_DURATION = 6019; // 6 секунд 19 миллисекунд
const unsigned long TIMER_INTERVAL = 10000; // Интервал таймера (5 секунд)
// this type is needed for sum of result of millis and MOTOR_DURATION
unsigned long timerStartTime = 0; // Время начала отсчёта таймера
// uint64_t timerStartTime = 0; // Время начала отсчёта таймера
// unsigned long timerStartTime = 0; // Время начала отсчёта таймера
const unsigned long SAVE_REMAINING_TIMER_TIME_INTERVAL = TIMER_INTERVAL / 5; // сохранять значение каждую пятую часть от таймера
unsigned long lastSaveRemainingTimerTime = millis();
volatile bool floaterInterraptionState;
volatile bool forcedStartButtonState = false;
volatile bool timerButtonState = false;
bool timerActive = false; // Флаг активности таймера
bool to_save_flag = true; // Сохранять время таймера или нет
#define DEBUG true
void debugTime(){
if (DEBUG) {
Serial.print(millis());
Serial.print(" ");
}
}
void debugPrint(const char* message) {
if (DEBUG) {
Serial.print(message);
}
}
void debugPrintULONG(const unsigned long number) {
if (DEBUG) {
Serial.print(number);
}
}
void debugPrintln(const char* message) {
if (DEBUG) {
Serial.println(message);
}
}
void debugPrintlnTimed(const char* message) {
if (DEBUG) {
debugTime();
Serial.println(message);
}
}
// print function; can be removed
void debug_print_uint64_t(uint64_t num) {
if (DEBUG) {
// Function that can print uint64_t nums
char rev[128];
char *p = rev+1;
while (num > 0) {
// Serial.println('0' + (num % 10));
*p++ = '0' + (num % 10);
num /= 10;
}
p--;
/*Print the number which is now in reverse*/
while (p > rev) {
Serial.print(*p--);
}
Serial.println(*p);
// Serial.println();
}
}
// print function; can be removed
void debug_print_int64_t(int64_t num) {
if (DEBUG) {
char rev[128];
char *p = rev+1;
if (num < 0) {
Serial.print('-');
num = -num;
}
while (num > 0) {
*p++ = '0' + (num % 10);
num /= 10;
}
p--;
/*Print the number which is now in reverse*/
while (p > rev) {
Serial.print(*p--);
}
// Serial.println(*p);
}
}
unsigned long defaultAfterMotorTimerTime(){
return 2 * TIMER_INTERVAL + MOTOR_DURATION;
}
void changeTimerButtonState() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 200) {
timerButtonState = !timerButtonState;
if (timerButtonState) {
timerActive = true; // Активируем таймер при нажатии кнопки
// miliseconds that remains from the previous startup of the machine and hardcoded value to next lubrication
timerStartTime = loadRemainingTimerTimeFromEEPROM() + timerStartTime;
// Выставляем дефолтное время таймера, чтобы не срабатывало сразу же
if (timerStartTime == 0){
timerStartTime = 2 * TIMER_INTERVAL;
}
// В первом запуске не учитывается время работы мотора
timerStartTime = millis() + timerStartTime; // Запоминаем время начала отсчёта таймера
// Start save timer here to do not save one more time after timer is turned off
lastSaveRemainingTimerTime = millis();
// Serial.println(timerStartTime);
debugPrintlnTimed("Timer started");
} else {
timerActive = false; // Деактивируем таймер при повторном нажатии кнопки
debugPrintlnTimed("Timer stopped");
// Serial.println(timerStartTime);
if (to_save_flag && timerStartTime >= millis()){
// Serial.println(timerStartTime - MOTOR_DURATION - currentMillis);
// Timer is active
saveRemainingTimerTimeToEEPROM(timerStartTime - millis());
}
timerStartTime = 0; // Сбрасываем предыдущий таймер
// saveRemainingTimerTimeToEEPROM(0); // Delete saved remaining time
}
}
lastInterruptTime = interruptTime;
}
void changeForcedStartState() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 400) {
forcedStartButtonState = !forcedStartButtonState;
if (forcedStartButtonState && timerActive) {
// timerStartTime = millis(); // Сбрасываем таймер при нажатии кнопки
// При принудительном запуске, сброс таймера
timerStartTime = millis() + (defaultAfterMotorTimerTime());
// Serial.println(timerStartTime);
debugPrintlnTimed("Timer reset");
}
lastInterruptTime = interruptTime;
}
}
void changeOilState() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 200) {
floaterInterraptionState = !floaterInterraptionState;
digitalWrite(oilOKLed, !floaterInterraptionState);
digitalWrite(oilEMPTYLed, floaterInterraptionState);
}
lastInterruptTime = interruptTime;
}
void controlMotor(bool start) {
static unsigned long motorStartTime = 0;
if (motorStartTime > 0 && millis() - motorStartTime >= MOTOR_DURATION) {
digitalWrite(mosfet, LOW);
motorStartTime = 0;
debugPrintlnTimed("mosfet=off");
to_save_flag = true;
} else if (start && motorStartTime == 0) {
digitalWrite(mosfet, HIGH);
motorStartTime = millis();
debugPrintlnTimed("mosfet=on");
to_save_flag = false;
}
}
void saveRemainingTimerTimeToEEPROM(unsigned long remainingTime) {
// #if defined(ESP8266)|| defined(ESP32)
// EEPROM.begin(512);
// #endif
// Save value to EEPROM
// debug_print_int64_t(remainingTime);
// debugPrintln(" ");
EEPROM.put(0, remainingTime);
// #if defined(ESP8266)|| defined(ESP32)
// EEPROM.commit();
// #endif
debugTime();
debugPrint("Value ");
// debug_print_int64_t(remainingTime);
// Serial.print(EEPROM.get(0, remainingTime));
debugPrintULONG(remainingTime);
debugPrint(" saved to EEPROM address: ");
debugPrint("0");
debugPrintln(" ");
}
unsigned long loadRemainingTimerTimeFromEEPROM() {
unsigned long _remainingTime;
EEPROM.get(0, _remainingTime);
debugPrint("Loaded remaining timer time(ms): ");
// debug_print_uint64_t(_remainingTime + 1);
debugPrintULONG(_remainingTime + 1);
debugPrintln(" ");
// If memory was empty before, it returns -1 but as unsigned long it is 2**32-1
if ((_remainingTime + 1) == 0){
_remainingTime = 0;
}
return (unsigned long)_remainingTime;
}
void setup() {
Serial.begin(9600);
pinMode(mosfet, OUTPUT);
pinMode(oilOKLed, OUTPUT);
pinMode(oilEMPTYLed, OUTPUT);
attachPCINT(digitalPinToPCINT(timerButton), changeTimerButtonState, CHANGE);
// timerButtonState = digitalRead(timerButton);
// saveRemainingTimerTimeToEEPROM((unsigned long)15392);
// unsigned long test = (millis() + 1000);
// Serial.println(test - millis());
// delay(1000);
// Serial.println(test - millis());
// while(1);
attachPCINT(digitalPinToPCINT(forcedStartButton), changeForcedStartState, CHANGE);
// forcedStartButtonState = digitalRead(forcedStartButton);
attachPCINT(digitalPinToPCINT(floaterInterraption), changeOilState, CHANGE);
floaterInterraptionState = digitalRead(floaterInterraption);
digitalWrite(oilOKLed, !floaterInterraptionState);
digitalWrite(oilEMPTYLed, floaterInterraptionState);
}
void loop() {
unsigned long currentMillis = millis();
// Проверка таймера
if (timerActive && timerStartTime >= currentMillis && timerStartTime - currentMillis <= TIMER_INTERVAL) {
debugPrintlnTimed("Timer elapsed, starting motor");
// Serial.println(timerStartTime - currentMillis);
controlMotor(true); // Включаем мотор по истечении таймера
// // timerActive = false; // Деактивируем таймер
// При окончании таймера, сбрасываем таймер и прибавляем время,
// которое необходимо на смазку, и время таймера,
// чтобы смазка по таймеру не происходила сразу после принудительной смазки
timerStartTime = currentMillis + defaultAfterMotorTimerTime();
// Serial.println(timerStartTime);
}
// Проверка принудительного запуска
if (forcedStartButtonState) {
forcedStartButtonState = false;
debugPrintlnTimed("Forced start, starting motor");
saveRemainingTimerTimeToEEPROM(0);
controlMotor(true); // Включаем мотор принудительно
}
if (timerActive && currentMillis - lastSaveRemainingTimerTime >= SAVE_REMAINING_TIMER_TIME_INTERVAL){
// Serial.println(currentMillis - timerStartTime);
// Serial.println(timerStartTime - currentMillis);
// Save remaining time of timer for next session in case of earlier machine stop
if (to_save_flag && timerStartTime >= currentMillis){
// Serial.println(timerStartTime - MOTOR_DURATION - currentMillis);
// Timer is active
saveRemainingTimerTimeToEEPROM(timerStartTime - currentMillis);
}
// else if (timerStartTime < currentMillis) {
// saveRemainingTimerTimeToEEPROM(0);
// }
// else {
// // Timer is elapsed and motor is working
// saveRemainingTimerTimeToEEPROM(0);
// }
lastSaveRemainingTimerTime = currentMillis;
}
// Управление мотором
controlMotor(false); // Выключаем мотор, если время истекло
}