#include <AccelStepper.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <Bounce2.h>
// Настройки для шаговых двигателей
#define DIR_PIN_SLIDER 2
#define STEP_PIN_SLIDER 3
#define DIR_PIN_ROTATE 4
#define STEP_PIN_ROTATE 5
AccelStepper stepperSlider(AccelStepper::DRIVER, STEP_PIN_SLIDER, DIR_PIN_SLIDER);
AccelStepper stepperRotate(AccelStepper::DRIVER, STEP_PIN_ROTATE, DIR_PIN_ROTATE);
// Дисплей SSD1306 (I2C)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Кнопки для меню
#define BUTTON_NEXT_PIN 6
#define BUTTON_SELECT_PIN 7
#define BUTTON_BACK_PIN 8
Bounce buttonNext = Bounce();
Bounce buttonSelect = Bounce();
Bounce buttonBack = Bounce();
// Переменные для таймлапса
bool timelapseMode = false;
unsigned long exposureTime = 1000; // Время экспозиции в миллисекундах
unsigned long pauseTime = 2000; // Время паузы в миллисекундах
unsigned long lastMoveTime = 0;
unsigned long lastExposureTime = 0;
bool isExposing = false;
// Параметры слайдера
long positionSlider = 0;
long positionRotate = 0;
int speed = 100; // Скорость движения двигателей
// Параметры меню
int menuIndex = 0;
String menuItems[] = {"Move Slider", "Move Rotate", "Timelapse", "Settings"};
int numMenuItems = 4;
// Функция для отображения меню на OLED
void displayMenu() {
u8g2.clearBuffer();
for (int i = 0; i < numMenuItems; i++) {
if (i == menuIndex) {
u8g2.drawStr(10, 15 + (i * 10), ">");
}
u8g2.drawStr(20, 15 + (i * 10), menuItems[i].c_str());
}
u8g2.sendBuffer();
}
// Функция для настройки таймлапса
void timelapseSetup() {
u8g2.clearBuffer();
u8g2.setCursor(0, 15);
u8g2.print("Exp Time: ");
u8g2.print(exposureTime);
u8g2.setCursor(0, 30);
u8g2.print("Pause Time: ");
u8g2.print(pauseTime);
u8g2.sendBuffer();
}
// Инициализация
void setup() {
// Инициализация шаговых двигателей
stepperSlider.setMaxSpeed(1000);
stepperRotate.setMaxSpeed(1000);
// Инициализация дисплея
u8g2.begin();
// Инициализация кнопок
pinMode(BUTTON_NEXT_PIN, INPUT_PULLUP);
pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP);
pinMode(BUTTON_BACK_PIN, INPUT_PULLUP);
buttonNext.attach(BUTTON_NEXT_PIN);
buttonSelect.attach(BUTTON_SELECT_PIN);
buttonBack.attach(BUTTON_BACK_PIN);
buttonNext.interval(25);
buttonSelect.interval(25);
buttonBack.interval(25);
}
// Основной цикл программы
void loop() {
buttonNext.update();
buttonSelect.update();
buttonBack.update();
// Обработка меню
if (buttonNext.fell()) {
menuIndex = (menuIndex + 1) % numMenuItems;
}
if (buttonSelect.fell()) {
switch (menuIndex) {
case 0:
// Движение слайдера
positionSlider += 1000;
stepperSlider.moveTo(positionSlider);
break;
case 1:
// Поворот платформы
positionRotate += 1000;
stepperRotate.moveTo(positionRotate);
break;
case 2:
// Режим таймлапса
timelapseMode = !timelapseMode;
break;
case 3:
// Настройки таймлапса
timelapseSetup();
break;
}
}
// Обновление дисплея
displayMenu();
// Движение двигателей
stepperSlider.run();
stepperRotate.run();
// Логика таймлапса
if (timelapseMode) {
unsigned long currentTime = millis();
if (!isExposing && currentTime - lastMoveTime >= pauseTime) {
// Двигаем двигатели во время паузы
positionSlider += 100;
positionRotate += 100;
stepperSlider.moveTo(positionSlider);
stepperRotate.moveTo(positionRotate);
lastMoveTime = currentTime;
isExposing = true;
lastExposureTime = currentTime;
}
if (isExposing && currentTime - lastExposureTime >= exposureTime) {
// Начинаем экспозицию, двигатели останавливаются
isExposing = false;
}
}
}