Come usare Arduino per pilotare un potenziometro digitale

Molte applicazioni richiedono la variazione continua di alcuni parametri, come ad esempio un alimentatore, un amplificatore audio, un termostato o un varilight che solitamente impiegano un potenziometro analogico e l’intervento manuale di una persona per effettuare queste variazioni.
Possiamo digitalizzare questi sistemi impiegando lo stesso principio di regolazione basato su potenziometro ma invece di agire fisicamente sulla manopola di regolazione possiamo utilizzare dei comandi software per incrementare decrementare il valore resistivo del potenziometro.

Il componente che andremmo ad usare è l’integrato MCP4131-103 prodotto dalla Microchip. E’ un integrato a 8 pin che possiamo comandare tramite il protocollo seriale SPI.
Al suo interno troviamo un potenziometro da 10Kohm.

Diagramma interno MCP4131 103

Il potenziometro è composto da una rete resistiva composta da 128 elementi  il cui valore totale è, nel nostro modello, di 10Kohm. Tramite software possiamo spostare la posizione dello Wiper, che corrisponde al contatto strisciante di un potenziometro meccanico. Gli spostamenti dello Wiper vengono definiti steps e vanno dalla posizione 00H (Wiper collegato al pin P0A) alla posizione 80H(Wiper collegato al pin P0B).
Il potenziometro digitale MCP4131 permette un massimo di 129 steps.

MCP4131 Internal potentiometer diagram

Il datasheet è comune a diversi potenziometri digitali quindi per poter capire quale siano i comandi corretti per pilotare il nostro modello dobbiamo esaminare le parti che ci interessano. La prima sezione riguarda le Caratteristiche del dispositivo (Device Features)

Caratteristiche del dispositivo MCP4131-103

Da questa tabella deduciamo che il dispositivo ha un singolo potenziometro, che i valori della posizione dello Wiper sono memorizzati in RAM (piuttosto che sulla EEPROM). L’interfaccia di comunicazione è SPI, i numeri di Steps sono 129 e il range con cui possiamo alimentare l’integrato va da 1.8Vdc a 5.5Vdc.

L’MCP4131 supporta comandi a 8 bit e a 16 bit. Il comando a 8 bit permette di incrementare o decrementare il valore dello Wiper di uno steps per volta mentre il comando a 16 bit permette di scrivere direttamente sulla RAM il valore della posizione dello Wiper.

MCP4131command format

Nella figura il comando a 8 bit è composto da 2 bit di dati (che non vengono utilizzati), 2 bit di comando (incremento – decremento)  e 4 bit che definiscono l’indirizzo di memoria che vogliamo usare (indirizzo dello Wiper 00h).
Nella figura del comando a 16 bit la prima parte è identica a quella a 8 bit con la differenza che nei 2 bit di comando possiamo specificare se scrivere o leggere dall’area di memoria del dispositivo, i restanti 8 bit compongono il Data Byte che ci permette di indicare direttamente il valore dello Wiper.

Gli indirizzi di memoria disponibili sono i seguenti:

MCP4131 Memory Mapnel nostro caso utilizzeremmo l’indirizzo 00h, che corrisponde all’unico Wiper disponibile all’interno del nostro chip.

I bit di commando invece sono i seguenti:

MCP4131 Command Bits

Passando alla pratica, se volessi inviare un comando di incremento al Wiper dell’MCP4131, usando la modalità a 8bit, invierei tramite SPI il valore decimale 4

Arduino Leonardo MCP4131

Per decrementare il valore corrente dello Wiper bisogna spedire via SPI il valore decimale 8:

Arduino Leonardo MCP4131

Se volessi spostare il Wiper al centro della sua corsa, utilizzerei la modalità a 16 bit, inviando per primo il dato contenente l’indirizzo di memoria che vogliamo usare e il comando di scrittura

Leonardo mcp4131-103

Seguito dal valore della posizione dove vogliamo spostare lo Wiper, in questo esempio il valore 64 decimale (128/2) corrisponde a metà corsa.

Leonardo

Ora che conosciamo come utilizzare il chip possiamo passare alla pratica collegando la porta SPI dell’Arduino all’MCP4131. Nel mio caso ho utilizzato un Arduino Leonardo (la porta SPI è disponibile sui pin dell’header ICSP). Lo schema è il seguente:

