Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Wire.h>
- #include <LiquidCrystal_I2C.h>
- LiquidCrystal_I2C lcd(0x3F,20,4);
- // Modifica DEBUG in true per stampare sul monitor seriale
- // Impostare a false per velocizzare al massimo la ISR
- #define DEBUG false
- #if DEBUG
- #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
- #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
- #else
- #define DEBUG_PRINT(...)
- #define DEBUG_PRINTLN(...)
- #endif
- // Definizione degli ingressi
- #define ENC_A 2 // PIN D2
- #define ENC_B 3 // PIN D3
- #define RESET 4 // PIN D4
- // Dichiarazione delle variabili globali
- const double mt_per_impulso = 0.001F;
- const int direzione = +1; // Se il conteggio viene eseguito al contrario impostare -1
- double distanza = 0;
- long contatore = 0;
- unsigned long aggiornaLCD;
- void setup(){
- pinMode(ENC_A, INPUT_PULLUP);
- pinMode(ENC_B, INPUT_PULLUP);
- pinMode(RESET, INPUT_PULLUP);
- Serial.begin (19200);
- Serial.println("Start");
- // Attach Interrupt Service Routine to both interrupt pins
- attachInterrupt(digitalPinToInterrupt(ENC_A), leggi_encoder, CHANGE);
- attachInterrupt(digitalPinToInterrupt(ENC_B), leggi_encoder, CHANGE);
- lcd.init();
- lcd.backlight();
- lcd.setCursor(0,0);
- lcd.print("Distanza misurata: ");
- lcd.setCursor(0,1);
- }
- // Ciclo principale
- void loop(){
- if(digitalRead(RESET) == LOW){
- contatore = 0;
- }
- distanza = contatore * mt_per_impulso;
- if(millis()- aggiornaLCD > 200){
- aggiornaLCD = millis();
- DEBUG_PRINT("Conteggio attuale: ");
- DEBUG_PRINT(contatore);
- DEBUG_PRINT("; Distanza misurata: ");
- DEBUG_PRINT(distanza);
- DEBUG_PRINTLN(" metri.");
- lcd.setCursor(0,1);
- lcd.print(distanza);
- lcd.print(" metri.");
- }
- }
- /*
- La variabile "statoEncoder" terrà conto contemporaneamente dello stato precedente
- e di quello attuale degli ingressi collegati all'encoder PINA e PINB secondo il seguente schema:
- statoEncoder bit n:
- 7 6 5 4 3 2 1 0
- NULL NULL NULL NULL OLDA OLDB PINA PINB
- Per come funziona un encoder in quadratura, solo alcune combinazioni sono valide:
- _______ _______
- PinA ______| |_______| |______ PinA
- negativo <--- _______ _______ __ --> positivo
- PinB __| |_______| |_______| PinB
- OLDA OLDB PINA PINB Valore Array
- 0 0 0 1 +1 (indice 1)
- 0 0 1 0 -1 (indice 2)
- 0 1 0 0 -1 (indice 4)
- 0 1 1 1 +1 (indice 7)
- 1 0 0 0 +1 (indice 8)
- 1 0 1 1 -1 (indice 11)
- 1 1 0 1 -1 (indice 13)
- 1 1 1 0 +1 (indice 14)
- */
- const int statiValidi[] = {0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, +1, 0};
- volatile uint8_t statoEncoder = 0;
- volatile uint8_t indiceArray = 0;
- volatile bool ticToc = false;
- // ISR (Interrupt Service Routine) associata al cambiamento di stato di PINA e PINB
- void leggi_encoder(){
- // Eseguo uno shift di due posizioni a sinistra per non sovrascrivere la lettura precedente
- statoEncoder <<= 2;
- // Imposto i bit relativi allo stato attuale di PINA e PINB
- // Leggo direttamente il valore della porta D per velocizzare il più possibile la ISR
- // Inoltre, in questo modo posso anche eventualmente usare qualsiasi pin dell'ATmega328
- // sfruttando il "pin change interrupt" invece degli "external interrupt" che sono associati solo a D2/D3
- statoEncoder |= bitRead(PIND, 2) << 1 | bitRead(PIND, 3) ;
- // Applico la maschera per tenere conto solo dei 4 bit di encoderState realmente usati
- indiceArray = 0b00001111 & statoEncoder;
- DEBUG_PRINT("Indice:\t");
- DEBUG_PRINTLN(indiceArray);
- // Aggiorno il contatore solo quando ho una variazione sia di PINA che di PINB (quindi ogni 2 interrupt)
- if (ticToc) {
- contatore += statiValidi[indiceArray] * direzione;
- }
- ticToc = !ticToc;
- DEBUG_PRINTLN();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement