gestione encoder

ciao questo codice serve per leggere i passi di un encoder, ho provato il codice senza la possibilità di azzerare i passi ogni secondo e funziona, quando ho aggiunto la parte per azzerare i passi ogni secondo non funziona, qualcuno può aiutarmi

//VARIABILI DI TEMPO
unsigned long istante_ultimo_cambiamento_stato = 0; 
int tempo_per_istante = 1000 ; // Periodo per ogni lettura degli impulsi in questo caso  1 secondo


//GESTIONE PWM DI POTENZA
#define pwm 5 // pin per il pwm del motore
int valorepwm = 0; // valore del duty cycle tra 0 e 255

// GESTIONE ENCODER 
#define encoderCLK 2 // CLK (canale A) connesso al pin D2
#define encoderDT 3  // DT (Canale B) connesso al pin D4
#define interrupt0 0 // Associato al pin 2 di Arduino
#define interrupt1 1
volatile int lastEncoded = 0;
volatile long encoderO = 0;
volatile long encoderA = 0;
 long encoderOeff = 0;
 long encoderAeff = 0;
volatile long encoderF = 0;
int lastMSB = 0;
int lastLSB = 0;




void setup() {
  
  // I pin sono impostati come ingresso
  pinMode(encoderCLK, INPUT);    // interrupt 0
  pinMode(encoderDT, INPUT);   
  pinMode(pwm,OUTPUT);

  
  attachInterrupt(1, Encoder, CHANGE);
  attachInterrupt(0, Encoder, CHANGE);
 
  Serial.begin(9600);
 
  analogWrite(pwm, 0);
}

void loop() {
 if (millis() -  istante_ultimo_cambiamento_stato >= tempo_per_istante) 
  {
     istante_ultimo_cambiamento_stato = millis();
    if(encoderO%4 == 0){
  encoderOeff = encoderO/4;
}
if(encoderA%4 == 0){
  encoderAeff = encoderA/4;
}

 encoderF = encoderOeff - encoderAeff ; 
     Serial.print("    ");
     Serial.print(encoderF);
     Serial.print("    ");
     Serial.print(encoderOeff);
     Serial.print("    ");
     Serial.println(encoderAeff);

      encoderO = 0; // resetto le variabili 
      encoderA = 0; // resetto le variabili    
 }

}

void Encoder(){
  int MSB = digitalRead(encoderCLK); 
  int LSB = digitalRead(encoderDT); 
 
  int encoded = (MSB << 1) |LSB; 
  int sum  = (lastEncoded << 2) | encoded; 
 
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderO ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderA ++;
 
  lastEncoded = encoded; 
}

un ulteriore codice con qualche aggiunta che non funziona

//VARIABILI DI TEMPO
unsigned long istante_ultimo_cambiamento_stato = 0; 
int tempo_per_istante = 1000 ; // Periodo per ogni lettura degli impulsi in questo caso  1 secondo


//GESTIONE PWM DI POTENZA
#define pwm 5 // pin per il pwm del motore
int valorepwm = 0; // valore del duty cycle tra 0 e 255

// GESTIONE ENCODER 
#define encoderCLK 2 // CLK (canale A) connesso al pin D2
#define encoderDT 3  // DT (Canale B) connesso al pin D4
#define interrupt0 0 // Associato al pin 2 di Arduino
#define interrupt1 1
volatile int lastEncoded = 0;
volatile long encoderO = 0;
volatile long encoderA = 0;
 long encoderOeff = 0;
 long encoderAeff = 0;
volatile long encoderF = 0;
int lastMSB = 0;
int lastLSB = 0;

bool i,j = 0;


void setup() {
  
  // I pin sono impostati come ingresso
  pinMode(encoderCLK, INPUT);    // interrupt 0
  pinMode(encoderDT, INPUT);   
  pinMode(pwm,OUTPUT);

  
  attachInterrupt(1, Encoder, CHANGE);
  attachInterrupt(0, Encoder, CHANGE);
 
  Serial.begin(9600);
 
  analogWrite(pwm, 0);
}

void loop() {
 if (millis() -  istante_ultimo_cambiamento_stato >= tempo_per_istante) 
  {
     istante_ultimo_cambiamento_stato = millis();
    if(encoderO%4 == 0 && i == 1){
  encoderOeff = encoderO/4;
  i = 0;
}
if(encoderA%4 == 0 && j == 1){
  encoderAeff = encoderA/4;
  j = 0;
}

 encoderF = encoderOeff - encoderAeff ; 
     Serial.print("    ");
     Serial.print(encoderF);
     Serial.print("    ");
     Serial.print(encoderOeff);
     Serial.print("    ");
     Serial.println(encoderAeff);

      encoderO = 0; // resetto le variabili 
      encoderA = 0; // resetto le variabili
 }
}

