Problema di risposta da selettore

Buongiorno a tutti, ho recentemente ripreso un vecchio progetto Arduino, aggiungendo un selettore rotativo evitando una serie d’interruttori.

Tutto bene, ma quando ho cercato d’inviare con un HC-12 il codice ottenuto mi sono accorto che non sempre l’invio era corrispondente alla posizione selezionata. Ho provato a cambiare il Mega (cinese!) ma il risultato non cambiava, rifatto i collegamenti, cambiato i PIN di riferimento, cambiato l’interruttore … stesso risultato!

Qualcuno può mettermi sulla giusta strada per correggere l’errore (che io non ho trovato?).

Allego file con lo schema dei collegamenti dell’interruttore (P.S.: i resistori sono da 470 ohm).

/*
   Prova selettore
   18.06.19
*/

#include <SoftwareSerial.h>
SoftwareSerial HC12(52, 50); // HC-12 TX Pin, HC-12 RX Pin

const int p_verde = A15;
const int p_giallo = A14;
const int p_rosso = A13;

// Sequenziale

#define seq1 23 // pin di input dove è collegato il pulsante
#define seq2 25 // pin di input dove è collegato il pulsante
#define seq3 27 // pin di input dove è collegato il pulsante
#define seq4 29 // pin di input dove è collegato il pulsante
#define seq5 31 // pin di input dove è collegato il pulsante
#define seq6 33 // pin di input dove è collegato il pulsante
#define seq7 35 // pin di input dove è collegato il pulsante
#define seq8 37 // pin di input dove è collegato il pulsante
#define seq9 39 // pin di input dove è collegato il pulsante
#define seq10 41 // pin di input dove è collegato il pulsante

char nr6 = 'i';
int nr7 = 0;  // pulsanti
char stringa;
int v_alt = 0;

void setup() {
  pinMode( p_verde, INPUT);
  pinMode( p_giallo, INPUT);
  pinMode( p_rosso, INPUT);

  pinMode(seq1, INPUT);     // imposta il pin digitale come input
  pinMode(seq2, INPUT);     // imposta il pin digitale come input
  pinMode(seq3, INPUT);     // imposta il pin digitale come input
  pinMode(seq4, INPUT);     // imposta il pin digitale come input
  pinMode(seq5, INPUT);     // imposta il pin digitale come input
  pinMode(seq6, INPUT);     // imposta il pin digitale come input
  pinMode(seq7, INPUT);     // imposta il pin digitale come input
  pinMode(seq8, INPUT);     // imposta il pin digitale come input
  pinMode(seq9, INPUT);     // imposta il pin digitale come input
  pinMode(seq10, INPUT);     // imposta il pin digitale come input

  Serial.begin(9600);
  HC12.begin(9600);

}

void loop() {
  // controlla lo stato dei pulsanti
  if (digitalRead(p_verde) == LOW) {
    nr7 = 1;  // Avvio
  } else if (digitalRead(p_giallo) == LOW)  {
    nr7 = 2;  // azzera
  }  else if (digitalRead(p_rosso) == LOW) {
    nr7 = 3;  // stop
  } else {
    nr7 = 0;
  }

  // controlla la posizione dell'interruttore sequenziale
  if (digitalRead(seq1) == HIGH) {
    nr6 = 'a';
  } else if (digitalRead(seq2) == HIGH)  {
    nr6 = 'b';
  }  else if (digitalRead(seq3) == HIGH) {
    nr6 = 'c';
  } else if (digitalRead(seq4) == HIGH)  {
    nr6 = 'd';
  }  else if (digitalRead(seq5) == HIGH) {
    nr6 = 'e';
  } else if (digitalRead(seq6) == HIGH) {
    nr6 = 'f';
  } else if (digitalRead(seq7) == HIGH)  {
    nr6 = 7;
  }  else if (digitalRead(seq8) == HIGH) {
    nr6 = 8;
  }  else if (digitalRead(seq9) == HIGH) {
    nr6 = 'g';
  }  else if (digitalRead(seq10) == HIGH) {
    nr6 = 'h';
  } else {
    nr6 = 'i';
  }


  if (nr6 != 'i') {
    Serial.println(nr6);
    trasmetti();
  }
  delay(1000);
}

void trasmetti() {

  if ((nr7 > 0) && (stringa != 'i')) {

    if ((nr7 == 1) && (v_alt == 0)) {
      /*
          invia l'istruzione di avvio
      */

      HC12.print(stringa);
      Serial.println(stringa);

    } else if ((nr7 == 2) && (v_alt == 0)) {
      /*
         azzera il tiner
      */

      stringa = 'm';

      HC12.print(stringa);

    } else if ((nr7 == 3) && (v_alt == 0)) {
      /*
         invia l'istruzione di STOP
      */
      v_alt = 1;
      stringa = 'n';

      HC12.print(stringa);

    } else if (v_alt == 1)   {

      if ((nr7 == 1) || (nr7 == 2)) {
        /*
          invia l'istruzione di Ripresa gara
        */
        stringa = 'o';
        v_alt = 0;
        HC12.print(stringa);
      }
    }
    delay(250);
  }

  nr7 = 0;
}

