Doppio Encoder rotativo

Salve,
devo installare due Encoder rotativi su Arduino Uno. Grazie al codice messo a disposizione dal fornitore hardware, è stato semplice installare un encoder. Il problema si presenta nell’inserire il secondo encoder! ho provato a modificare il codice, generando dei problemi nei risultati ottenuti, in quanto se ruoto solo un encoder varia anche il risultato del secondo encoder pur essendo fermo, come da screen!
Vi ringrazio anticipatamente per la cortese attenzione.

////////////////////////////////////////////////////////////////////////////
//  Demo Program on YOUTUBE
//  
//  it's Arduino Software by VINARI ( www.makepcb.co.kr and www.kitnara.co.kr )
/////////////////////////////////////////////////////////////////////////////
#include<arduino.h>
#include <MsTimer2.h>

const int SSI_ENC_1_CLK = 6;  //red           // SSI  clk  - output
const int SSI_ENC_1_DAT = 7; //green         // SSI  data - input
const int SSI_ENC_2_CLK = 8;  //red           // SSI  clk  - output
const int SSI_ENC_2_DAT = 9; //green         // SSI  data - input
                        
word rD_SSI_Encoder_1_LpTm;          // Timer Buf
word rd_SSI_Encoder_1_Data = 0;      // Encoder Data Buf
word Old_rd_SSI_Encoder_1_Data = 0;  // Compare Encoder Data Buf
word Fix_SSI_Encoder_1_Data = 0;     // Final Encoder Data Buf
byte rD_SSI_Encoder_1_LpCnt = 0;     // 
byte rD_SSI_Encoder_1_Flag = 0;      // 
                        
word rD_SSI_Encoder_2_LpTm;          // Timer Buf
word rd_SSI_Encoder_2_Data = 0;      // Encoder Data Buf
word Old_rd_SSI_Encoder_2_Data = 0;  // Compare Encoder Data Buf
word Fix_SSI_Encoder_2_Data = 0;     // Final Encoder Data Buf
byte rD_SSI_Encoder_2_LpCnt = 0;     // 
byte rD_SSI_Encoder_2_Flag = 0;      // 
 
const word SS_HEX[12] =
{
  0x0800, 0x0400, 0x0200, 0x0100, 
  0x0080, 0x0040, 0x0020, 0x0010, 
  0x0008, 0x0004, 0x0002, 0x0001 
};

