Site icon Renzo Mischianti

PCF8574 un expander i2c I/O digitale: Arduino, esp8266 e esp32, encoder rotativo – Parte 2

Spread the love

PCF8574 i2c expander digitale di IO uso dell’encoder rotativo

Un  trasduttore di posizione angolare, chiamato anche   encoder rotativo, è un dispositivo elettromeccanico che converte la posizione angolare o il movimento di un albero o di un asse in segnali di uscita analogici o digitali.

Introduzione agli encoder

Gli encoder rotativi sono utilizzati in una vasta gamma di applicazioni che richiedono il monitoraggio o il controllo, o entrambi, di sistemi meccanici, inclusi controlli industriali, robotica, obiettivi fotografici, dispositivi di input del computer come mouse e trackball optomeccanici e piattaforme radar rotanti .

Puoi acquistare l’encoder o il modulo già pronto per la prototipazione.

Rotative encoders

Puoi trovare il rotary encoder su AliExpress

Rotative encoder module
Puoi trovare il modulo rotary encoder module su AliExpress
Rotary encoder with switch pinout

Il modulo è più semplice da gestire, il problema più fastidioso di un encoder rotativo è il disturbo che lo caratterizza. Il modulo ha solo un semplice resistore pull-up per ridurre il rumore, ma se vuoi usare l’encoder in formato nativo è meglio se oltre ad applicare un resistore pull-up applicare anche un semplice filtro.

Encoder module schema

Per pull-up utilizzo una resistenza da 10k collegata al VCC, per il filtro utilizzo una resistenza da 10k dall’encoder e un condensatore da 100nF collegato al GND.

Encoder filter schema

L’encoder funziona con la rotazione della piastra collegata agli interruttori.

Il movimento genera una sequenza predeterminata:

Incremental directional encoder

Quindi dobbiamo decodificare questa sequenza per ottenere rotazione e direzione.

Libreria

Puoi trovare la mia libreria qui o direttamente dal Library manager dell’Arduino IDE.

Download

Fare clic sul pulsante DOWNLOADS nell’angolo in alto a destra, rinominare la cartella non compressa PCF8574.

Verificare che la cartella PCF8574 contenga PCF8574.cpp e PCF8574.h.

Collocare la cartella della libreria PCF8574 come / librerie / cartella.

Potrebbe essere necessario creare la sottocartella librerie se è la tua prima libreria.

Riavvia l’IDE.

IC or Module

Puoi usare un normale IC o un modulo.

pcf8574 IC

Puoi trovare il pcf8574 su AliExpress

pcf8574 module
Puoi trovare il modulo pcf8574 module su AliExpress

Schema di connessione

Come spiegato per collegare un encoder al pcf8574 o anche al microcontrollore, è necessario un filtro per ridurre il rumore o almeno utilizzare un modulo.

Qui uno schema di connessione completo sulla breadboard.

WeMos D1 mini (esp8266) pcf8574 encored breadboard schema

Il risultato in questa foto.

Rotative encoders breadboard

Sketchs di esempio

Utilizzo base

Ecco uno schizzo di base che utilizza una funzionalità di base della libreria.

/*
 * PCF8574 GPIO Port Expand
 * https://mischianti.org
 *
 * PCF8574    ----- WeMos
 * A0         ----- GRD
 * A1         ----- GRD
 * A2         ----- GRD
 * VSS        ----- GRD
 * VDD        ----- 5V/3.3V
 * SDA        ----- D1(PullUp)
 * SCL        ----- D2(PullUp)
 * INT        ----- INT(PullUp)
 *
 * P0     ----------------- ENCODER PIN A
 * P1     ----------------- ENCODER PIN B
 * P2     ----------------- ENCODER BUTTON
 *
 */
#include "Arduino.h"
#include "PCF8574.h"

int encoderPinA = P0;
int encoderPinB = P1;

#define INTERRUPTED_PIN D7

void ICACHE_RAM_ATTR updateEncoder();

// initialize library
PCF8574 pcf8574(0x38, INTERRUPTED_PIN, updateEncoder);

volatile long encoderValue = 0;
uint8_t encoderButtonVal = HIGH;

void setup()
{
	  Serial.begin (9600);
	  delay(500);

	  // encoder pins
	  pcf8574.pinMode(encoderPinA, INPUT_PULLUP);
	  pcf8574.pinMode(encoderPinB, INPUT_PULLUP);
	  // encoder button
	  pcf8574.pinMode(P2, INPUT_PULLUP);

	  // Set low latency with this method or uncomment LOW_LATENCY define in the library
	  // Needed for encoder
//	  pcf8574.setLatency(0);

	  // Start library
	  pcf8574.begin();
}

bool changed = false;

void loop()
{
	if (changed){
		Serial.print("ENCODER --> ");
		Serial.print(encoderValue);
		Serial.print(" - BUTTON --> ");
		Serial.println(encoderButtonVal?"HIGH":"LOW");
		changed = false;
	}
}

uint8_t encoderPinALast = LOW;
uint8_t valPrecEncoderButton = LOW;