Grazie anticipatamente per l’eventuale aiuto.

Saluti

Enrico

SchemaSelettore_schem.pdf (1.3 MB)

Scusa ma a parte le resistenze in serie (inutili perché solo uno dei pin sarà collegato quindi al massimo ti basta metterne UNA sola tra il centrale del selettore e +5V), quei pin non sono né pullup né pulldown, quindi se li lasci fluttuanti hai letture potenzialmente sballate!

Possibili soluzioni:

1) Imposti i pin come INPUT_PULLUP ed il centrale del commutatore lo metti a GND invece che a 5V, quindi ogni pin va confrontato con LOW per sapere se è selezionato

2) Metti una resistenza di pulldown per ognuno dei pin (ossia sposti le attuali per collegarle tra il pin del selettore e GND, non tra pin e selettore!)

Ma direi che invece di usare 10 pin digitali potrebbe bastare usarne uno solo ma analogico se li colleghi con un opportuno partitore resistivo tra ogni pin (per cui la lettura analogica avrà 10 livelli di tensione, ammettendo un minimo di variabilità sul valore centrale).

Grazie per le informazioni.

Avevo già provato ad utilizzare un PIN analogico "leggendo" le diverse tensioni, ma saltuariamente ottenevo risultati "sballati" (probabilmente causa la mia scarsa manualità ed esperienza). Visto che disponevo di un Mega ho preferito usare più PIN digitali.

Proverò quindi una delle altre due soluzioni.

GRAZIE.

Saluti

Enrico

enrico24: Avevo già provato ad utilizzare un PIN analogico "leggendo" le diverse tensioni, ma saltuariamente ottenevo risultati "sballati" (probabilmente causa la mia scarsa manualità ed esperienza). Visto che disponevo di un Mega ho preferito usare più PIN digitali.

Sicuramente avendoli a disposizione male non fa, quindi ok così basta che li imposti o con pullup o pulldown.. :D

Però per il futuro, posso dirti che io ho usato commutatori in quel modo (ad esempio per i commutatori di un pannello per Flight Simulator che feci per mio figlio) senza problemi, l'importante è che tu faccia un partitore fatto benino, ossia mettendo una resistenza tra due contatti adiacenti esempio:

Quindi nel codice devi verificare i valori che leggi per ognuna delle posizioni, ed ammettere un certo scarto (ossia non cercare il valore esatto).

Nel tuo caso se hai 10 posizioni avrai valori da 0 a +5V quindi in media intervalli da circa 1024/10 = 102 quindi andando sulla metà di ogni intervallo potrai considerare valori: Pos 0 = 0 (GND) Pos 1 = 102 Pos 2 = 204 ... eccetera Pos 9 = 1023 (+5V) quindi puoi fare una funzioncina che dato il valore letto dall'analogico ti restituisce l'indice della posizione del cursore. Per farlo ti basta considerare un range di +-51 centrato sul valore base, ossia del tipo:

int Analog2Rotary(int cur) {
    return int( (cur+51) /102);
}

BELLO!

Mi sembra un'ottima soluzione, proverò ad applicarla comandando i singoli LED tramite PIN.

Grazie

Enrico

PS: quali resistori consiglieresti di usare?

enrico24: Mi sembra un'ottima soluzione, proverò ad applicarla comandando i singoli LED tramite PIN.

E' sicuramente una OTTIMA soluzione per diversi motivi: - utilizzi solo un ingresso - utilizzi solo un filo per tutte le posizioni (più il gnd e il +5, chiaro) - hai meno possibilità di commettere errori, falsi contatti, eccetera e meno fili in giro. - il risultato con un solo ingresso è garantito come se avessi i tuoi 12 ingressi.

Certo, però devo gestire separatamento i 10 LED che mi indicano quale punto del selettore è collegato!

Saluti

Enrico

Ops, solo adesso mi sono accorto che non avevo mai menzionato il fatto che ad ogni posizione del selettore corrisponde una luce LED!

Scusate-

Enrico

Beh, no, si vedeva dallo schema che hai postato che usi i led per ogni posizione. Nel caso usassi un potenziometro puro sarebbero indispensabili per vedere a che posizione stai andando. Nel caso del commutatore che ti ha suggerito docdoc non servono. Se però ti interessa metterli ugualmente, puoi pensare ad un commutatore doppio: su un piano fai lo schema di docdoc e sul secondo arrivi con la +5v e la commuti sui relativi led.

