#include <LiquidCrystal_I2C_Hangul.h> // Подключение библиотеки для LCD
//Системные константы (ЗНАЧЕНИЯ НЕ ИЗМЕНЯТЬ)
#define PIN_STEP 3 // пины для подключения контактов STEP, DIR (шаг вращения)
#define PIN_DIR 2 // пины для подключения контактов DIR (направление вращения)
#define STEP_ROUND 200 // количество шагов на 1 оборот (ттх двигателя, 1 шаг = 1.8 градуса)
LiquidCrystal_I2C_Hangul lcd(0x27, 20, 4); // Настройка подключенного дисплея
//Глобальные константы и переменные
#define LIMITER 15 // коэффициент замедления мотора (max = 16)
boolean G_direction = true; // Направление движения мотора (true = по часовой)
unsigned long time; // Хранение времени после старта работы
int lastValueReostat = 0; // Предыдущее состояние реостата
int nowValueReostat = 0; // Текущее состояние реостата (не важно, сразу обновится)
unsigned int limit = pow(2,LIMITER); // Константа для замедления мотора
unsigned long nowArr[] = {0, 0}; // Время следующего запуска функций
unsigned int skipArr[] = { // Количество миллисекунд между запусками функций
100, // кол-во ms между опросами реостата (для увеличения отклика - уменьшить)
300 // время между шагами двигателя (не важно, сразу обновится)
};
//Считать данные с реостата и скорректировать вращение мотора
void checkValue(){
nowArr[0] += skipArr[0]; // Установить время следующего исполнения
nowValueReostat = analogRead(A0); // Один раз опросить реостат и использовать это значение до нового обновления
if (lastValueReostat != nowValueReostat){ // Только если реостат изменил свое значение применить корректировку
skipArr[1] = limit/(nowValueReostat + 1); // редактировать ms между шагами двигателя (зависит от limit), чем меньше число, тем быстрее вращение
nowArr[1]=time+skipArr[1]; // Обновить время следующего шага двигателя
lastValueReostat = nowValueReostat; // Обновить положение реостата
updateDisplay(); // Обновить данные на дисплее
}
}
// Выполнить поворот двигателя на один шаг (1.8 градус)
void stepMotor(){
nowArr[1] = time + skipArr[1]; // Установить время следующего исполнения
if (nowValueReostat>5){ // Реагировать только если значение реостата превышает 5
digitalWrite(PIN_STEP, HIGH); // Включение и отключение сигнала на драйвер мотора
delay(1);
digitalWrite(PIN_STEP, LOW);
}
}
// Отобразить данные на дисплее
void updateDisplay(){
lcd.clear(); // Очистить состояние дисплея
lcd.setCursor(0, 0); // Печатать с 1 столбца и 1 строки
lcd.print(1000/skipArr[1]*1.8); // Вывести на экран значение поворота в градусах на секунду
lcd.print(" grad/s ");
int percent = constrain((nowValueReostat % 1024*0.1), 0, 100); // Скорость оборотов в процентах
if(percent/100>0) lcd.setCursor(16, 0); // Если число 1 знак то печатать с 17 столбца
else if(percent/10>0) lcd.setCursor(17, 0); // Если число 2 знак то печатать с 18 столбца
else lcd.setCursor(18, 0); // Иначе печатать с 19 столбца
lcd.print(percent); // Вывод данных
lcd.setCursor(19, 0);
lcd.print("%");
}
// Первоначальная настройка перед работой (системная функция)
void setup() {
// Serial.begin(115200); //Отладочный модуль, нужен для использования Serial.println();
pinMode(PIN_STEP, OUTPUT);
pinMode(PIN_DIR, OUTPUT);
pinMode(A0, INPUT);
digitalWrite(PIN_STEP, 0);
digitalWrite(PIN_DIR, G_direction);
lcd.init(); // Инициализация дисплея
lcd.backlight(); // Подсветка экрана вкл
lcd.begin(20, 4);
}
// Основной цикл программы (системная функция)
void loop() {
/*
Каждый такт получаем время с начала работы контроллера. Массив nowArr сожержит время следующего запуска функции.
Каждый цикл проверяется пришло ли время запустить нужную нам функцию, если да, то функция запускается,
внутри функции определяется время следующего ее запуска и так по кругу
Такой стиль исполнения кода называется EventLoop, он отлично эмулирует параллельность работы нескольких компонентов
*/
time = millis();
if(time > nowArr[0]) checkValue();
if(time > nowArr[1]) stepMotor();
}
/*
TODO
Необходимо дописать работу с реостатом для редактирования температуры и подсоединить сам нагревательный элемент
Добавить информативности на дисплей
*/