void Call_EncData_Sum(byte inbit, word *sumdata, byte rp)
{
  if(inbit) *sumdata +=  SS_HEX[rp];
}
////////////////Encoder 1/////////////////////
void rD_SSI_Encoder_1_Loop()
{

  byte rd_Data = 0,i;
  switch(rD_SSI_Encoder_1_LpCnt)
  {
  case 0:
    
    pinMode(SSI_ENC_1_CLK, OUTPUT); 
    pinMode(SSI_ENC_1_DAT, INPUT); 
    
    rD_SSI_Encoder_1_LpCnt = 0x10;
    break;
  case 0x10:
    rD_SSI_Encoder_1_LpTm = 0;       
    rD_SSI_Encoder_1_LpCnt = 0x12;
    break;
  case 0x12:
    if(rD_SSI_Encoder_1_LpTm < 100)  // waiting 100 ms
    {
    }
    else
    {
      rD_SSI_Encoder_1_LpCnt = 0x20;
    }
    break;

  case 0x20:
    rD_SSI_Encoder_1_LpTm = 0;       // INI. Timer
    rD_SSI_Encoder_1_LpCnt = 0x24;
    break;
  case 0x24:
    if(rD_SSI_Encoder_1_LpTm < 100)  // 
    {
    }
    else
    {
      rD_SSI_Encoder_1_LpCnt = 0x30;
    }
    break;
  case 0x30:
    digitalWrite(SSI_ENC_1_CLK,0);  // Clk output - 0
    digitalWrite(SSI_ENC_1_CLK,1);  // Clk output - 1
    rD_SSI_Encoder_1_LpCnt = 0x32;
    break;
  case 0x32:
    rd_SSI_Encoder_1_Data = 0;      
    for(i=0;i<12;i++)
    {
      rd_Data = digitalRead(SSI_ENC_1_DAT);                   // Read Data
      digitalWrite(SSI_ENC_1_CLK,0);                          // Clk output - 0
      Call_EncData_Sum(rd_Data, &rd_SSI_Encoder_1_Data, i);   // Make Sum Encoder Data
      digitalWrite(SSI_ENC_1_CLK,1);                          // Clk output - 1
    }
    rD_SSI_Encoder_1_LpCnt = 0x34;
    break;
  case 0x34:
    
    if(rD_SSI_Encoder_1_Flag == 0) rD_SSI_Encoder_1_LpCnt = 0x36;
    else rD_SSI_Encoder_1_LpCnt = 0x38;
    break;
  case 0x36:
    if(Old_rd_SSI_Encoder_1_Data>>2 != rd_SSI_Encoder_1_Data>>2)
    {
       
       Old_rd_SSI_Encoder_1_Data = rd_SSI_Encoder_1_Data;
       rD_SSI_Encoder_1_Flag = 1;
       rD_SSI_Encoder_1_LpCnt = 0x20;
    }
    else
    {
      rD_SSI_Encoder_1_LpCnt = 0xf0;
    }
    break;
  case 0x38:
      rD_SSI_Encoder_1_Flag = 0;
      Old_rd_SSI_Encoder_1_Data = rd_SSI_Encoder_1_Data;
      Fix_SSI_Encoder_1_Data = rd_SSI_Encoder_1_Data; // move data to final buf
      rD_SSI_Encoder_1_LpCnt = 0xf0;
    break;
  case 0xf0:
   
 
    
    rD_SSI_Encoder_1_LpCnt = 0x20;
    break;
  default:
    rD_SSI_Encoder_1_LpCnt = 0;
    break;
  }
}
////////////////Encoder 2/////////////////////
void rD_SSI_Encoder_2_Loop()
{

  byte rd_Data = 0,i;
  switch(rD_SSI_Encoder_2_LpCnt)
  {
  case 0:
    pinMode(SSI_ENC_2_CLK, OUTPUT); 
    pinMode(SSI_ENC_2_DAT, INPUT); 
    rD_SSI_Encoder_2_LpCnt = 0x10;
    break;
  case 0x10:
    rD_SSI_Encoder_2_LpTm = 0;       
    rD_SSI_Encoder_2_LpCnt = 0x12;
    break;
  case 0x12:
    if(rD_SSI_Encoder_2_LpTm < 100)  // waiting 100 ms
    {
    }
    else
    {
      rD_SSI_Encoder_2_LpCnt = 0x20;
    }
    break;

//////////////////////////////// Loop  ////////////////////////////////////    
  case 0x20:
    rD_SSI_Encoder_2_LpTm = 0;       // INI. Timer
    rD_SSI_Encoder_2_LpCnt = 0x24;
    break;
  case 0x24:
    if(rD_SSI_Encoder_2_LpTm < 100)  // 
    {
    }
    else
    {
      rD_SSI_Encoder_2_LpCnt = 0x30;
    }
    break;
  case 0x30:
    digitalWrite(SSI_ENC_2_CLK,0);  // Clk output - 0
    digitalWrite(SSI_ENC_2_CLK,1);  // Clk output - 1
    rD_SSI_Encoder_2_LpCnt = 0x32;
    break;
  case 0x32:
    rd_SSI_Encoder_2_Data = 0;      
    for(i=0;i<12;i++)
    {
      rd_Data = digitalRead(SSI_ENC_2_DAT);                   // Read Data
      digitalWrite(SSI_ENC_2_CLK,0);                          // Clk output - 0
      Call_EncData_Sum(rd_Data, &rd_SSI_Encoder_2_Data, i);   // Make Sum Encoder Data
      digitalWrite(SSI_ENC_2_CLK,1);                          // Clk output - 1
    }
    rD_SSI_Encoder_2_LpCnt = 0x34;
    break;
  case 0x34:
    
    if(rD_SSI_Encoder_2_Flag == 0) rD_SSI_Encoder_2_LpCnt = 0x36;
    else rD_SSI_Encoder_2_LpCnt = 0x38;
    break;
  case 0x36:
    if(Old_rd_SSI_Encoder_2_Data>>2 != rd_SSI_Encoder_2_Data>>2)
    {
       Old_rd_SSI_Encoder_2_Data = rd_SSI_Encoder_2_Data;
       rD_SSI_Encoder_2_Flag = 1;
       rD_SSI_Encoder_2_LpCnt = 0x20;
    }
    else
    {
      rD_SSI_Encoder_2_LpCnt = 0xf0;
    }
    break;
  case 0x38:
      rD_SSI_Encoder_2_Flag = 0;
      Old_rd_SSI_Encoder_2_Data = rd_SSI_Encoder_2_Data;
      Fix_SSI_Encoder_2_Data = rd_SSI_Encoder_2_Data; // move data to final buf
      rD_SSI_Encoder_2_LpCnt = 0xf0;
    break;
  case 0xf0:
    Serial.print("Ang");  
    Serial.print("     ");    
    Serial.print( Fix_SSI_Encoder_1_Data,HEX ); 
    Serial.print("     "); 
    Serial.print("Ang2°");  
    Serial.print("     ");    
    Serial.println( Fix_SSI_Encoder_2_Data,HEX );  
  
    rD_SSI_Encoder_2_LpCnt = 0x20;
    break;
    default:
    rD_SSI_Encoder_2_LpCnt = 0;
    break;
  }
}
///////////////////////////////////////////////////////////////////////////

