//#include <GyverOLED.h>
#include <EncButton.h>
#include <AccelStepper.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define ORANGE 0xFF00
//#define OLED_SOFT_BUFFER_64 // Буфер на стороне МК
//GyverOLED<SSD1306_128x64> oled; // Обьект дисплея
EncButton eb (3, 2, 4) ; // энкодер с кнопкой <A, B, KEY>
const int RIGHT_BUTTON_PIN = 5; // кнопка на пине 12
const int LEFT_BUTTON_PIN = 5; // кнопка на пине 8
const int RESET_BUTTON =-1; // сброс первого зуба
//#define EB_HOLD_TIME 5000 // время удержания кнопки єнкодера для входа в меню
#define STEP_PIN 7 // Подключение шагового двигателя к пинам
#define DIR_PIN 6 // Подключение шагового двигателя к пинам
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
int dir = -1; //используется для смены направления
int buzzerPin = 12; //Пищалка
int microstepping ;
float circle = 360; // Для вычисления углов
bool previousRunState = false;
volatile bool isRunning = false;
//----------- меню -----------
#define ITEMS 12
const char i0[] PROGMEM = " Steps :";
const char i1[] PROGMEM = " Speed :";
const char i2[] PROGMEM = " MicroStep :";
const char i3[] PROGMEM = " Step :";
const char i4[] PROGMEM = " Accel :";
const char i5[] PROGMEM = " Parameter 5:";
const char i6[] PROGMEM = " Parameter 6:";
const char i7[] PROGMEM = " Parameter 7:";
const char i8[] PROGMEM = " Parameter 8:";
const char i9[] PROGMEM = " Parameter 9:";
const char i10[] PROGMEM = " Parameter 10:";
const char i11[] PROGMEM = " Parameter 11:";
const char* const names[] PROGMEM = {
i0, i1, i2, i3,
i4, i5, i6, i7,
i8, i9, i10, i11
};
int16_t data[ITEMS];
int step = 2; // Минимальное количество зубов на делителе
bool flag = true;
bool allowChange = false;
bool menuChange = false; //флаг скрытого меню
unsigned long lastChangeTime = 0; // переменная для отслеживания времени последнего изменения
// -----------------------------------------------------
const uint8_t lock_19x16[] PROGMEM = {
0x00, 0x80, 0xF8, 0xFC, 0x8E, 0x86, 0x86, 0x86, 0x86, 0x9C, 0xFC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t unlock_19x16[] PROGMEM = {
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0xFC, 0x86, 0x06, 0x06, 0x06, 0x06, 0xFC, 0xF8, 0x00,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
};
void setup() {
Serial.begin(9600);
tft.begin();
tft.setRotation (1);
tft.drawRoundRect (0, 0, 320, 240, 6, CYAN);
pinMode (buzzerPin, OUTPUT); //BUZZER
//oled.init(); // инициализация экрана
//oled.setContrast(255); //Яркость экрана
attachInterrupt(0, isr, CHANGE);
attachInterrupt(1, isr, CHANGE);
eb.setHoldTimeout(6000);
data[0] = 2; //делитель вращения
data[1] = 300; //скорость вращения
data[2] = 16; //режим дробления шага
data[3] = 200; //шаги на 1 оборот
data[4] = 500; //Ускорение
data[5] = 1; //текущее положение
stepper.setMaxSpeed(data[1]);
stepper.setAcceleration(data[4]);
stepper.setCurrentPosition(0);
attachInterrupt(digitalPinToInterrupt(RIGHT_BUTTON_PIN), runButtonISR, FALLING);
}
void runButtonISR()
{
isRunning = !isRunning;
}
void isr()
{
eb.tickISR(); // специальный тикер прерывания для энкодера
}
void setMicrostepping(int16_t microsteps)
{
}
void loop()
{
eb.tick(); // опрос энкодера происходит здесь
int buttonStateIGHT = digitalRead(RIGHT_BUTTON_PIN);
int buttonStateLEFT = digitalRead(LEFT_BUTTON_PIN);
int buttonStateRESET = digitalRead(RESET_BUTTON);
static int lastButtonStateIGHT = HIGH;
static int lastButtonStateLEFT = HIGH;
static int lastButtonStateRESET = HIGH;
if (buttonStateIGHT == LOW && lastButtonStateIGHT == HIGH)
{
tone (buzzerPin, 1100);
delay (50);
noTone (buzzerPin);
Serial.println ("крутим вправо");
int stepsToMove = data[3];
stepper.move((stepsToMove * data[2]) / data[0]);
data [5] ++; //текущий зуб
if (data [5] > data [0] )
{
data [5]=1;
tone (buzzerPin, 500);
delay (50);
tone (buzzerPin, 700);
delay (50);
tone (buzzerPin, 200);
noTone (buzzerPin);
}
if (data [5] == -1)
{
data [5]=1;
}
isRunning = true; // Установка флага isRunning в true (двигатель вращаеться)
while (stepper.distanceToGo() != 0)
{
stepper.run();
}
isRunning = false;// Сброс флага isRunning в false (двигатель не вращаеться)
tone (buzzerPin, 900);
delay (50);
noTone (buzzerPin);
stepper.stop();
Serial.println ("доехали");
stepper.setCurrentPosition(0); // Сброс позиции для следующего оборота
}
lastButtonStateIGHT = buttonStateIGHT;
if (buttonStateLEFT == LOW && lastButtonStateLEFT == HIGH) {
tone (buzzerPin, 1100);
delay (50);
noTone (buzzerPin);
Serial.println ("Крутим влево");
int stepsToMove = data[3];
stepper.move(((stepsToMove * data[2]) / data[0])*dir);
data [5] --; //текущий зуб
if (data [5] < (data [0] / (-1) ))
{
data [5]=1;
tone (buzzerPin, 500);
delay (50);
tone (buzzerPin, 700);
delay (50);
tone (buzzerPin, 200);
noTone (buzzerPin);
}
if (data [5] == 0)
{
data [5]=-2;
}
isRunning = true; // Установка флага isRunning в true (двигатель вращаеться)
while (stepper.distanceToGo() != 0) {
stepper.run();
}
isRunning = false;// Сброс флага isRunning в false (двигатель не вращаеться)
tone (buzzerPin, 900);
delay (50);
noTone (buzzerPin);
stepper.stop();
Serial.println ("доехали");
stepper.setCurrentPosition(0); // Сброс позиции для следующего оборота
}
lastButtonStateLEFT = buttonStateLEFT;
if (buttonStateRESET == LOW && lastButtonStateRESET == HIGH)
{
tone (buzzerPin, 2200);
delay (50);
noTone (buzzerPin);
Serial.println ("переназначение первого зуба");
data[5] = 1;
}
lastButtonStateRESET = buttonStateRESET;
if (eb.hold())
{
tone (buzzerPin, 1100);
delay (50);
noTone (buzzerPin);
delay (100);
menuChange = !menuChange;
Serial.println("скрытое меню");
}
if (menuChange)
{
static int8_t pointer = 0;
if (eb.left() || eb.leftH())
{
if (flag)
{
pointer = constrain(pointer - 1, 0, ITEMS - 1);
}
else
{
if (pointer == 2)
{
// Ограничиваем изменение значений data[2] (микрошаг)
if (data[pointer] == 32)
{
data[pointer] = 16;
}
else if (data[pointer] == 16)
{
data[pointer] = 8;
} else if (data[pointer] == 8)
{
data[pointer] = 4;
}
else if (data[pointer] == 4)
{
data[pointer] = 2;
}else if (data[pointer] == 2)
{
data[pointer] = 1;
}
else if (data[pointer] == 1)
{
data[pointer] = 32;
}
setMicrostepping(data[pointer]);
}
else if (pointer == 1)
{
// Изменение для "Speed" кратно 100
data[pointer] = constrain(data[pointer] - 50, 0, 10000);
}
else if (pointer == 4)
{
// Изменение для "accel" кратно 100
data[pointer] = constrain(data[pointer] - 100, 0, 30000);
}
else
{
data[pointer]++;
}
}
}
if (eb.right() || eb.rightH())
{
if (flag)
{
pointer = constrain(pointer + 1, 0, ITEMS - 1);
}
else
{
if (pointer == 2)
{
// Ограничиваем изменение значений data[2]
if (data[pointer] == 1)
{
data[pointer] = 2;
}
else if (data[pointer] == 2)
{
data[pointer] = 4;
}
else if (data[pointer] == 4)
{
data[pointer] = 8;
}
else if (data[pointer] == 8)
{
data[pointer] = 16;
}
else if (data[pointer] == 16)
{
data[pointer] = 32;
}
else if (data[pointer] == 32)
{
data[pointer] = 1;
}
setMicrostepping(data[pointer]);
}
else if (pointer == 1)
{
// Изменение для "Speed" кратно 100
data[pointer] = constrain(data[pointer] + 50, 0, 10000);
}
else if (pointer == 4)
{
// Изменение для "accel" кратно 100
data[pointer] = constrain(data[pointer] + 100, 0, 30000);
}
else
{
data[pointer]--;
}
}
}
if (eb.click())
{
flag = !flag;
}
tft.setCursor(0, 0);
tft.fillScreen(ILI9341_BLACK);
for (int16_t i = 0; i < 8; i++)
{
printMenuItem(pointer > 7 ? i + (pointer - 7) : i);
}
for (int16_t i = 0; i < 8; i++)
{
tft.setCursor(85, i);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2);
tft.print(data[pointer > 7 ? i + (pointer - 7) : i]);
}
printPointer(constrain(pointer, 0, 7));
//oled.update(); //++
}
else
{
if (eb.click())
{
tone (buzzerPin, 800);
delay (100);
noTone (buzzerPin);
delay (100);
Serial.println ("клик");
allowChange = !allowChange;
// Сбросить таймер при каждом нажатии
lastChangeTime = millis();
}
if (millis() - lastChangeTime >= 10000) {
allowChange = false; // Вернуть флаг в исходное состояние
}
if (allowChange)
{
if (eb.right())
{
tone (buzzerPin, 1200);
delay (50);
noTone (buzzerPin);
data[0] = data[0] ++; //пункт меню 1 который отображаеться на главном экране
step++;
data[0] = step;
}
else if (eb.left() && step > 2)
{
tone (buzzerPin, 1000);
delay (50);
noTone (buzzerPin);
data[0] = data[0] --;
step--;
data[0] = step;
}
}
// ------ Рамка----
// tft.drawRoundRect (0, 0, 320, 240, 6, CYAN);
//tft.fillRoundRect (1, 1, 80, 30, 6, GREEN);
//tft.fillScreen(ILI9341_BLACK);
//oled.line(1, 1, 128, 1);
//tft.drawLine(0, 10, 128, 10, MAGENTA);
//tft.drawLine(0, 36, 128, 36, MAGENTA);
//oled.roundRect(80, 42, 123, 60);
//oled.line(80, 42, 123, 42);
//oled.line(80, 60, 123, 60);
//oled.line(80, 42, 80, 60);
//oled.line(123, 42, 123, 60);
//oled.line(50, 1, 50, 64);
//oled.line(83, 1, 83, 64);
//oled.setScale(1);
tft.drawRoundRect (2, 2, 150, 50, 6, YELLOW);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(3);
tft.setCursor(10, 10);
tft.print("divider");//("Делитель");
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(3);
tft.setCursor(280, 10);
tft.drawRoundRect (255, 52, 62, 50, 6, RED);
tft.print(data[0]);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(3);
tft.setCursor(10, 60);
tft.drawRoundRect (2, 52, 150, 50, 6, YELLOW);
tft.print("current");//("Делитель");
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(3);
tft.setCursor(280, 60);
tft.drawRoundRect (255, 2, 62, 50, 6, RED);
tft.print(data[5]);
tft.setCursor(10, 210);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2);
tft.print("angle rotation");
tft.setTextColor(ILI9341_GREEN); tft.setTextSize(2);
tft.setCursor(240, 210);
tft.print(circle / data[0]);
//tft.drawBitmap(110, 40, bitmap_16x16, 16, 16);
if (allowChange)
{
//tft.drawBitmap(110, 45, unlock_19x16, 19, 16, CYAN);
}
else
{
// tft.drawBitmap(110, 100, lock_19x16, 19, 16, CYAN);
}
//tft.fillScreen(ILI9341_BLACK);
}
}
void printPointer(int16_t pointer)
{
if (flag)
{
//tft.setCursor(0, pointer);
//oled.setScale(1);
//tft.print(">");
}
else
{
//tft.setCursor(120, pointer);
//oled.setScale(1);
//tft.print("<");
}
}
void printMenuItem(int16_t num)
{
char buffer[21];
int16_t ptr = pgm_read_word(&(names[num]));
int16_t i = 0;
do
{
buffer[i] = (char)(pgm_read_byte(ptr++));
} while (buffer[i++] != NULL);
//oled.setScale(1);
//tft.println(buffer);
}