La scelta del partitore su pin analogico è concettualmente sbagliata Lo OP avrebbe cosi 1 un ingresso ad alta impedenza (disturbi) e 10 uscite 11 pin usati

La scelta dello OP è invece corretta concettualmente, solo 10 ingresso a bassa impedenza Il problema è realizzativo Ha messo gli ingressi tra led è resistenza,in questa maniera l'ingresso non sente 5v, ma la tensione del led, insufficiente per gli ingressi di Arduino

Secondo ciò che ho detto sopra, i pin utilizzati sarebbero... solo 1 e per i led non ha senso prelevarli dalle uscite ma solo utilizzare il commutatore per saperne la posizione. Però, se vogliamo dire che non ci fidiamo dell'ingresso e allora vogliamo controllare anche l'uscita, allora va bene...

E scegliere quindi un commutatore a due vie 10 posizioni? Mi sa che costa di più...

Standardoil: La scelta del partitore su pin analogico è concettualmente sbagliata Lo OP avrebbe cosi 1 un ingresso ad alta impedenza (disturbi) e 10 uscite 11 pin usati

A meno di avere dei cavi lunghi (cosa che mi pare si possa escludere) che potrebbero indurre fluttuazioni nell'ingresso ad alta impedenza, non ci sono problemi ad usare un commutatore in quel modo, ossia come partitore resistivo (con resistenze ad esempio da 1k), cosa ci sia di "concettualmente sbagliato" non è molto chiaro, e tra l'altro è una configurazione molto diffusa proprio per questi casi (commutatori o pulsanti da premere solo uno per volta), ed io stesso l'ho usata con pieno successo su più commutatori per Flight Simulator.

E comunque è solo per ottimizzare i pin, nel suo caso dato che usa una Mega non ha problemi e può anche lasciare tutto com'è, il mio era solo un suggerimento "per il futuro" (e meno male che l'avevo pure scritto...) non necessariamente per questa applicazione specifica.

enrico24: Ops, solo adesso mi sono accorto che non avevo mai menzionato il fatto che ad ogni posizione del selettore corrisponde una luce LED!

Come già correttamente evidenziato da steve-cr, se vuoi puoi utilizzare un commutatore doppio ossia con doppi contatti, sul secondo cablerai (ricorda la resistenza per limitare la corrente!) i LED corrispondenti ad ognuna delle posizioni mandando ad esempio +5V sul comune (tramite resistenza limitatrice) ed i LED tutti a GND.

In alternativa, potresti pensare ad una coppia di 74HC595 (con i quali gestire fino a 16 LED), ma insomma, se hai una Mega e non hai problemi di pin sarebbe una inutile complicazione.

Oddiobbono... Per NON voler correggere l'errore di cablaggio di aver messo l'ingresso dopo la resistenza invece che prima, ci mettiamo a giocare con gli shift register? Ma pensare easy non si usa più? Certo che poi servono 12 pagine per 2 pomodori (piante di)...

Grazie a tutti, al momento ho “girato” LED e alimentazione e tutto sembra funzionare. Certo la tensione che va al PIN è un po’ bassina (1.6/1.7 V) ma sembrerebbe funzionare.

Ecco il nuovo programma e lo schema

…...