#define Encoder_Reset_Timer_Offset ( 1000 * 30)

word Reset_Encoder_1_Point_LpTm = 0;
byte Reset_Encoder_1_Point_LpCnt = 0;

word Reset_Encoder_2_Point_LpTm = 0;
byte Reset_Encoder_2_Point_LpCnt = 0;

 

// function of timer interrupt

void Timer_1ms()
{
  rD_SSI_Encoder_1_LpTm++;
  Reset_Encoder_1_Point_LpTm++;
  rD_SSI_Encoder_2_LpTm++;
  Reset_Encoder_2_Point_LpTm++;
}


void setup()
{
  // Timer 1mS
  MsTimer2::set(1, Timer_1ms); // 500ms period
  MsTimer2::start();
  Serial.begin(9600);
}

void loop()
{
  rD_SSI_Encoder_1_Loop();
  rD_SSI_Encoder_2_Loop();
}

>Giovanni1974: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More → Modify che si trova in basso a destra del tuo post) e racchiudere il codice all’interno dei tag CODE (… sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non avrai sistemato il codice come richiesto, nessuno ti potrà rispondere, quindi ti consiglio di farlo al più presto. :wink:

Ciao, Giovanni.
Io faccio sempre così:

int E; // Risultato della routine encoder(): 1, -1, 0.
byte S; // Lettura dei due valori dell'encoder.
byte So;// Lettura precedente dell'encoder.
int X; // Usato in encoder() per evitare letture multiple.

void encoder()
{
//            PD 76543210
// S=3-PIND&B00000011; Gli I/O 0 e 1 sono PD0 e PD1, perciò non devo scorrere a destra.
// S=3-(PIND>>3)&B00000011; Serviva per l'encoder su PD3 e PD4.
// S=3-((PIND>>4)&B00000011); // Gli I/O 4 e 5 erano PD4 e PD5, perciò dovevo scorrere a destra di 4 bit.
S=3-((PIND>>2)&B00000011); // Uso PD2 e PD3, quindi scorro a destra di 2 bit per farli diventare 0 e 1. 
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11).  
S^=S>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
         // ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if (S!=So && S==0) X=0;
if (X==0)
  {
  if (So==1&&S==2)
    {E=1; X=1;
    // Bip();
    }
  if (So==3&&S==2)
    {E=-1; X=1;
    // Bip();
    }
  if (S==0)
    {E=0; X=0;}
  So=S;  
  }
}

