Stabilizzare il valore di tensione di un potenziometro su ingresso analogico

Buona sera vorrei un consiglio su come stabilizzare al massimo l'uscita di un potenziometro che finisce su un pin analogico , diciamo A0.

In alcune posizioni il valore è un po' ballerino e sgarra di un paio di punti.

per intenderci in un ciclo misura 544 e magari quello successivo 546.

Su altre posizioni del potenziometro invece la lettura è stabile.

Esiste un modo oppure dipende del potenziometro (quello presente nello student kit) e quindi mi attacco al tram e ne compro di più precisi?

Vi chiedo gentilmente di sorvolare su soluzioni prettamente software, diciamo che il mio progetto richiede una certa precisione senza scendere nei particolari :stuck_out_tongue:

Vi ringrazio in anticipo comunity :slight_smile:

Avete per caso un condensatore elettrolitico da 10 uF?, non credo, se state usando un kit per studenti.
Quindi, senza utilizzare software, dovrete recarvi al negozio più vicino, ma non fatevi ingannare da meravigliosi potenziometri che costano decine di euro, acquistate un multigiro economico, come quelli blu che sicuramente hanno alcuni dei moduli del vostro kit, non risolverà completamente il problema ma lo risolverà in parte.
Salute.

1 Like

Si ho il condensatore.

Lo metto in parallelo agli ingressi Vcc e Gnd del condensatore oppure in serie sull'uscita del condensatore?

Il che equivale ad un errore dello 0,2%
Se vuoi ottenere prestazioni migliori con l'ADC integrato, se non basta il condensatore di filtro sull'ingresso, devi valutare l'uso una tensione di riferimento esterna per l'ADC che sia molto più stabile di quella di alimentazione (usata come riferimento di default).

Ci sono degli integrati specifici che nascono proprio per questa funzione.

1 Like

