Загрузка данных
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(
SCREEN_WIDTH,
SCREEN_HEIGHT,
&Wire,
OLED_RESET
);
// ===================== ПИНЫ =====================
const byte injectorPins[4] = {2, 3, 4, 5};
const byte injectorButtonPin = 6;
const byte relay1ButtonPin = 7;
const byte relay1Pin = 8;
const byte relay2ButtonPin = 9;
const byte relay2Pin = 10;
const byte timePotPin = A0;
const byte countPotPin = A1;
// ===================== ДИАПАЗОНЫ =====================
const unsigned int MIN_INJECTOR_TIME = 5;
const unsigned int MAX_INJECTOR_TIME = 25;
const int MIN_CYCLES = 10;
const int MAX_CYCLES = 100;
// ===================== ВРЕМЕНА =====================
const unsigned long INJECTOR_LOCK_TIME = 10000UL;
// R1 теперь работает 15 секунд
const unsigned long RELAY1_TIME = 15000UL;
const unsigned long DEBOUNCE_TIME = 25UL;
const unsigned long DISPLAY_UPDATE_TIME = 100UL;
// ===================== ФИЛЬТРАЦИЯ =====================
const byte POT_SAMPLES = 8;
// ===================== НАСТРОЙКИ =====================
unsigned int injectorOpenTime = MIN_INJECTOR_TIME;
int injectorCycles = MIN_CYCLES;
// ===================== ФИЛЬТРОВАННЫЕ ADC =====================
int filteredTimeValue = 0;
int filteredCountValue = 0;
// ===================== ФОРСУНКИ =====================
bool injectorRunning = false;
byte currentInjector = 0;
int currentCycle = 0;
unsigned long injectorStartTime = 0;
// ===================== БЛОКИРОВКА КНОПКИ ФОРСУНОК =====================
bool injectorButtonLocked = false;
unsigned long injectorUnlockTime = 0;
// ===================== R1 =====================
bool relay1Active = false;
unsigned long relay1StartTime = 0;
// ===================== КНОПКИ =====================
struct Button {
byte pin;
bool stableState;
bool lastReading;
unsigned long lastChangeTime;
};
Button injectorButton = {
injectorButtonPin,
HIGH,
HIGH,
0
};
Button relay1Button = {
relay1ButtonPin,
HIGH,
HIGH,
0
};
Button relay2Button = {
relay2ButtonPin,
HIGH,
HIGH,
0
};
unsigned long lastDisplayUpdate = 0;
// ==================================================
// SETUP
// ==================================================
void setup() {
// Форсунки
for (byte i = 0; i < 4; i++) {
pinMode(injectorPins[i], OUTPUT);
digitalWrite(injectorPins[i], LOW);
}
// Реле
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, LOW);
// Кнопки
pinMode(injectorButtonPin, INPUT_PULLUP);
pinMode(relay1ButtonPin, INPUT_PULLUP);
pinMode(relay2ButtonPin, INPUT_PULLUP);
// OLED
display.begin(
SSD1306_SWITCHCAPVCC,
OLED_ADDRESS
);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("INJECTOR CONTROL");
display.display();
delay(500);
}
// ==================================================
// LOOP
// ==================================================
void loop() {
readSettings();
updateButton(injectorButton);
updateButton(relay1Button);
updateButton(relay2Button);
updateInjectors();
updateInjectorLock();
updateRelay1();
updateRelay2();
updateDisplay();
}
// ==================================================
// ЧТЕНИЕ ПОТЕНЦИОМЕТРОВ
// ==================================================
int readPotFiltered(byte pin) {
long sum = 0;
for (byte i = 0; i < POT_SAMPLES; i++) {
sum += analogRead(pin);
}
return sum / POT_SAMPLES;
}
void readSettings() {
int newTimeValue =
readPotFiltered(timePotPin);
int newCountValue =
readPotFiltered(countPotPin);
// Потенциометр времени
if (newTimeValue <= 3) {
filteredTimeValue = 0;
} else if (newTimeValue >= 1020) {
filteredTimeValue = 1023;
} else if (
abs(newTimeValue - filteredTimeValue) >= 3
) {
filteredTimeValue = newTimeValue;
}
// Потенциометр количества циклов
if (newCountValue <= 3) {
filteredCountValue = 0;
} else if (newCountValue >= 1020) {
filteredCountValue = 1023;
} else if (
abs(newCountValue - filteredCountValue) >= 3
) {
filteredCountValue = newCountValue;
}
// Переводим ADC в настройки
injectorOpenTime =
map(
filteredTimeValue,
0,
1023,
MIN_INJECTOR_TIME,
MAX_INJECTOR_TIME
);
injectorCycles =
map(
filteredCountValue,
0,
1023,
MIN_CYCLES,
MAX_CYCLES
);
injectorOpenTime =
constrain(
injectorOpenTime,
MIN_INJECTOR_TIME,
MAX_INJECTOR_TIME
);
injectorCycles =
constrain(
injectorCycles,
MIN_CYCLES,
MAX_CYCLES
);
}
// ==================================================
// ОБРАБОТКА КНОПКИ
// ==================================================
bool buttonPressed(Button &button) {
bool reading =
digitalRead(button.pin);
unsigned long now =
millis();
if (reading != button.lastReading) {
button.lastChangeTime = now;
button.lastReading = reading;
}
if (
now - button.lastChangeTime >=
DEBOUNCE_TIME
) {
if (reading != button.stableState) {
button.stableState = reading;
if (button.stableState == LOW) {
return true;
}
}
}
return false;
}
// ==================================================
// ОБРАБОТКА КНОПОК
// ==================================================
void updateButton(Button &button) {
// Кнопка запуска форсунок
if (&button == &injectorButton) {
if (buttonPressed(button)) {
if (
!injectorRunning &&
!injectorButtonLocked
) {
startInjectorCycle();
}
}
}
// Кнопка R1
if (&button == &relay1Button) {
if (buttonPressed(button)) {
if (
!injectorRunning &&
!relay1Active
) {
relay1Active = true;
relay1StartTime =
millis();
digitalWrite(
relay1Pin,
HIGH
);
}
}
}
}
// ==================================================
// ЗАПУСК ФОРСУНОК
// ==================================================
void startInjectorCycle() {
injectorRunning = true;
currentInjector = 0;
currentCycle = 0;
injectorButtonLocked = true;
digitalWrite(
injectorPins[currentInjector],
HIGH
);
injectorStartTime =
micros();
}
// ==================================================
// РАБОТА ФОРСУНОК
// ==================================================
void updateInjectors() {
if (!injectorRunning)
return;
unsigned long now =
micros();
unsigned long requiredTime =
(unsigned long)injectorOpenTime *
1000UL;
if (
now - injectorStartTime >=
requiredTime
) {
digitalWrite(
injectorPins[currentInjector],
LOW
);
currentInjector++;
// Закончили четвёртую форсунку
if (currentInjector >= 4) {
currentInjector = 0;
currentCycle++;
// Все циклы закончены
if (
currentCycle >= injectorCycles
) {
injectorRunning = false;
injectorUnlockTime =
millis();
return;
}
}
// Следующая форсунка
digitalWrite(
injectorPins[currentInjector],
HIGH
);
injectorStartTime =
micros();
}
}
// ==================================================
// БЛОКИРОВКА КНОПКИ ФОРСУНОК
// ==================================================
void updateInjectorLock() {
if (!injectorButtonLocked)
return;
if (injectorRunning)
return;
if (
millis() - injectorUnlockTime >=
INJECTOR_LOCK_TIME
) {
injectorButtonLocked = false;
}
}
// ==================================================
// РЕЛЕ R1
// ==================================================
void updateRelay1() {
if (!relay1Active)
return;
if (
millis() - relay1StartTime >=
RELAY1_TIME
) {
digitalWrite(
relay1Pin,
LOW
);
relay1Active = false;
}
}
// ==================================================
// РЕЛЕ R2
// ==================================================
void updateRelay2() {
if (
relay2Button.stableState == LOW
) {
digitalWrite(
relay2Pin,
HIGH
);
} else {
digitalWrite(
relay2Pin,
LOW
);
}
}
// ==================================================
// OLED
// ==================================================
void updateDisplay() {
if (
millis() - lastDisplayUpdate <
DISPLAY_UPDATE_TIME
) {
return;
}
lastDisplayUpdate =
millis();
display.clearDisplay();
display.setTextColor(
SSD1306_WHITE
);
display.setTextSize(1);
display.setCursor(0, 0);
// Состояние форсунок
if (injectorRunning) {
display.print("INJECTING");
} else if (injectorButtonLocked) {
display.print("LOCKED");
} else {
display.print("READY");
}
// Время открытия форсунки
display.setTextSize(2);
display.setCursor(0, 14);
display.print("T:");
display.print(injectorOpenTime);
display.print("ms");
// Количество циклов
display.setCursor(0, 35);
display.print("N:");
display.print(injectorCycles);
display.setTextSize(1);
// Информация о форсунках
if (injectorRunning) {
display.setCursor(78, 16);
display.print("INJ:");
display.print(currentInjector + 1);
display.setCursor(78, 28);
display.print("CY:");
display.print(currentCycle + 1);
}
// Обратный отсчёт блокировки
else if (injectorButtonLocked) {
unsigned long elapsed =
millis() - injectorUnlockTime;
unsigned long remaining =
(
INJECTOR_LOCK_TIME -
elapsed +
999
) / 1000;
display.setCursor(78, 16);
display.print("LOCK");
display.setCursor(78, 28);
display.print(remaining);
display.print("s");
}
// ==================================================
// R1 — ОБРАТНЫЙ ОТСЧЁТ
// ==================================================
display.setCursor(0, 56);
display.print("R1:");
if (relay1Active) {
unsigned long elapsed =
millis() - relay1StartTime;
unsigned long remaining;
if (elapsed < RELAY1_TIME) {
remaining =
(
RELAY1_TIME -
elapsed +
999
) / 1000;
} else {
remaining = 0;
}
display.print(remaining);
display.print("s");
} else {
display.print("OFF");
}
// ==================================================
// R2
// ==================================================
display.print(" R2:");
if (
relay2Button.stableState == LOW
) {
display.print("ON");
} else {
display.print("OFF");
}
display.display();
}