Per usare due encoder, devi solo usare altri due pin, adattando la parte iniziale.

Per due encoder diventa (salvo errori...):

int E1; // Risultato della routine encoder() per l'encoder1: 1, -1, 0.
int E2; // Risultato della routine encoder() per l'encoder2: 1, -1, 0.
byte S1; // Lettura dei due valori dell'encoder1.
byte S2; // Lettura dei due valori dell'encoder2.
byte S1o;// Lettura precedente dell'encoder1.
byte S2o;// Lettura precedente dell'encoder2.
int X1; // Usato in encoder() per evitare letture multiple.
int X2; // Usato in encoder() per evitare letture multiple.

void encoder()
{
E1=0; E2=0;
// ENCODER 1:
//             PD 76543210
S1=3-((PIND>>2) &B00000011); // Uso PD2 e PD3, quindi scorro a destra di 2 bit per farli diventare 0 e 1.
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11). 
S1^=S1>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
         // ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if (S1!=S1o && S1==0) X1=0;
if (X1==0)
  {
  if (S1o==1 && S1==2)
    {E1=1; X1=1;
    // Bip();
    }
  if (S1o==3 && S1==2)
    {E1=-1; X1=1;
    // Bip();
    }
  if (S1==0)
    {E1=0; X1=0;}
  S1o=S1; 
  }

S2=3-((PIND>>4) &B00000011); // Uso PD4 e PD5, quindi scorro a destra di 4 bit per farli diventare 0 e 1.
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11). 
S2^=S2>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
         // ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
if (S2!=S2o && S2==0) X2=0;
if (X2==0)
  {
  if (S2o==1 && S2==2)
    {E2=1; X2=1;
    // Bip();
    }
  if (S2o==3 && S2==2)
    {E2=-1; X2=1;
    // Bip();
    }
  if (S2==0)
    {E2=0; X2=0;}
  S2o=S2; 
  }
}

Dopo aver chiamato la funzione hai i risultati in E1 ed E2, che possono valere 0 (nessun movimento), +1 (incremento), -1 (decremento). Naturalmente, puoi anche farli restituire alla funzione.

Bip() è una funzione che contiene solo un tone() alla frequenza, della durata e sul pin che preferisci. Se usi un cicalino autooscillante (che richiede solo i 5V) diventa: digitalWrite(PIN, HIGH); delay(100); digitalWrite(pin, LOW);
delay(100); è la durata del bip. Usando il delay, l'esecuzione si blocca per un attimo. Se è un problema, devi fare diversamente. Comunque, se il bip non ti serve, puoi lasciarlo come commento o cancellarlo.

Per come ho modificato il codice, A e B degli encoder devono stare sugli I/O 2 e 3 e sugli I/O 4 e 5, ma è possibile modificarli, pur mantenendo almeno quelli di ogni encoder sulla stessa porta (B o D) per evitare errori dovuti alle letture non contemporanee.

Grazie Gianluca per la cortese attenzione e per il tempo dedicato, analizzando bene la modifica apportata al codice originale non avevo cambiato lo switch! ora sembra andare bene.. dico sembra perchè ogni tanto mi restituisce un valore diverso.. credo sia dovuto agli encoder cinesi. speriamo che tengono!
Distinti Saluti

Prego, Giovanni :slight_smile:

Per risolvere il problema, se il tuo loop() gira molto velocemente e puoi rallentarlo un po' senza problemi, prova ad aggiungere delay(10); dopo la chiamata a encoder().