void Encoder(){
  int MSB = digitalRead(encoderCLK); 
  int LSB = digitalRead(encoderDT); 
 
  int encoded = (MSB << 1) |LSB; 
  int sum  = (lastEncoded << 2) | encoded; 
 
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderO ++; i = 1;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderA ++; j = 1;
 
  lastEncoded = encoded; 
}

nessun consiglio?

ma se invece di fare tanti calcoli usi il metodo "normale" per avere il valore dell'encoder

cambiando questo

   if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderO ++; i = 1;
   if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderA ++; j = 1;

e ovviamente anche le dichiarazioni di variabile e quant'altro
così:

if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) ValoreEncoder ++; 
if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) ValoreEncoder --;

Patrick_M perchè devo avere le due variabili separate, e quando le azzero (come quello che ho scritto nel mio sketck) i valori non tornano, hai qualche soluzione di come azzerarle? grazie

quello che vedo io è:
ogni secondo se ho mosso l'encoder, se uno dei valori ( destra o sinistra) è divisibile per 4 esegue la divisione e stampa la differenza tra i due poi azzera il contatore

quando dici che non funziona cosa vuol dire?
cosa dovrebbe fare secondo te?

Patrick_M esatto questo dovrebbe fare perchè i passi effettivi di un encoder usando questo sketch sono quando li dividi per 4 perche questo programma verica i cambi di stato.
Quando dico che non funziona intendo dire che quando inizio a girare perciò è effettivamente sta girando nella seriale si legge il valore dei passi pari a zero o per quanto meno siccuramente errati.
Il compito del programma è azzerare i passi allo scattare di ogni secondo

luchinho:
Patrick_M
esatto questo dovrebbe fare perchè i passi effettivi di un encoder usando questo sketch sono quando li dividi per 4 perche questo programma verica i cambi di stato.
Quando dico che non funziona intendo dire che quando inizio a girare perciò è effettivamente sta girando nella seriale si legge il valore dei passi pari a zero o per quanto meno siccuramente errati.
Il compito del programma è azzerare i passi allo scattare di ogni secondo

Un errore logico potrebbe essere sicuramente questo:

if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderO ++; i = 1;
if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderA ++; j = 1;

Le istruzioni sottolineate in rosso vengono SEMPRE eseguite, non sono condizionate dall'istruzione if. Se vuoi che siano dipendenti dalla condizione dell'if, devi usare le parentesi graffe:

if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) {
   encoderO ++;
   i = 1;
}

if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) {
   encoderA ++;
   j = 1;
}

Oltretutto, perché la funzione Encoder() non la richiami mai??? Cioè le istruzioni contenute nella funzione non saranno mai e poi mai eseguite se da qualche parte non la usi nel loop().

encoder viene chiamata dagli interrupts

però hai ragione, non avevo fatto caso alla struttura dell'if

certo, se non si usano le parentesi graffe solo la prima istruzione fa parte dell'if la successiva è come se fosse scritta fuori dal blocco

Grazie krypton18 hai ragione, ma non funziona nel modo corretto

Patrick_M:
encoder viene chiamata dagli interrupts

Ah chiedo venia, non l'avevo proprio notato.

Grazie krypton18 hai ragione, ma non funziona nel modo corretto

Cioè??? Qual è il comportamento del sistema?

Comunque se ricordo bene l'uso degli interrupt va in conflitto con la funzione millis(), cioè non permette a ques'ultima di tenere traccia del tempo in maniera corretta. La cosa più semplice da fare per la misura del tempo è utilizzare un modulo RTC, dal costo di pochi euro DS3231 - Arduino, che sicuramente non è influenzato dagli interrupt ed è anche più preciso della funzione millis() essendo che il suo orologio interno conta indipendentemente da ciò che fa Arduino.

Un esempio dell'uso dell'RTC nel tuo caso specifico potrebbe essere il seguente codice:

#include <DS3231.h> //RTC è collegato ai pin SDA e SCL di Arduino e lavora in I2C
#include <Wire.h>

... inclusione di librerie e/o altre dichiarazioni di variabili ...

DS3231 Clock;						//definizione dell'oggetto di tipo RTC DS3231

void setup () { 	
	
	... altro codice ...	
	
	Wire.begin();					// Start the I2C interface
	Clock.setSecond(0);				//Setto i secondi dell'RTC a zero
	
} 	

void loop () { 	
	
	static int lastsecond = 0;		//la variabile viene inizializzata a zero una sola volta
	int second = Clock.getSecond();	//acquisizione secondo corrente
	
	if (second != lastsecond) {		//se è trascorso più di un secondo...
		encoderA = 0;				//azzero passi encoder A
		encoder0 = 0;				//azzero passi encoder 0
		lastsecond = second;		//memorizzo il secondo corrente
	} 	
	.... altro codice ... 	
}	

.... altre funzioni ...

Esempio di collegamento del modulo RTC all'Arduino MEGA: