AtTiny85 Encoder – Attiny Slave

Nel corso degli ultimi articoli dedicati all’Attiny85 e l’encoder hai letto come usare quest’ultimo come master ed arduino come slave.

Attiny85 Encoder light

L’amico Cristian mi ha giustamente suggerito, nell’ultimo incontro, di invertire i ruoli I2C dei due componenti in gioco, è nato quindi questo articolo: AtTiny85 Encoder – Attiny Slave.

L’idea di usare l’attiny85 come master nella comunicazione rende il codice lato arduino meno complesso in quanto ogni invio di dati da parte dell’encoder arriva su arduino che ha una funzione sempre in ascolto sull’indirizzo specificato, come hai letto negli articoli della scorsa settimana.

Il limite della soluzione resta che logicamente dovresti avere un solo master in una comunicazione I2C e più slave, inoltre il “cervello” della comunicazione, quindi il master, non è di certo l’encoder ma arduino , o genuino, che hanno il controllo di tutto il resto del progetto e l’encoder viene interrogato dal microcontrollore quando gli occorre recuperare il dato di rotazione.

Vantaggi del AtTiny85 Encoder – Attiny Slave

Riprendendo i vantaggi esposti nel precedente paragrafo avere l’Attiny85 slave ti offre i seguenti vantaggi:

AtTiny-slave-Arduino-master-i2c

  • un unico Arduino/Genuino Master I2C
  • più di un encoder come slave
  • controllo delle comunicazioni dal microcontrollore principale
  • interrogazione puntuale dell’encoder slave in funzione della fase del progetto

Connessione del attiny85 slave

lo schema elettrico non varia tra la soluzione in cui l’arduino è slave e l’attiny85  master o questa proposta in quanto è sempre l’attiny85 a occuparsi della lettura dell’encoder ad esso connesso:

Attiny85 Encoder schema

ciò che varia è lo sketch che devi caricare sull’attiny85 e di conseguenza anche quello dell’arduino.

 

Lo sketch dell’AtTiny85 slave

// Code for the ATtiny85
#define I2C_SLAVE_ADDRESS 0x8 // Address of the slave
 
#include <TinyWireS.h>
#include "avr/interrupt.h"; 

#define encA 3
#define encB 4
#define swtc 1

volatile byte currentValue = 0;
volatile int  lastEncoded  = 0;
 
void setup()
{
    TinyWireS.begin(I2C_SLAVE_ADDRESS); // join i2c network
    //TinyWireS.onReceive(receiveEvent); // not using this
    TinyWireS.onRequest(requestEvent);
 
    pinMode(encA, INPUT_PULLUP);
    pinMode(encB, INPUT_PULLUP);
    pinMode(swtc, INPUT_PULLUP);
    digitalWrite(encA, HIGH);
    digitalWrite(encB, HIGH);
   
    GIMSK = 0b00100000;       // Enable pin change interrupts
    PCMSK = 0b00011010;       // Enable pin change interrupt PB3,PB4,PB1
    sei();                    // Turn on interrupts
}
 
void loop() {
    // This needs to be here
    TinyWireS_stop_check();
}
 
// Gets called when the ATtiny receives an i2c request
void requestEvent() {
    TinyWireS.send(currentValue);
    TinyWireS.send(digitalRead(swtc));
}

ISR(PCINT0_vect) {
  byte MSB = digitalRead(encA); //MSB = most significant bit
  byte LSB = digitalRead(encB); //LSB = least significant bit
  
  int encoded = (MSB << 1) |LSB; //converting 2 pin value to 1 number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the 
                                           //previous encoded value
  if(sum==0b1101 || sum==0b0100 || sum==0b0010 || sum==0b1011) currentValue++;
  if(sum==0b1110 || sum==0b0111 || sum==0b0001 || sum==0b1000) currentValue--;
  
  lastEncoded = encoded; //store this value for next time
}

Le parti principali dello sketch non sono variate, ossia la lettura e decodifica della quadratura dell’encoder per capire il verso di rotazione della manopola, ciò che varia è la parte relativa alla comunicazione i2c a partire dalla linea 02: definisci l’indirizzo su cui l’attiny dovrà rispondere alle chiamate i2c, se usi più slave ogniuno deve avere un indirizzo differente;

linea 04: includi la libreria “TinyWireS.h” al posto della TinyWireM.h in quanto la “S” finale indica la parte Slave;

linee 05-12: restano fondamentalmente invariate, ho eliminato qualche variabile non più necessaria;

linea 16: inizializzi la nuova istanza della libreria TinyWireS passandole l’indirizzo su cui deve rispondere;

linea 18: onRequest in questo caso è il metodo che usi sull’Attiny85, nei precedenti esempi lo hai utilizzato sull’Arduino, e richiama la funzione requestEvent ogni volta che riceve una richiesta dal Master;

linee 20-29: restno invariate;

linea 34: la funzione loop() è molto più semplice, si preoccupa solo di lanciare il metodo TinyWireS_stop_check();

linee 38-41: la funzione requestEvent invocata dal metodo onRequest alla linea 18, ogni volta che viene richimata invia 2 byte: il primo è il numero calcolato sulla rotazione dell’encoder ed il secondo è il valore di pressione del pulsante di cui l’encoder è dotato.