Arduino Leonardo collegamento MCP4131-103

L’uscita W è collegata all’ingresso analogico A0 della Leonardo, in questo modo posso misurare il valore di tensione disponibile su tale piedino.
Il Pin B dell’MCP4131, corrispondente alla posizione 00H è collegato a massa mentre il pin A corrispondente alla posizione 80H è collegato alla 5Vdc.
Il codice seguente posiziona lo Wiper nella posizione 00H, ottenendo cosi una tensione pressochè nulla sul pin W (poiche internamente il pin W è collegato con il pin B).

#include <SPI.h>

void setup()
{
  //Definisco il pin come uscita
  //il pin 2 viene usato per selezionare il
  //chip all'interno di un collegamento SPI
  pinMode (2, OUTPUT);

  //Inizializzo la libreria SPI
  SPI.begin();

  //Inizializzo la porta seriale
  Serial.begin(9600);

  //metto alta la linea CS per
  //deselezionare il chip MCP4131
  digitalWrite(2, HIGH);

}

void loop()
{
  //Inizializzo la posizione dello Wiper
  byte Posizione = 0;

  //Per selezionare l'MCP4131
  //metto basso la linea CS del
  //potenziometro digitale
  digitalWrite(2, LOW);

  //Invio il primo byte per eseguire una scrittura
  //sul registro Wiper
  SPI.transfer(0);
  //Invio il valore della posizione dello Wiper
  //valori da 00H a 80H (0-128 in decimale)
  SPI.transfer(Posizione);

  //metto alta la linea CS per
  //deselezionare il chip MCP4131
  digitalWrite(2, HIGH);

  //eseguo la lettura sul pin analogico A0
  //in questo pin è collegato il pin Wiper
  //del potenziometro digitale
  int Data = analogRead(0);

  //spedisco il dato letto al serial Monitor
  //Valori da 0 a 1023
  Serial.println(Data);

  //ritardo di mezzo secondo
  delay(500);
}

Aprendo il serial monitor otterremmo dei valori prossimi allo zero poichè la tensione in ingresso del pin A0 sarà nulla. Questo è ciò che avviene all’interno dell’MCP4131:

Wiper to GND

Per posizionare lo Wiper verso il pin A, collegato alla 5Vdc, dobbiamo scrivere sull’indirizzo 00H il valore 80H, come descritto nel codice seguente:

#include <SPI.h>

void setup()
{
  //Definisco il pin come uscita
  //il pin 2 viene usato per selezionare il
  //chip all'interno di un collegamento SPI
  pinMode (2, OUTPUT);

  //Inizializzo la libreria SPI
  SPI.begin();

  //Inizializzo la porta seriale
  Serial.begin(9600);

  //metto alta la linea CS per
  //deselezionare il chip MCP4131
  digitalWrite(2, HIGH);

}

void loop()
{
  //Inizializzo la posizione dello Wiper
  byte Posizione = 128;

  //Per selezionare l'MCP4131
  //metto basso la linea CS del
  //potenziometro digitale
  digitalWrite(2, LOW);

  //Invio il primo byte per eseguire una scrittura
  //sul registro Wiper
  SPI.transfer(0);
  //Invio il valore della posizione dello Wiper
  //valori da 00H a 80H (0-128 in decimale)
  SPI.transfer(Posizione);

  //metto alta la linea CS per
  //deselezionare il chip MCP4131
  digitalWrite(2, HIGH);

  //eseguo la lettura sul pin analogico A0
  //in questo pin è collegato il pin Wiper
  //del potenziometro digitale
  int Data = analogRead(0);

  //spedisco il dato letto al serial Monitor
  //Valori da 0 a 1023
  Serial.println(Data);

  //ritardo di mezzo secondo
  delay(500);
}

In questo caso aprendo il serial monitor leggeremmo dei valori prossimi a 1023 in quanto sul pin analogico A0 sarà presente la tensione di 5Vdc.
Internamente otterremo questo risultato:

wiper to vcc

Di conseguenza per avere tutti gli altri valori intermedi potremmo cambiare il valore della variabile Posizione assegnandole valori tra 0 e 128.