keypad lettura singolo pin analogico

sto realizzando una cosa come questa:

|500x281

anche se al posto dei resistori da 4.7Komh sto usando da soli 200omh (svariate prove per trovare un valore che mi desse una buona differenza)

questo il codice

int keyboard = 0;
int key;


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

void loop() {
  delay(50);

  checkSensor();
  Serial.print("mV:  "); Serial.print(key);
  Serial.print(" | key:  "); Serial.println(checkSensor());
  Serial.println("");

}

int checkSensor() {
  key = analogRead(keyboard) / 10 * 10;

  if (key == 900) return 1;
  if (key == 480) return 2;
  if (key == 330) return 3;
  if (key == 720) return 4;
  if (key == 430) return 5;
  if (key == 290) return 6;
  if (key == 590) return 7;
  if (key == 380) return 8;
  if (key == 270) return 9;
  if (key == 500) return 10;
  if (key == 340) return 0;
  if (key == 250) return 11;
}

mi sono immamorato di quel /10*10 che eliminando la virgola porta le oscillazioni a +-10 (non idea mia)

per il resto purtroppo ogni volta che carico lo sketch mi sembra che i valori di riferimento cambino... sto alimentando la keyboard con i 5V di arduino, il problema deduco essere una non perfetta costanza dell alimentazione? dovrei aggiungere un condensatore fra analog e ground?

che ne dite di questo tipo di soluzione :smiley:

#define tasti 11 // 12-1

int keyboard = A0;
int mV;
int riferimenti[tasti] = {};


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

void setting() {
  Serial.println("primi i tasti da 1 a # in ordine");
  delay(500);

  for (int i = 0; i <= tasti; i++) {

    Serial.print("premi:");
    if (i < 9)    Serial.println(i + 1);
    if (i == 9)   Serial.println("*");
    if (i == 10)  Serial.println("0");
    if (i == 11)  Serial.println("#");
    delay(1500);

    for (int a = 0; a < 10; a++) { //10 letture intervallate da 200ms, ancora devo aggiungere la media
      riferimenti[i] = analogRead(keyboard) / 10 * 10;
      delay(200);
    }

    Serial.println(riferimenti[i]);
    if (i == tasti)   Serial.println("fine calibrazione");
    else              Serial.println("prossimo");
    delay(500);
    Serial.println("");
  }

  for (int c = 0; c <= tasti; c++) Serial.println(riferimenti[c]);
  delay(3000);

}


void loop() {
  delay(50);
  mV = analogRead(keyboard) / 10 * 10;

  checkSensor();
  Serial.print("mV:  "); Serial.print(mV);
  Serial.print(" | key:  "); Serial.println(checkSensor());
  Serial.println("");

}

int checkSensor() {
  for (int b = 0; b <= tasti; b++) {
    if (mV == riferimenti[b]) return b + 1;
    //if (return==tasti+1) return 0;
  }
}

in poche parole ho aggirato il problema di avere dei riferimenti diversi in base all alimentazione creando i riferimenti all interno del programma stesso!

se riesco ad aggiungerci la media fra le 10 registrazioni e poi qualche altra piccola cosa tipo invece di scrivere 10 scrivi * e così via mi sembra carino

edit: sarebbe bellissimo aggiungere piuttosto che la media la moda ma forse adesso sto esagerando con le aspettative nelle mie capacità ahahah

edit 2: codice aggiornato con varie piccole migliorie adesso l unica cosa che manca è la moda, ma già così è perfetto!

ho provato alcune strategie tipo:

 for (int i = 0; i <= tasti; i++) {
   for (int a = 0; a <= reg; a++) {
      media[a] = analogRead(keyboard) / 10 * 10;
      totale = media[a] + totale;
      delay(200);
    }

    riferimenti[i] = totale / 100 * 10;
    totale = 0;
}

però ottengo letture più “scarse”

se posso essere critico… invece di tutto quel casino non è più semplice individuare un intervallo di valori per ogni tasto? così se la lettura cambia di qualche unità non hai problemi…

