#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Encoder.h>
// === Настройки ===
#define MAX_POSITION 5000 // Макс. шагов (калибровать!)
#define ACCELERATION 800 // Ускорение
#define SPEED_AUTO 1200 // Скорость в авторежиме
#define TIMELAPSE_INTERVAL 5 // Интервал между кадрами (сек)
// === Пины ===
#define STEP_PIN 8
#define DIR_PIN 9
#define LIMIT_MIN 5
#define LIMIT_MAX 6
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
// === OLED ===
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// === Энкодер ===
Encoder myEncoder(ENCODER_CLK, ENCODER_DT);
long oldPosition = 0;
// === Слайдер ===
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
enum Mode { MANUAL, AUTO, TIMELAPSE };
Mode currentMode = MANUAL;
bool isRunning = false;
int targetPos = 0;
unsigned long lastTimelapseShot = 0;
void setup() {
Serial.begin(9600);
// Инициализация OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED не подключен!");
while (1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.display();
// Настройка двигателя
stepper.setMaxSpeed(SPEED_AUTO);
stepper.setAcceleration(ACCELERATION);
// Настройка пинов
pinMode(LIMIT_MIN, INPUT_PULLUP);
pinMode(LIMIT_MAX, INPUT_PULLUP);
pinMode(ENCODER_SW, INPUT_PULLUP);
// Калибровка (едем к MIN)
display.println("Calibrating");
display.display();
while (digitalRead(LIMIT_MIN) == HIGH) {
stepper.moveTo(-10000);
stepper.run();
}
stepper.setCurrentPosition(0);
display.clearDisplay();
updateDisplay();
}
void loop() {
// Обработка энкодера
long newPosition = myEncoder.read();
if (newPosition != oldPosition) {
int delta = (newPosition > oldPosition) ? 100 : -100;
targetPos = constrain(targetPos + delta, 0, MAX_POSITION);
stepper.moveTo(targetPos);
oldPosition = newPosition;
updateDisplay();
}
// Обработка кнопки энкодера (переключение режимов)
if (digitalRead(ENCODER_SW) == LOW) {
delay(200); // Дебаунс
switch (currentMode) {
case MANUAL: currentMode = AUTO; break;
case AUTO: currentMode = TIMELAPSE; break;
case TIMELAPSE: currentMode = MANUAL; break;
}
updateDisplay();
}
// Управление движением
switch (currentMode) {
case MANUAL:
if (stepper.distanceToGo() != 0) stepper.run();
break;
case AUTO:
if (stepper.distanceToGo() == 0) {
targetPos = (targetPos == 0) ? MAX_POSITION : 0;
stepper.moveTo(targetPos);
}
stepper.run();
break;
case TIMELAPSE:
if (millis() - lastTimelapseShot >= TIMELAPSE_INTERVAL * 1000) {
if (stepper.distanceToGo() == 0) {
targetPos = (targetPos == 0) ? MAX_POSITION : 0;
stepper.moveTo(targetPos);
}
stepper.run();
lastTimelapseShot = millis();
}
break;
}
// Защита от перегрузки
checkLimits();
}
// Проверка концевых выключателей
void checkLimits() {
if (digitalRead(LIMIT_MIN) == LOW && stepper.currentPosition() < 0) {
stepper.stop();
stepper.setCurrentPosition(0);
}
if (digitalRead(LIMIT_MAX) == LOW && stepper.currentPosition() > MAX_POSITION) {
stepper.stop();
stepper.setCurrentPosition(MAX_POSITION);
}
}
// Обновление дисплея
void updateDisplay() {
display.clearDisplay();
display.setCursor(0, 0);
// Режим
display.print("Mode: ");
switch (currentMode) {
case MANUAL: display.println("Handle"); break;
case AUTO: display.println("Auto"); break;
case TIMELAPSE: display.println("TL"); break;
}
// Позиция
display.print("Pos: ");
display.print(stepper.currentPosition());
display.print("/");
display.println(MAX_POSITION);
// Цель
display.print("Tsel: ");
display.println(targetPos);
// Таймлапс (если активен)
if (currentMode == TIMELAPSE) {
display.print("Int: ");
display.print(TIMELAPSE_INTERVAL);
display.println(" sec");
}
display.display();
}