Anche questo potrebbe aiutare, non so quanto per un potenziometro che (ipotizziamo) sia collegato tra Vcc(e quindi Vref) e GND. Una variazione della Vcc non dovrebbe comportare cambio di lettura.
D'altronde l'OP ha esplicitamente affermato di non voler scendere nei particolari, così non sappiamo ad esempio che scheda sta usando (e che risoluzione ha l'ADC), che potenziometro sta usando (1Kohm? 1Mohm? Lineare? Logaritmico?), come questo sia collegato, come viene effettuata la lettura, per quale scopo si usa questa lettura.
Per me le informazioni sono troppo scarse per poter consigliare una soluzione.

Ciao, Ale.

2 Likes

Io, d'altra parte, nemmeno m'illuderei di poter ottenere una stabilità migliore dello 0,2%! Stiamo parlando di +/-1LSB, al livello del rumore di quantizzazione...

Presumo che il potenziometro sia collegato: un terminale al +, l'altro al - e il cursore ad A0. Collegare il condensatore da 1 a 10 uF tra il cursore e GND".
So che non volete sentir parlare di software, ma prendere il valore finale come media di diverse letture non è difficile e risolverebbe il problema in modo considerevole, basta aggiungere la seguente funzione dietro il loop:

int media (int porta, int volte) {
  int letture [volte], lettura;
  for (int n = 0; n < volte; n++) {
    letture [n] = analogRead (porta);
  }
  lettura = 0;
  for (int n = 0; n < volte; n++) {
    lettura = lettura + letture [n];
  }
  lettura = lettura / volte;
  return lettura;
}

E invece di utilizzare la funzione " analogRead (A0) ", utilizzare " media (porta , volte) " dove:

  • porta, è una porta valida da A0 a A7.
  • volte è il numero di letture da calcolare come media.

Provate il seguente esempio e vedete i risultati attraverso la porta seriale.

void setup() {
  Serial.begin(9600);
}

void loop() {
Serial.println (  media (A0, 6)  );
delay (2000);
}

int media (int porta, int volte) {
  int letture [volte], lettura;
  for (int n = 0; n < volte; n++) {
    letture [n] = analogRead (porta);
    Serial.print (letture [n]);
    Serial.print (",");  
  }
  Serial.println ("");
  lettura = 0;
  for (int n = 0; n < volte; n++) {
    lettura = lettura + letture [n];
  }
  lettura = lettura / volte;
  return lettura;
}

Saluti

1 Like

Sto usando una Esp32 con risoluzione ADC 9 bit . Ecco mi scuso ma vi dico anche altre info, forse è indispensabile.
Il potenziometro è quello contenuto nello student kit di arduino. Mappo il valore analogico per avere un corrispondente valore da 0 a 160 e da 0 a 128 (quindi in realtà i potenziometri sono due) che corrispondono ai pixel di uno schermo TFT da 1.8 pollici. Insomma vorrei eliminare la vibrazione del cursore che stampa ad ogni ciclo un pixel sullo schermo dopo aver ripulito lo schermo stesso. I valori mappati oscillano di uno/ due punti ma solo in alcuni casi, ma essendo, appunto, mappati significa che l'errore è più del 2%. Ho deciso di usare una definizione bassa perché ho pensato che desse meno problemi.

Sono un neofita nel campo elettronica perdonatemi se a volte sono poco preciso nel fare le domande. :stuck_out_tongue:

Spero che tu sia opportunamente documentato su come funziona l'ADC dell'ESP32 (quale poi? ne esistono varie versioni...), perchè è un po' diverso rispetto ad altre MCU.
E ancora non vediamo il tuo codice...

Ciao, Ale.

1 Like
#include "rectangle.h"


#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library
TFT_eSprite img = TFT_eSprite(&tft); // per impostare uno sprite 

// g34 potenziometro per il controllo orizontale
int up = 35; //in base all'impostazione aumenta i valori
int sel = 32; // seleziona il tipo di impostazione
int color = 33; //Cambia il colore
int canc = 25; // cancella ultima forma 
// g13 potenziometro di 

int lastX = 0 ;
int lastY = 0 ; 
int mOrizontal = 0;
int mVertical = 0;
int mSizeX=0;
int mSizeY=0;
byte stato = 0;
int timer = 0;
int potOrizontale=0; 
int potVerticale=0;
int potSizeX=0; 
int potSizeY=0;
Forma aRect[10];
int nForme = 0; 
int colors[6];
int nColors = 0;



int option = 0; //seleziona il tipo di opzione
Rectangle rect;

void setup() {
 colors[0] = TFT_BLACK;
 colors[1] = TFT_RED;
 colors[2] = TFT_YELLOW;
 colors[3] = TFT_BLUE; 
 colors[4] = TFT_GREEN;
 colors[5] = TFT_PINK;
 
 
 Serial.begin(115200);
 Serial.println("Initialized"); 
 analogSetWidth(9);
 pinMode(up, INPUT); 
 pinMode(sel, INPUT);
 pinMode(color, INPUT);
 pinMode(canc, INPUT);
 
 tft.init();   // initialize a ST7735S chip
 uint16_t time = millis();
 tft.fillScreen(TFT_BLACK);
 time = millis() - time; 
 
}

void loop() {
  int t0 = millis(); 
  //Seleziona per disegnare forma
  int btnSel = digitalRead(sel);
  delay(10); 
  if (btnSel && timer>300) {
    timer=0;
    stato++;
    if(stato>1) {
      stato=0;
    }
    if (stato==1 ) {
      aRect[nForme] = Rectangle(mOrizontal,mVertical, 20, 20,colors[nColors]);
      nForme++;
      draw(mOrizontal,mVertical);
    }
  } 
  //pulsente del colore
  int btnColor = digitalRead(color);
  if (btnColor && timer>300){
    timer=0;
    nColors++;
    if (nColors>5) {
      nColors=0; 
    }
    aRect[nForme-1].color=colors[nColors];
    draw(mOrizontal,mVertical);
  }
  //pulsente cancella
  int cancella = digitalRead(canc);
  if (cancella && timer>300){
    timer=0;
    nForme--;
    if (nForme<0){
      nForme=0;
      aRect[nForme] = Rectangle(mOrizontal,mVertical, 20, 20,TFT_NAVY);
    }
    
    draw(mOrizontal,mVertical);
  }
  
  
  Serial.println(stato);
  //Serial.println(potVerticale);
  if(stato==0) {
     potOrizontale = analogRead(34); 
     potVerticale = analogRead(13);
     mOrizontal = map(potOrizontale, 0,511, 0 ,127);  
     mVertical = map(potVerticale, 0,511, 0 ,159); 
     
     if (!(mOrizontal<lastX+1 && mOrizontal>lastX-1 ) || !(mVertical<lastY+1 && mVertical>lastY-1 )) {
        tft.fillScreen(TFT_NAVY); 
        draw(mOrizontal,mVertical);    
     }
     delay(10); 
     lastX = mOrizontal;
     lastY = mVertical;
     
  }else {
    if (stato==1) {
      potSizeX = analogRead(34); 
      potSizeY = analogRead(13); 
      mSizeX = map(potSizeX,0,511,0,127);
      mSizeY = map(potSizeY,0,511,0,159);
      aRect[nForme-1].rightTopX=mSizeX; 
      aRect[nForme-1].rightTopY=mSizeY;
      if (!(mSizeX<lastX+1 && mSizeX>lastX-1 ) || !(mSizeY<lastY+1 && mSizeY>lastY-1 )) {
        tft.fillScreen(TFT_NAVY); 
        draw(mOrizontal,mVertical);    
      }
     delay(10); 
     lastX = mSizeX;
     lastY = mSizeY;
    }
  }
  timer = timer + millis() - t0;
  
}
 

void draw(int x_, int y_) {
   tft.fillScreen(TFT_NAVY);
   for (int i=0; i<nForme; i++) {
    tft.fillRect(aRect[i].leftButtomX,aRect[i].leftButtomY,aRect[i].rightTopX,aRect[i].rightTopY,aRect[i].color);
   }
   
   tft.fillCircle(x_, y_, 2, TFT_RED); 
  
}

Non lo volevo postare perchè me ne vergogno.....è disordinato e inefficiente. Il mio intento è quello di fare un programmino per fare disegni con le figure geometriche fondamentali.
Il problema, che ho già affrontato in un' altro post, è che la libreria che sto usando mi da problemi ad utilizzare gli oggetti sprite e quindi per poter far scorrere il cursore sugli oggetti senza che venga disegnata una linea durante lo spostamento devo ridisegnare tutto ad ogni loop.
Peccato che la velocità non basta e quindi si vede un lampeggiamento. Per tenere ferma l'immagine, almeno quando il cursore è fermo ho scritto questo

if (!(mSizeX<lastX+1 && mSizeX>lastX-1 ) || !(mSizeY<lastY+1 && mSizeY>lastY-1 )) {
        tft.fillScreen(TFT_NAVY); 
        draw(mOrizontal,mVertical);    
      }

In questo modo ridisegno l'immagine solo quando muovo il cursore per spostarmi in un'altra area dello schermo. Non è bellissimo . Ma almeno quando si sta fermi l'immagine è stabile.
Mentre quando muovo il cursore l'immagine sfarfalla.

Questo è il precedente post.

https://forum.arduino.cc/t/display-tft-con-ts7785s-e-spi-frequenza-di-aggiornamento-bassa/1008385/18

La libreria che sto usando (TFT_eSPrite) ha gli oggetti Sprite ma non funzionano come mi aspetterei.
Ho seguito i consigli di Maurotec ma gli sprite vengono disegnati ma lo scroll non funziona
e se li sposto dando una nuova posizione con pushSprite() non viene cancellata l'immagine precedente anche se uso successivamente il comando deleteSprite().

Ad un certo punto ho anche pensato di salvare i valori dei colori dell'area da sovrascrivere prima di disegnare il cursore per poi rispristinarla dopo il suo passaggio in modo che bisognava ridisegnare solo piccole porizioni di pixel a vantaggio della velocità, ma sfortunatamente l'unico comando che legge il valore del colore del pixel readPixel() restituisce un colore diverso da quello che è realmente disegnato, ed ho letto un post inglese che

La libreria TFT e GFX non mi sembra abbiano soluzioni al mio problema.
Probabilmente è Lo schermo un po limitato un AZDelivery TFT 1.8 con drive TS7735c.

Ho trovato questo compromesso che andrebbe anche bene dato che lo faccio solo per divertirmii. Il problema è che lo sfarfallio di cui parlavo ad inizio post fa in modo che a volte anche da fermo le immagini tremano perchè ridisegno tutto ogni volta che i valori cambiano.

Speravo semplicemente che ci fosse una soluzione hardware per non dover riscrivere tutto da capo.

Insomma Ale, un bel casino. Anche perchè come ti dicevo sono un dilettante e i arrabatto.

Grazie tantissimo per la pazienza.

Fabio

Mi spiace ma non so darti consigli specifici, ho usato quella libreria ma senza fare animazioni. Credo che tu stia sbagliando qualcosa nella gestione degli sprite, es. deleteSprite() non serve per cancellare lo sprite dal display...
Forse non ti servono nemmeno gli sprite, prova ad esempio a partire dall'esempio incluso nella libreria del gioco Pong, che mi sembra faccia qualcosa di simile a quello che vuoi fare (e che, confesso, non ho ancora capito, ma sono notoriamente duro di comprendonio...).
Per quanto riguarda il potenziometro prova a non settare la risoluzione a 9 bit , lasciala con il default a 12 bit, e fai uno shift di 3 bit a dx dopo la lettura, es:

potSizeX = analogRead(34) >> 3;

vedi se migliora qualcosa. Comunque se hai letto il link del mio post precedente avrai visto che il potenziometro copre un range maggiore di quello ADC, quindi ti troverai a sfruttare 3/4 della sua corsa. Forse avresti vita più facile usando 2 encoder, ogni scatto incrementi o decrementi di uno senza stare a fare calcoli o conversioni.

Ciao, Ale.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.