// Sequenziale
#define SIZESEQ 10//Il numero di posizioni presenti
const byte sequenziale [SIZESEQ] = {22, 24, 26, 28, 30, 32, 34, 36, 38, 40}; //I pin a cui sono collegati
const int significato [SIZESEQ + 1] = {  1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; //L'insieme dei valori da trasmettere

i-----

void setup() {

  ….

  for (byte i = 0; i < SIZESEQ; i++)
  {
    pinMode (sequenziale[i], INPUT);
  }

  Serial.begin(9600);

}

void loop() {
…..

  // controlla la posizione dell'interruttore sequenziale
  byte i;
  for (i = 0; i < SIZESEQ; i++)//I va da 0 a 10
  {
    if (digitalRead (sequenziale[i]) == LOW) //==HIGH è sottinteso
      break;//Ma si ferma se sento pulsante
  }
  nr6 = significato[i];
  if (nr6 > 9) {
    nr6 = 0;
  }

…..
  }

enrico24: Grazie a tutti, al momento ho "girato" LED e alimentazione e tutto sembra funzionare. Certo la tensione che va al PIN è un po' bassina (1.6/1.7 V) ma sembrerebbe funzionare.

Eh certo! Lo schema, se corrisponde a quanto hai cablato, non va ancora bene.

Hai detto infatti di aver "girato LED e alimentazione" ossia hai messo ora il comune del commutatore a GND invece di +5V e girato i LED, ma questo non serve allo scopo che era quello fare in modo che i pin siano o pullup o pulldown, perché ci sono ancora le resistenze in posizione sbagliata, ossia tra pin e commutatore invece che tra pin e GND (per pulldown) o pin e +5V (per pullup).

Con quella configurazione tu avrai sempre fluttuanti i pin (tranne quello collegato dal selettore) perché da un lato hanno la resistenza che non finisce da nessuna parte (il selettore sta altrove) e dall'altro un LED che conduce in verso opposto. Inoltre il pin selezionato lo mandi ora a GND, quindi avrai una lettura a zero, come se fosse pullup!

Se vuoi tenere la configurazione in "pulldown", il centrale del commutatore devi rimetterlo a +5V, ed ogni pin va collegato al proprio piedino del commutatore e ad una resistenza da 10k che va verso GND (pulldown). Per aggiungere anche un LED, collegherai sempre al pin anche una resistenza da 220 ohm che tramite il LED va a massa.

Per farmi capire, ho fatto al volo uno schemino, rappresenta la connessione del SINGOLO pin e relativo contatto del commutatore:

|500x424

Prova a modificare il tuo schema in questo modo e fammi sapere. Ovviamente la "if" per uno schema con pin in pulldown (che intendevi nel commento con "HIGH è sottinteso"??) sarà:

if (digitalRead (sequenziale*) == HIGH)*

x docdoc, grazie. se ho ben capito i collegamenti dovrebbero venir fatti come da schema allegato (scusa le incomprensioni di un vecchio chimico che in tarda età si è messo a “pasticciare” con l’elettronica!!).

Saluti

PS:il commento “HIGH” mi ero dimenticato di cancellarlo; in effetti mi pare che ‘if (digitalRead (sequenziale) == HIGH)’ si possa anche scrivere ‘if (digitalRead (sequenziale) )’ con lo stesso risultato.

SchemaSelettore_1_schem.pdf (1.15 MB)

enrico24: x docdoc, grazie. se ho ben capito i collegamenti dovrebbero venir fatti come da schema allegato

No, nel mio schema se vedi ci sono DUE resistenze per pin. Qui tu hai lasciato solo quella che limita la corrente al LED, ma non hai messo quella che deve implementare il "pulldown" ossia verso GND, che è la cosa più importante per il funzionamento!

(scusa le incomprensioni di un vecchio chimico che in tarda età si è messo a "pasticciare" con l'elettronica!!).

Non scusarti, non c'è problema!

in effetti mi pare che 'if (digitalRead (sequenziale) == HIGH)' si possa anche scrivere 'if (digitalRead (sequenziale) )' con lo stesso risultato.

Si perché la if() se ha un qualsiasi valore diverso da zero, è TRUE, di fatto scrivere:

if (digitalRead (sequenziale) )

equivale a:

if (digitalRead (sequenziale) != 0)

Ma il caldo fa male? Oggi ho dormito per la prima volta a Varese in settimana, primo passo di un trasloco a puntate... Molto più fresco... Quindi ripeto la domanda: il caldo vi male? Il led e la sua resistenza già fanno da pull-down. Avete mai visto led scollegati che lampeggiano da soli causa disturbi? E K&R dicono che if(condizione) equivale a condizione==vero non che equivale a !0 qui sbagliavo Dicono esattamente così, ricordavo male, chiedo venia

Standardoil: Quindi ripeto la domanda: il caldo vi male? Il led e la sua resistenza già fanno da pull-down. Avete mai visto led scollegati che lampeggiano da soli causa disturbi?

Non ho capito: tu fai pulldown con una resistenza da 220 Ohm ed un LED che è normalmente in interdizione?

Contento te, a Varese si farà forse così, ma io metto sempre una da 10k per avere un pulldown sicuro e stabile, poi qui in questo caso il LED è "accessorio" ossia serve solo per fare in modo che si accenda quando si porta a +5V il pin.

A parte l'insinuazione sul caldo che potevi risparmiarti, e sulla quale sorvolerò invitandoti a fare altrettanto, grazie.

E K&R dicono che if(condizione) equivale a condizione==vero non che equivale a !0

No, stiamo parlando di una espressione che restituisce un valore numerico, quindi la if() lo considera "true" se il valore è diverso da zero, e "false" se uguale a zero. Visto che non ci credi, eccoti un estratto del K&R, 2nd edition, pagina 55:

3.2 If-Else The if -else statement is used to express decisions. Formally, the syntax is if (expression) statement 1 else statement 2 where the else part is optional. The expression is evaluated; if it is true (that is, if expression has a non-zero value), statement 1 is executed. If it is false {expression is zero} and if there is an else part, statement 2 is executed instead. Since an if simply tests the numeric value of an expression, certain coding shortcuts are possible. The most obviousis writing if (expression) instead of if (expression != 0) Sometimes this is natural and clear; at other times it can be cryptic

Per cui se un valore è true se diverso da zero significa 'condizione != 0', come ho detto io.

Possiamo ora proseguire e dare una mano all'OP invece di polemizzare inutilmente? Ti ringrazio.