linee 43-58: sono invariate rispetto agli sketch precedenti e si preoccupano della decodifica dell’encoder.

Lo sketch dell’Arduino / Genuino Master IIC

Il codice dello sketch lato arduino è più semplice:

//Code for the Arduino Master
#include <Wire.h>

#define TARGET_ID 0x08

void setup()
{
 Wire.begin(); // join i2c bus (address optional for master)
 Serial.begin(9600); // start serial for output
}
 
void loop() {
  Wire.requestFrom(TARGET_ID, 2); // request 1 byte 
                                                     // from slave device
 
  while(Wire.available() > 0) {
    byte i = Wire.read();
    byte sw = Wire.read();
    
    Serial.print( "Enc: " );
    Serial.print( i );
    Serial.print( " - Switch: " );
    Serial.println( sw );
   }
 
delay(100);
}

le linee si sono ridotte a sole 27 in cui le principali differenze risiedono nella linea 04: in cui definisci l’indirizzo o gli indirizzi se fossero più di uno gli slave;

linee 06-10: l’inizializzazione della Wire avviene senza dover specificare l’indirizzo sul quale rispondere, lo hai inserito nella componente slave;

linea 13: componi la chiamata i2c verso il target di 2 byte;

linee 16-24: ad ogni ricezione del buffer I2C scrivi sul monitor seriale i valori che ti arrivano dall’incoder;

linea 26: attendi 100 millisecondi prima di eseguire un nuovo ciclo di loop();

Il video della soluzione con Attiny85 slave e Arduino/Genuino Master i2C

Con entrambi gli sketch funzionanti ecco il risultato:

  • Questo sito ed i suoi contenuti è fornito "così com'è" e Mauro Alfieri non rilascia alcuna dichiarazione o garanzia di alcun tipo, esplicita o implicita, riguardo alla completezza, accuratezza, affidabilità, idoneità o disponibilità del sito o delle informazioni, prodotti, servizi o grafiche correlate contenute sul sito per qualsiasi scopo.
  • Ti chiedo di leggere e rispettare il regolamento del sito prima di utilizzarlo
  • Ti chiedo di leggere i Termini e Condizioni d'uso del sito prima di utilizzarlo
  • In qualità di Affiliato Amazon io ricevo un guadagno dagli acquisti idonei qualora siano presenti link al suddetto sito.

Permalink link a questo articolo: https://www.mauroalfieri.it/elettronica/attiny85-encoder-attiny-slave.html

6 commenti

1 ping

Vai al modulo dei commenti

    • Marco Pisano il 23 Novembre 2016 alle 23:21
    • Rispondi

    Ciao,
    ho provato a realizzare il tuo progetto ma mi da errore compilando lo scketch del attiny85:

    Arduino:1.7.11 (Windows 7), Scheda:”ATtiny85 @ 1 MHz (internal oscillator; BOD disabled)”

    Nel platform.txt di terze parti non è definito il compiler.path. Si prega di segnalare questo problema al suo sviluppatore.

    Encoder1.ino: In function ‘void setup()’:

    Encoder1.ino:18:15: error: ‘class USI_TWI_S’ has no member named ‘onRequest’

    Encoder1.ino:20:19: error: ‘INPUT_PULLUP’ was not declared in this scope

    Encoder1.ino: In function ‘void loop()’:

    Encoder1.ino:33:26: error: ‘TinyWireS_stop_check’ was not declared in this scope

    Errore durante la compilazione

    1. Ciao Marco,
      purtroppo il mio sketch è stato sviluppato e testato con l’IDE del sito arduino.cc, oggi alla versione 1.6.12.
      L’ide che stai utilizzando potrebbe avere delle differenti implementazioni ed uso delle schede di terze parti.

    • Dino il 26 Novembre 2017 alle 01:11
    • Rispondi

    Ciao,
    innanzitutto ti ringrazio per il tempo che dedichi a pubblicare ed a spiegare il codice.
    Vorrei chiederti se secondo te è possibile utilizzare lo sketch che hai pubblicato anche per controllare la posizione dell’asse di un motore DC collegato ovviamente ad un encoder, in particolare avrei bisogno di capire la massima frequenza alla quale si possono leggere i valori ed il tempo impiegato alla trasmissione della lettura.

    Grazie

    1. Ciao Dino,
      si è possibile usare l’attiny per fare quello che desideri, dovrai modificare, ovviamente, il codice in quanto questo non possiede tale possibilità e sacrificare l’I2C.

        • Dino il 1 Dicembre 2017 alle 22:12
        • Rispondi

        Cosa mi consigli per la comunicazione tra PC e Arduino? a parte la USB ovviamente

        Grazie

        1. Ciao Dino,
          è molto variabile, direi che sarebbe utile conoscere il progetto ed il Pc ce vuoi usare, potresti usare sia WiFi sia Bluetooth

  1. […] la descrizione dello sketch nell’articolo encoder attiny slave in cui lo sketch è stato spiegato linea per linea, in questa occasione è importante sapere […]

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.