int checkSensor() {
  key = analogRead(keyboard) / 10 * 10;

  if (key >= 800) return 1;
  if (key >= 650) return 4;
  if (key >= 550) return 7;
  if (key >= 500) return 10;
  if (key >= 450) return 2;
  if (key >= 400) return 5;
  if (key >= 350) return 8;
  if (key >= 340) return 0;
  if (key >= 330) return 3;
  if (key >= 290) return 6;
  if (key >= 270) return 9;
  if (key >= 250) return 11;
}

nell’esempio ho aggiustato i valori partendo dai tuoi… fai delle verifiche.
magari cambiando il valore delle resistenze riesci ad ottonere anche scarti maggiori tra i vari tasti.

devi essere critico, sono qui per imparare!

già ho modificato le resistenze per avere valori il più distanti possibili e ho aggiunto un condensatore

si mettendo degli intervalli si avranno sicuramente letture più pulite, era l approccio che avevo fatto all inizio dopo il valore fisso, però mi era sembrato un buon esercio la creazione di quella funzione setting(); e poi anche perchè questa mi permette di avere una soluzione più immediata nel caso di tastiere o resistenze o collegamenti differenti. per esempio adesso sto usando lo stesso sketch sia con una tastiera 4x3 che con una matrice di pulsanti 4x4

È stato un buon esercizio, ma nella soluzione finale dovresti seguire il consiglio di @fratt.

Intanto perché il tuo approccio è orribile dal punto di vista della User Experience (hai mai visto un telefono che ogni volta che lo accendi ti chiede di premere tutti i tasti???), ma soprattutto perché difficilmente le letture analogiche restituiscono sempre lo stesso valore, oscillano sempre di qualche unità.

Dato che la lettura del ADC come minimo fluttua sempre di +/- 1 count nella migliore delle ipotesi, è così e non ci puoi fare nulla, è necessario usare una lettura con isteresi, non puoi usare un confronto su un valore assoluto.

Devi fare una cosa di questo tipo:

if (lettura > val1 && lettura < val2) valore = quellochetipare:

val2 deve essere maggiore di val1 perché rappresenta l’intervallo all’interno del quale hai valore che cerchi, p.e. ipotizzando che ti aspetti un valore compreso tra 150 e 160 che corrisponde a * il codice è:

if (lettura > 150 && lettura < 160) valore = ‘*’;

In questo modo elimini tutti i problemi dovuti alle inevitabili fluttuazioni del ADC e le tolleranze su i valori delle resistenze.

astrobeed:
Dato che la lettura del ADC come minimo fluttua sempre di +/- 1 count nella migliore delle ipotesi, è così e non ci puoi fare nulla, è necessario usare una lettura con isteresi, non puoi usare un confronto su un valore assoluto.

Devi fare una cosa di questo tipo:

if (lettura > val1 && lettura < val2) valore = quellochetipare:

val2 deve essere maggiore di val1 perché rappresenta l’intervallo all’interno del quale hai valore che cerchi, p.e. ipotizzando che ti aspetti un valore compreso tra 150 e 160 che corrisponde a * il codice è:

if (lettura > 150 && lettura < 160) valore = ‘*’;

In questo modo elimini tutti i problemi dovuti alle inevitabili fluttuazioni del ADC e le tolleranze su i valori delle resistenze.

Yep i know, giusto per essere precisi fluttua di +- 10 anche per questo range così grande ho provato a mettere valori assoluti

SukkoPera:
È stato un buon esercizio, ma nella soluzione finale dovresti seguire il consiglio di @fratt.

Intanto perché il tuo approccio è orribile dal punto di vista della User Experience (hai mai visto un telefono che ogni volta che lo accendi ti chiede di premere tutti i tasti???), ma soprattutto perché difficilmente le letture analogiche restituiscono sempre lo stesso valore, oscillano sempre di qualche unità.

Pensa che ho “scoperto” gli array quando me li hai detti tu prima non li usavo

Oh beh, se vuoi ti posso parlare anche di altre strutture dati più o meno astruse, tipo Heap, Hash Table, Red-Black Tree, k-d Tree… :smiley: