#include <LiquidCrystal_I2C.h>
void refreshDisplay(int e=0, float mm=0);
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define ENCODER_CLK 2
#define ENCODER_DT 3
// ШД для перемещения
#define SMM_DIR 4
#define SMM_STEP 5
#define SMM_STEPS_PER_REVOLUTION 200
#define SMM_MM_PER_REVOLUTION 3.6
#define SMM_STEP_DELAY 20 // пауза между сменами значения на ноге для шага
boolean SMM_STEP_LEVEL = LOW;
int stepsForOneDirection;
// ШД для вращения
#define SMR_DIR 7
#define SMR_STEP 8
#define SMR_STEPS_PER_REVOLUTION 200
#define SMR_GBRatio 3 // коэф понижающего редуктора
#define SMR_STEP_DELAY 10 // пауза между сменами значения на ноге для шага
boolean SMR_STEP_LEVEL = LOW;
int stepsFromZero; // сколько шагов сделано от начала
int cuttingEdgesNum = 1; // кол-во режущих кромок 1-32
float mmToTool = 0.9; // мм от зубца до шлифовального диска
boolean allowSharping = false; // разрешение заточки
boolean needRefresh = true;
int lastMovementDir = 0; // последнее смещение энкодера
int progressPerc = 0;
//--------------------------------------
// mode:
// 0 - хз
// 1 - выбор количества режущих кромок
// 2 - мм от зубца до шлиф диска
// 3 - ожидание запуска - крутилкой "ожидание" => "старт", клик
// 4 - заточка показывается прогресс
int mode = 0;
//--------------------------------------
class button {
public:
button (byte pin) {
_pin = pin;
pinMode(_pin, INPUT_PULLUP);
}
bool click() {
bool btnState = digitalRead(_pin);
if (!btnState && !_flag && millis() - _tmr >= 100) {
_flag = true;
_tmr = millis();
return true;
}
if (!btnState && _flag && millis() - _tmr >= 500) {
_tmr = millis ();
return true;
}
if (btnState && _flag) {
_flag = false;
_tmr = millis();
}
return false;
}
private:
byte _pin;
uint32_t _tmr;
bool _flag;
};
// Инициализируем кнопку
const int modeSwitch_pin = 6;
button modeSwitch_btn(modeSwitch_pin);
// обработчик энкодера\крутилки
void readEncoder() {
int dtValue = digitalRead(ENCODER_DT);
if (dtValue == HIGH)
lastMovementDir++;
if (dtValue == LOW)
lastMovementDir--;
}
void setup() {
// lcd init
lcd.init();
lcd.backlight(); // new
// encoder
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
// sm init
pinMode(SMM_DIR, OUTPUT);
digitalWrite(SMM_DIR, HIGH);
pinMode(SMM_STEP, OUTPUT);
digitalWrite(SMM_STEP, LOW);
pinMode(SMR_DIR, OUTPUT);
digitalWrite(SMM_DIR, HIGH);
pinMode(SMR_STEP, OUTPUT);
digitalWrite(SMM_STEP, LOW);
}
// перерисовка дисплея
void refreshDisplay(int e=0, float mm=0){
lcd.clear();
switch(mode) {
case 0: lcd.print("idle..."); break;
case 1: lcd.print("edges: "); lcd.print(cuttingEdgesNum); break;
case 2: lcd.print("mm to tool: "); lcd.print(mmToTool); break;
case 3:
if (allowSharping)
lcd.print("press to start");
else
lcd.print("blocked");
break;
case 4:
lcd.print("progress: "); lcd.print(progressPerc); lcd.print("%");
if ((e>0) || (mm>0) ) {
lcd.setCursor(0, 1);
lcd.print("e: "); lcd.print(e);
lcd.print(" mm: ");lcd.print(mm);
}
break;
}
needRefresh = false;
}
void loop() {
// обработка кнопки
if (modeSwitch_btn.click()) {
if (mode!=3 || allowSharping) {
mode++;
needRefresh = true;
}
if (mode==4) {// заточка
stepsForOneDirection = mmToTool/SMM_MM_PER_REVOLUTION*SMM_STEPS_PER_REVOLUTION;
// цикл по количеству кромок
for(int e=1; e<=cuttingEdgesNum; e++) {
// цикл по шагам ШД в одну сторону
digitalWrite(SMM_DIR, HIGH);
for (int s=0; s<stepsForOneDirection ; s++) {
digitalWrite(SMM_STEP, HIGH);
delay(SMM_STEP_DELAY);
digitalWrite(SMM_STEP, LOW);
delay(SMM_STEP_DELAY);
progressPerc = 100 * ( (e*1.0-1)/cuttingEdgesNum + s*1.0/(stepsForOneDirection*cuttingEdgesNum*2) );
refreshDisplay(e, 1.0*mmToTool*(s+1)/stepsForOneDirection);
}
// цикл по шагам ШД в другую сторону
digitalWrite(SMM_DIR, LOW);
for (int s=0; s< stepsForOneDirection; s++) {
digitalWrite(SMM_STEP, HIGH);
delay(SMM_STEP_DELAY);
digitalWrite(SMM_STEP, LOW);
delay(SMM_STEP_DELAY);
progressPerc = 100 * ( (e*1.0-1)/cuttingEdgesNum + s*1.0/(stepsForOneDirection*cuttingEdgesNum*2) + 1.0/(cuttingEdgesNum*2) );
refreshDisplay(e, mmToTool - 1.0*mmToTool*(s+1)/stepsForOneDirection);
}
// Смена режущей кромки
digitalWrite(SMR_DIR, HIGH);
for (stepsFromZero=round(1.0*(e-1)/cuttingEdgesNum * SMR_STEPS_PER_REVOLUTION * SMR_GBRatio); stepsFromZero< round(1.0*(e)/cuttingEdgesNum * SMR_STEPS_PER_REVOLUTION * SMR_GBRatio); stepsFromZero++) {
digitalWrite(SMR_STEP, HIGH);
delay(SMR_STEP_DELAY);
digitalWrite(SMR_STEP, LOW);
delay(SMR_STEP_DELAY);
}
} // цикл по шагам ШД в одну сторону
progressPerc = 100;
refreshDisplay();
}
if (mode>4) {
mode = 0;
allowSharping = false;
}
} // обработка кнопки
// обработка крутилки
if (lastMovementDir!=0) {
switch(mode) {
case 0: break;
case 1:
cuttingEdgesNum+=lastMovementDir;
if (cuttingEdgesNum<1) cuttingEdgesNum=1;
if (cuttingEdgesNum>32) cuttingEdgesNum=32;
needRefresh = true;
break;
case 2:
mmToTool+=lastMovementDir * 1.0 / 10;
needRefresh = true;
break;
case 3:
allowSharping = !allowSharping;
needRefresh = true;
break;
case 4: // хз
break;
}
lastMovementDir = 0;
} // обработка крутилки
// обновим экран, если надо
if (needRefresh) refreshDisplay();
}