/*################### File version: 4.0 ##################*/
/*########################################################*/
/* Controllo stepmotor per il nastro trasportatore a      */
/* scopo didattico (il docente dovrà spiegarne il         */
/* funzionamento).                                        */
/* vengono utilizzati tre pulsanti:                       */
/*  - pulsante rosso P1 per halt e stop del motore;       */
/*  - pulsante verde P2 per controllare il senso          */
/*    di rotazione;                                       */
/*  - pulsante grigio per controllare il microstepping    */
/*    (quindi la velocità) del motore.                    */
/* Il programma utilizza per il tasto P1 tre funzioni     */
/* logiche con cui si tenta di simulare il comportamento  */
/* di un debounce hardware basato su flip flop; per il    */
/* tasto P2 la chiamata a funzione dove con tre funzioni  */
/* logiche simili a quelle per il tasto P1; per il tasto  */
/* P2 l'interrupt del microcontrollore.                   */
/*                                                        */
/*     driver A4988 e DRV8825                             */
/*         ,-----------,                                  */
/*  ENABLE |o         o| V_MOTORE                         */
/*     MS1 |o ____    o| GND                              */
/*     MS2 |o|    |   o| 2B                               */
/*     MS3 |o|____|   o| 2A                               */
/*   RESET |o         o| 1A                               */
/*   SLEEP |o     _   o| 1B                               */
/*    STEP |o    |_|  o| VDD                              */
/*     DIR |o         o| GND                              */
/*         `-----------'                                  */
/*                                                        */
/*    ==========================================          */
/*     MS1 | MS2	|  MS3 |  stepLevel resolution          */
/*    -----|------|------|----------------------          */
/*    Low	 | Low	| Low	 |  Full step                     */
/*    High | Low	| Low	 |  1/2 step                      */
/*    Low	 | High |	Low	 |  1/4 step                      */
/*    High | High |	Low	 |  1/8 step                      */
/*    High | High |	High |	1/16 step                     */
/*    =========================================           */
/*########################################################*/
//##### urutils.h #####
void waitUntilInputLow(int btn, unsigned t)
{
   do{
	 delay(t);
   }while(digitalRead(btn)!=LOW);
}

struct DiffTimer
{
	volatile unsigned long elapsed, last;
	volatile bool timerState=false;
	void reset(){
	    elapsed = 0;
	    last = millis();
	}
	void toggle(){
	    if(timerState){
    	        stop();
	    }else{
		start();
	    }	
	}
	void stop(){
	    if(timerState){
		timerState = false;
    	        elapsed += millis() - last;
	    }	
	}
	void start(){
	    if(!timerState){
		timerState = true;
		last = millis();
	    }
	}
	unsigned long get(){
	    if(timerState){
		return millis() - last + elapsed;
	    }
	    return elapsed;
	}
	void set(unsigned long e){
	    reset();
	    elapsed = e;
	}
};
//##### urutils.h #####
#include <TimerOne.h>  // Libreria per gestire interrupt basati su timer
#define dirPin 6 //2
#define stepPin 3
#define button_ForwardReverse 5
#define button_HaltStart 4
#define button_Microstep 2 //6
#define  DEBOUNCETIME 50

volatile bool dirChange = false;
volatile bool directionChange;
volatile bool direction = true;
volatile bool stato = false;
volatile bool stepChange = false;
volatile int count1 = 0;
DiffTimer deb;
uint16_t speed;
uint8_t startStopPin = 0;
uint8_t stepLevel = 0;
uint16_t stepInterval = 1200; // Microsecond (600µs HIGH + 600µs LOW)

int MS[3] = {9, 8, 7}; // pin microstepper MS1=MS[0]->9, MS2=MS[1]->8, MS3=MS[2]->7
boolean microstepArray[5][3] = {
 {LOW, LOW, LOW},
 {HIGH, LOW, LOW},
 {LOW, HIGH, LOW},
 {HIGH, HIGH, LOW},
 {HIGH, HIGH, HIGH} 
};

enum resolution{
	FULL,
	HALFT,
	QUARTER,
	EIGHTH,
	SIXTEENTH
};

// Definizione per lo stato dei pulsanti
struct Button {
  uint8_t pin;
  uint8_t val0;
  uint8_t val;
  //uint8_t count;
  //bool state;
  bool changed() {
	val = digitalRead(pin);
	bool changed = (val != val0);
	val0 = val;	// aggiornamento livello precedente al livello attuale
	return changed;     // ritorna il valore attuale del pulsante
  }
};

Button buttonStart = {button_HaltStart, LOW};
Button buttonDir = {button_ForwardReverse, LOW};
Button buttonStep = {button_Microstep, LOW};

bool setResolution(uint8_t level){
	if (level < 0 || level > 4) return false;
	Serial.print("Res: ");
	for (int i = 0; i < 3; i++) {
      digitalWrite(MS[i],microstepArray[level][i]);
      Serial.print(microstepArray[level][i]);
    }
	Serial.println();
	return true;
}

// Funzione di interrupt per controllare gli step del motore
void stepMotor() {
  static bool stepState = false;
  
  if (directionChange) {
    return;  // Non generare step durante il cambio di direzione
  }
  
  stepState = !stepState;
  digitalWrite(stepPin, stepState);
}

void setup() {
  Serial.begin(115200);
 
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(MS[0], OUTPUT);
  pinMode(MS[1], OUTPUT);
  pinMode(MS[2], OUTPUT);
  pinMode(button_ForwardReverse, INPUT);
  pinMode(button_HaltStart, INPUT);
  pinMode(button_Microstep, INPUT);
   
  setResolution(FULL);
  stato = false;
  speed = 600;
  direction = true;
  directionChange = false;
  deb.start();
  
  // Configura l'interrupt di timer per gli step del motore
  Timer1.initialize(stepInterval/2);  // Metà del periodo totale
  Timer1.attachInterrupt(stepMotor);
  Timer1.stop();  // Ferma il timer finché non è necessario
}

void loop() {
	
	if(deb.get() >= DEBOUNCETIME) {                       
		deb.reset();   
	
		if(buttonStep.changed()){
			if(buttonStep.val){
			  stepLevel++;
			  stepLevel = stepLevel%5;
			  setResolution(stepLevel);
			}
		}

		if(buttonDir.changed()){
		  //digitalWrite(stepPin, LOW);
		  directionChange = true;
			Serial.print("Direction: ");Serial.println(buttonDir.val);
		  delay(1000);
		  digitalWrite(dirPin, buttonDir.val);
		  directionChange = false;
		  //digitalWrite(stepPin, HIGH);
		}

		if(buttonStart.changed()){
			if(buttonStart.val){
				Timer1.start();
				Serial.println("Timer started");
			}else{
				Timer1.stop();
				Serial.println("Timer stopped");
			}
		}
	}
  delay(1);
}
$abcdeabcde151015202530354045505560fghijfghij
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
stepper1:A-
stepper1:A+
stepper1:B+
stepper1:B-
A4988
drv2:ENABLE
drv2:MS1
drv2:MS2
drv2:MS3
drv2:RESET
drv2:SLEEP
drv2:STEP
drv2:DIR
drv2:GND.1
drv2:VDD
drv2:1B
drv2:1A
drv2:2A
drv2:2B
drv2:GND.2
drv2:VMOT
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
vcc1:VCC
gnd1:GND
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
r4:1
r4:2
r5:1
r5:2
r6:1
r6:2
led1:A
led1:C
r7:1
r7:2
r3:1
r3:2