void updateEncoder(){
	// Encoder management
	uint8_t n = pcf8574.digitalRead(encoderPinA, true);
	if ((encoderPinALast == LOW) && (n == HIGH)) {
		if (pcf8574.digitalRead(encoderPinB, true) == LOW) {
			encoderValue--;
			changed = true; // Chnged the value
		} else {
			encoderValue++;
			changed = true; // Chnged the value
		}
	}
	encoderPinALast = n;

	// Button management
	encoderButtonVal = pcf8574.digitalRead(P2);
	if (encoderButtonVal!=valPrecEncoderButton){
	  changed = true; // Chnged the value of button
	  valPrecEncoderButton = encoderButtonVal;
	}
}

Ci sono alcune cose importanti da notare:

Nell’esp8266 per creare un callback per l’interrupt è necessario specificare ICACHE_RAM_ATTR.

void ICACHE_RAM_ATTR updateEncoder();

I pin dell’encoder sono INPUT_PULLUP

	  // encoder pins
	  pcf8574.pinMode(encoderPinA, INPUT_PULLUP);
	  pcf8574.pinMode(encoderPinB, INPUT_PULLUP);

Per utilizzare l’encoder con il pcf8574 devi azzerare la latenza e ci sono 3 modalità possibili:

Avremo molte letture false e duplicate (l’interrupt viene generato da ogni variazione), anche se abbiamo impostato il filtro.

Quindi nella procedura verificheremo quando il valore è stato modificato tramite da una variabile changed.

Utilizzo ottimizzato delle funzionalità della libreria

La libreria dispone di una serie di metodi per eseguire tutte le operazioni in maniera trasparente.

Invece di usare pinMode puoi usare direttamente il metodo encoder così:

PCF8574::encoder(uint8_t pinA, uint8_t pinB)

e la dichiarazione nel nostro casò diventerà:

	// encoder pins
	pcf8574.encoder(encoderPinA, encoderPinB);

per gestire la logica dell’encoder sono a disposizione 2 metodi il primo restituisce la variazione del tipo -1, 0 or 1.

int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB)

e la logica precedentemente descrittà diventerà:

	int vale = pcf8574.readEncoderValue(encoderPinA, encoderPinB);
	if (vale!=0){
		changed = true;
	}
	encoderValue = encoderValue + vale;

un altro semplice metodo è:

bool PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue)

che ritorna se l’encoder è variato (-1 o +1) e passando il riferimento della variabile encoderValue il metodo aggiorna il valore internamente.

Così il metodo diventerà:

changed = pcf8574.readEncoderValue(encoderPinA, encoderPinB, &encoderValue);

Qui come diventa lo sketch precedente:

/*
 * PCF8574 GPIO Port Expand
 * https://mischianti.org
 *
 * PCF8574    ----- WeMos
 * A0         ----- GRD
 * A1         ----- GRD
 * A2         ----- GRD
 * VSS        ----- GRD
 * VDD        ----- 5V/3.3V
 * SDA        ----- D1(PullUp)
 * SCL        ----- D2(PullUp)
 * INT        ----- INT(PullUp)
 *
 * P0     ----------------- ENCODER PIN A
 * P1     ----------------- ENCODER PIN B
 * P2     ----------------- ENCODER BUTTON
 *
 */
#include "Arduino.h"
#include "PCF8574.h"

int encoderPinA = P0;
int encoderPinB = P1;

#define INTERRUPTED_PIN D7

void ICACHE_RAM_ATTR updateEncoder();

// initialize library
PCF8574 pcf8574(0x38, INTERRUPTED_PIN, updateEncoder);

volatile long encoderValue = 0;
uint8_t encoderButtonVal = HIGH;

void setup()
{
	Serial.begin (9600);
	delay(500);

	// encoder pins
	pcf8574.encoder(encoderPinA, encoderPinB);
	// encoder button
	pcf8574.pinMode(P2, INPUT_PULLUP);

	// Start library
	pcf8574.begin();

}

bool changed = false;

// The loop function is called in an endless loop
void loop()
{
	if (changed){
		Serial.print("ENCODER --> ");
		Serial.print(encoderValue);
		Serial.print(" - BUTTON --> ");
		Serial.println(encoderButtonVal?"HIGH":"LOW");
		changed = false;
	}
}

bool valPrec = LOW;
void updateEncoder(){
	changed = pcf8574.readEncoderValue(encoderPinA, encoderPinB, &encoderValue);

//	int vale = pcf8574.readEncoderValue(encoderPinA, encoderPinB);
//	if (vale!=0){
//		changed = true;
//	}
//	encoderValue = encoderValue + vale;

	bool val = pcf8574.digitalRead(P2);
	if (val!=valPrec){
	  changed = true;
	  valPrec = val;
	}
}

Video dimostrativo

Grazie

  1. PCF8574 un expander i2c I/O digitale: Arduino, esp8266 e esp32, I/O ed interrupt
  2. PCF8574 un expander i2c I/O digitale: Arduino, esp8266 e esp32, encoder rotativo

Spread the love
Exit mobile version