Advertisement
TolentinoCotesta

Encoder_quadratura

Jun 5th, 2018
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.95 KB | None | 0 0
  1. #include <Wire.h>
  2. #include <LiquidCrystal_I2C.h>
  3. LiquidCrystal_I2C lcd(0x3F,20,4);
  4.  
  5.  
  6. // Modifica DEBUG in true per stampare sul monitor seriale
  7. // Impostare a false per velocizzare al massimo la ISR
  8. #define DEBUG false
  9. #if DEBUG
  10.   #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
  11.   #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
  12. #else
  13.   #define DEBUG_PRINT(...)
  14.   #define DEBUG_PRINTLN(...)
  15. #endif
  16.  
  17.  
  18. // Definizione degli ingressi
  19. #define ENC_A 2     // PIN D2  
  20. #define ENC_B 3     // PIN D3
  21. #define RESET 4     // PIN D4
  22.  
  23. // Dichiarazione delle variabili globali
  24. const double mt_per_impulso = 0.001F;
  25. const int direzione = +1;   // Se il conteggio viene eseguito al contrario impostare -1
  26. double distanza = 0;
  27. long contatore = 0;
  28.  
  29. unsigned long aggiornaLCD;
  30.  
  31. void setup(){
  32.   pinMode(ENC_A, INPUT_PULLUP);  
  33.   pinMode(ENC_B, INPUT_PULLUP);
  34.   pinMode(RESET, INPUT_PULLUP);
  35.  
  36.   Serial.begin (19200);
  37.   Serial.println("Start");
  38.  
  39.   // Attach Interrupt Service Routine to both interrupt pins
  40.   attachInterrupt(digitalPinToInterrupt(ENC_A), leggi_encoder, CHANGE);
  41.   attachInterrupt(digitalPinToInterrupt(ENC_B), leggi_encoder, CHANGE);
  42.    
  43.   lcd.init();
  44.   lcd.backlight();
  45.   lcd.setCursor(0,0);
  46.   lcd.print("Distanza misurata: ");
  47.   lcd.setCursor(0,1);
  48. }
  49.  
  50.  
  51. // Ciclo principale
  52. void loop(){
  53.   if(digitalRead(RESET) == LOW){
  54.     contatore = 0;
  55.   }
  56.  
  57.   distanza = contatore * mt_per_impulso;
  58.  
  59.   if(millis()- aggiornaLCD > 200){
  60.     aggiornaLCD = millis();
  61.     DEBUG_PRINT("Conteggio attuale: ");
  62.     DEBUG_PRINT(contatore);
  63.     DEBUG_PRINT("; Distanza misurata: ");
  64.     DEBUG_PRINT(distanza);
  65.     DEBUG_PRINTLN(" metri.");    
  66.     lcd.setCursor(0,1);
  67.     lcd.print(distanza);
  68.     lcd.print(" metri.");
  69.   }
  70. }
  71.  
  72.  
  73. /*
  74.   La variabile "statoEncoder" terrà conto contemporaneamente dello stato precedente
  75.   e di quello attuale degli ingressi collegati all'encoder PINA e PINB secondo il seguente schema:
  76.  
  77.   statoEncoder bit n:
  78.   7     6       5       4       3       2       1       0
  79.   NULL  NULL    NULL    NULL    OLDA    OLDB    PINA    PINB
  80.  
  81.   Per come funziona un encoder in quadratura, solo alcune combinazioni sono valide:
  82.  
  83.                             _______         _______      
  84.                 PinA ______|       |_______|       |______ PinA
  85.   negativo <---         _______         _______         __      --> positivo
  86.                 PinB __|       |_______|       |_______|   PinB
  87.  
  88.         OLDA    OLDB    PINA    PINB    Valore  Array
  89.         0       0       0       1       +1      (indice 1)
  90.         0       0       1       0       -1      (indice 2)
  91.         0       1       0       0       -1      (indice 4)
  92.         0       1       1       1       +1      (indice 7)
  93.         1       0       0       0       +1      (indice 8)
  94.         1       0       1       1       -1      (indice 11)
  95.         1       1       0       1       -1      (indice 13)
  96.         1       1       1       0       +1      (indice 14)        
  97. */
  98.  
  99.  
  100. const int statiValidi[] = {0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, +1, 0};  
  101. volatile uint8_t statoEncoder = 0;
  102. volatile uint8_t indiceArray = 0;
  103. volatile bool ticToc = false;
  104.  
  105. // ISR (Interrupt Service Routine) associata al cambiamento di stato di PINA e PINB
  106. void leggi_encoder(){    
  107.        
  108.   // Eseguo uno shift di due posizioni a sinistra per non sovrascrivere la lettura precedente  
  109.   statoEncoder <<= 2;
  110.  
  111.   // Imposto i bit relativi allo stato attuale di PINA e PINB  
  112.   // Leggo direttamente il valore della porta D per velocizzare il più possibile la ISR
  113.   // Inoltre, in questo modo posso anche eventualmente usare qualsiasi pin dell'ATmega328
  114.   // sfruttando il "pin change interrupt" invece degli "external interrupt" che sono associati solo a D2/D3
  115.   statoEncoder |=  bitRead(PIND, 2) << 1 | bitRead(PIND, 3) ;          
  116.  
  117.   // Applico la maschera per tenere conto solo dei 4 bit di encoderState realmente usati
  118.   indiceArray = 0b00001111 & statoEncoder;
  119.    
  120.   DEBUG_PRINT("Indice:\t");
  121.   DEBUG_PRINTLN(indiceArray);
  122.  
  123.   // Aggiorno il contatore solo quando ho una variazione sia di PINA che di PINB (quindi ogni 2 interrupt)  
  124.   if (ticToc) {
  125.     contatore += statiValidi[indiceArray] * direzione;    
  126.   }
  127.   ticToc = !ticToc;
  128.   DEBUG_PRINTLN();
  129. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement