Realizzare un menu su LCD

Ciao a tutti, premetto che, anche se mi interesso di Arduino da tempo e ho aiutato un amico con alcuni progetti basati su di esso, è la prima volta che mi trovo ad usarlo in prima persona. Il mio obiettivo è di convertire una macchina del fumo usata nei concerti di alcuni amici che hanno un gruppetto in modo da poterla comandare in DMX. La macchina è predisposta per lavorare con un suo comando, il quale ha due controlli, un pulsante per lo spruzzo immediato e la modalità continua comandata da un potenziometro che ne regola l'intensità. Con Arduino sono già riuscito a ricevere il DMX, volevo però introdurre anche una modalità "Timer" dove la macchina si attiva ogni X secondi. Sia per l'indirizzo DMX, sia per la configurazione della modalità e delle tempistiche pensavo di sfruttare un LCD 16x2 e 4 pulsanti. Per i pulsanti sono a corto di pin, così li ho collegati in modo analogico nel seguente modo: Menu -> A0, Exit -> A1, Up -> A2, Down -> A3.

L'idea logica del menù che ho in testa è questa:

+--------------------+
|Mode: DMX (001)     |
|Status: Heating     |
+--------------------+
          |
+--------------------+   +--------------------+   +--------------------+
|Mode selection      |___|Mode selection      |___|Mode selection      |
|> DMX               |   |> Timer             |   |> Remote            |
+--------------------+   +--------------------+   +--------------------+    
          |                        |                        |
+--------------------+   +--------------------+        Back to main 
|DMX Address         |   |Timer interval      |
|> 001               |   |> 60 sec            |
+--------------------+   +--------------------+  
          |                        |
     Back to main        +--------------------+
                         |Timer fog active    |
                         |> 5 sec             |
                         +--------------------+
                                   |
                              Back to main

La conferma avviene con il tasto Menu, il tasto Exit riporta sempre alla prima schermata, Up/Down cambiano i parametri di modalità (DMX, Timer, Remote), indirizzo DMX e intervalli di tempo.

Esempio pratico: Schermata iniziale -> Menu -> Con Up/Down scelgo DMX -> Menu -> Con Up/Down scelgo l'indirizzo -> Menu -> Schermata iniziale.

Ora quello che mi chiedo io è come realizzare un menù di questo tipo? Ho già pronte delle funzioni che mi permettono di salvare modalità, indirizzo e tempi in EEPROM (quindi alla conferma), ma non so come andare oltre ed impostare le schermate. Mi scuso per la lunga spiegazione, ma ho cercato di non tralasciare nulla. Siete un'ottima comunità, leggo spesso i topic, ora solo il vostro aiuto mi può salvare :P

Vai sul blog di liudr e guarda il suo phi menu relativo alla phi shield!

Guarda, ti lascio il sorgente della mia sveglia: è ancora in stato embrionale e poco commentato, ma è abbastanza semplice (:
Se ci sono cose che non capisci, dimmi ^^
La funzione che t’interessa, in particolare, è la showMenu.
Ci sono letture e scritture dalla EEPROM, ed i pulsanti sono gli stessi che usi tu.
Ovviamente, qualsiasi miglioria tu riesca ad apportare al codice, facci sapere :smiley:

ClockUP.pde (10.8 KB)

Grazie mille NeXTWay, ora lo guardo. Stavo guardando la libreria del Phi Shield, ma forse è troppo complicata per me. Vi faccio sapere!

NeXTWay, ho letto un po’ il tuo codice, mi sono anche informato un po’ sulla libreria Bouce, ma forse sono proprio bacato io, come funziona esattamente? Nel mio caso è conveniente usarla per i pulsanti?

Grazie :wink:

mmmh.. perchè mi fate venire queste idee in mente? una bella libreria per dei menu con lcd ]:D

ho già troppe cose da fare :sweat_smile:

comunque se vai a cercare il mio topic riguardo i palmari per tiro con l'arco e rs485 vedi come ho preferito fare i menu

Ok, ora faccio una ricerca ;) Si, ci vorrebbe una bella libreria semplice semplice per gestire i menù ;)

superlol bellissimo come progetto! ;) Ho visto inoltre che hai usato i2c per comandare l'lcd. Anche io ho problemi di pin, mi sai dire qualcosa di più su questo integrato che hai usato? Lo si trova? Per il menù a questo punto non mi resta che prendere spunto! ;)

forno: Ok, ora faccio una ricerca ;) Si, ci vorrebbe una bella libreria semplice semplice per gestire i menù ;)

il problema è che sarebbe pesantissima, io dichiaro una funzione per ogni menu/sottomenu. poi metto un loop fino alla pressione di enter o reset e avendo salvato l'ultimo valore sel pulsante so quale è stato schiacciato, salvo poi la "posizione del cursore" come fosse un id ed in base all'id chiamo un'altro menu.

del tipo:

int posizione = 1;
int ultimopulsante = 0;

void menu_uno() {
  while(ultimopulsante != 5) { //mettiamo che il 5 sia l'ok
    //mostri il menu
    if(ultimopulsante == 3) posizione++; // mettiamo prema su
    if(ultimopulsante == 2) posizione++; // mettiamo prema giù (da implementare un debounce è solo un esempio
  }
  passamenu(posizione);
}

void menu_due() {
  while(ultimopulsante != 5) { //mettiamo che il 5 sia l'ok
    //mostri il menu
    if(ultimopulsante == 3) posizione++; // mettiamo prema su
    if(ultimopulsante == 2) posizione++; // mettiamo prema giù (da implementare un debounce è solo un esempio
  }
  passamenu(posizione);
}

passamenu(int quale) {
  switch(quale) {
    case 1: // assegni ad ogni id una funzione del menu
    menu_uno();
    break;
    case 2:
    menu_due();
    break;
    //ecc...
  }
}

e li fai tutti così

io almeno è come faccio

forno: superlol bellissimo come progetto! ;) Ho visto inoltre che hai usato i2c per comandare l'lcd. Anche io ho problemi di pin, mi sai dire qualcosa di più su questo integrato che hai usato? Lo si trova? Per il menù a questo punto non mi resta che prendere spunto! ;)

grazie ma deve essere ancora completato (mancano un paio di centinaia di righe e poi va tutto ottimizzato, non sai che lavoro)

comunque come ho fatot per il menu te l'ho scritto sopra, poi l'ontegrato è un pcf8574, lo trovi ovunque, basta che prendi quello schema che è allegato, riguardo alla libreria che ho usato l'avevo trovata cercando tempo fa sul forum la dovresti trovare qui: http://www.xs4all.nl/~hmario/arduino/LiquidCrystal_I2C/LiquidCrystal_I2C.zip

è semplicissima e se la spulci un attimo capisci che l'unica cosa che cambia è mettere l'inidrizzo del pcf e poi è uguale alla lcd che usi normalmente

forno: NeXTWay, ho letto un po' il tuo codice, mi sono anche informato un po' sulla libreria Bouce, ma forse sono proprio bacato io, come funziona esattamente? Nel mio caso è conveniente usarla per i pulsanti?

Grazie ;)

Dentro i pulsantini ci sono delle molle. Quando premi, la molla "rimbalza" ed completa/interrompe il circuito più volte. In pratica, premi una volta ed ottieni tre-quattro pressioni. Questo non va bene: Bounce controlla lo stato del pulsante, lo salva in una variabile e lo ricontrolla dopo qualche millesimo di secondo (abbastanza perché il "rimbalzo" sia terminato) e ti restituisce 1 se il pulsante è premuto o 0 se non è premuto.

Problema: tenendo premuto il pulsante, ricevi tanti 1. Per questo ho scritto la funzione click, che impedisce questo (:

Il debouncing devi farlo, specialmente in un menu (altrimenti ti trovi a scorrere tre-quattro voci del menu in una sola pressione... snervante), la funzione click è facoltativa: io l'ho scritta perché mi dava fastidio, tu puoi toglierla o modificarla per permettere lo "scorrimento veloce" dopo che il pulsante viene premuto per un po' (300ms o giù di lì) ;)

Ragazzi siete stati di moltissimo aiuto! Allora mi son già procurato la libreria Bounce, ho visto anche la funzione click, mi sa che ne farò buon uso se non ti dispiace ;) Grazie anche per le precise spiegazioni su come impostare il codice del menù, mi sarà tutto di molto aiuto!

Qualche giorno che mi manca ancora qualche componente poi provo a montare tutto bene su breadboard e vi so dire!

Ciao! bel progettino! io lavoro come tecnico negli spettacoli, e non sai quante persone in giro avrebbero bisogno della stessa modifica che stai facendo tu! un'idea in più potrebbe essere (una volta che ti funziona tutto, ovviamente..) come per le macchine professionali, aggiungere la funzione che con la pressione di up e down contemporanei per un paio di secondi capovolgi X e Y dello schermo. utile quando hai la macchina in posizioni scomode!

Ciao e buon proseguimento!!

uhm…è possibile questo? cioè capovolgere lo schermo?

z3us: uhm.....è possibile questo? cioè capovolgere lo schermo?

non credo proprio, piuttosto puoi forse usando un LCD grafico e girando il tutto, però no non credo che sui normali alfanumerici puoi (al massimo fai 8 caratteri che sono quello che puoi definire, a meno che non li definisci ogni volta ma diventa un casino, anche se rimappando i caratteri forse puoi)

superlol:

z3us: uhm.....è possibile questo? cioè capovolgere lo schermo?

non credo proprio, piuttosto puoi forse usando un LCD grafico e girando il tutto, però no non credo che sui normali alfanumerici puoi (al massimo fai 8 caratteri che sono quello che puoi definire, a meno che non li definisci ogni volta ma diventa un casino, anche se rimappando i caratteri forse puoi)

Oppure, se proprio è una funzione vitale, si monta lo schermo su di un piano in plastica attaccato ad un bullone. Sotto si mette il dado e si può girare il display finché si vuole... Altrimenti, si compra un servo su eBay e si gestisce tutto da Arduino, ma perché complicare così tanto un progetto "semplice"? (:

:) Semplice fino a un certo punto, ho un'altro problema su questo progettino ma non so se mando il topic a quel paese se comincio a chiedere a destra e a manca cose che con il topic non hanno nulla a che fare! ;)

In ogni caso io pensavo che se il progettino riesce discretamente (venerdì 12 concerto, se va tutto bene vorrei portare la breadboard infilata in una scatola come versione beta) pensavo poi di metterlo a disposizione dell'utenza.

Girare lo schermo però mi spaventa assai! Io non ci avevo proprio pensato, ma la vedo dura per quanto riguarda rimappare i caratteri... Galb!

Ora ho l'amico Ardu accanto a me, provo a infilarci qualche menù ;)

Ok, ora si complica tutto…
Per familiarizzare con la libreria Bounce ho usato l’esempio del playground, cambiando solo il pin del pulsante da 2 a 9 per mia comodità…
Ho aggiunto anche il ritorno dello stato del pulsante a video.

// This code turns a led on/off through a debounced switch

#include <Bounce.h>

// This code turns a led on/off through a debounced button
// Build the circuit indicated here: http://arduino.cc/en/Tutorial/Button

#define BUTTON 9
#define LED 13

// Instantiate a Bounce object with a 5 millisecond debounce time
Bounce bouncer = Bounce( BUTTON,5 ); 

void setup() {
  pinMode(BUTTON,INPUT);
  pinMode(LED,OUTPUT);
  Serial.begin(9600);
}

void loop() {
 // Update the debouncer
  bouncer.update ( );

 // Get the update value
 int value = bouncer.read();

 // Turn on or off the LED
 if ( value == HIGH) {
   Serial.println("Button returns HIGH");
   digitalWrite(LED, HIGH );
 } else {
   Serial.println("Button returns LOW"); 
   digitalWrite(LED, LOW );
 }
delay(500);
}

Risultato, che il pulsante sia premuto o meno, quello che mi vedo stampare sulla seriale è sempre HIGH e il led non si spegne mai!
Allora ho fatto un altra prova, di quelle super banali:

void setup() {
  pinMode(9, INPUT);
  pinMode(13, OUTPUT);
}

void loop() {
  if(digitalRead(9))
  {
    digitalWrite(13, HIGH);
  }
  else
  {
    digitalWrite(13, LOW);
  }
  delay(1000);
}

Risultato, quando al pin 9 arrivano 5v il led sta acceso (pulsante premuto), quando stacco i 5v dal pin 9 il led lampeggia…
Qualcuno me lo spiega?

forno:
Risultato, quando al pin 9 arrivano 5v il led sta acceso (pulsante premuto), quando stacco i 5v dal pin 9 il led lampeggia…
Qualcuno me lo spiega?

Mmmh… hai messo una resistenza fra il pin e la terra?

Dovresti avere qualcosa del genere: 5v---->pulsante—>pin digitale<—resistenza—>GND

NeXTWay:

forno:
Risultato, quando al pin 9 arrivano 5v il led sta acceso (pulsante premuto), quando stacco i 5v dal pin 9 il led lampeggia…
Qualcuno me lo spiega?

Mmmh… hai messo una resistenza fra il pin e la terra?

Dovresti avere qualcosa del genere: 5v---->pulsante—>pin digitale<—resistenza—>GND

si chiama resistenza di pulldown è per forzare lo stato a LOW quando non vi è pressione oppure potrebbero arrivare letture “casuali” (per il valroe 1Mohm dovrebbe andare)

inoltre ti consiglio di scrivertelo da te il debounce:

int ultimotasto;
unsigned long ultimomomento;

int delay=300;

void checktasto() {
if(digitalRead(9)==HIGH) {
if(ultimotasto==9) {
if(millis()>=(ultimomomento+delay)){
ultimotasto = 9;
ultimomomento = millis();
}
else { ultimotasto = 0; }
}
else { ultimotasto=9; ultimomomento=millis(); }
}
// ricopia la parte sopra per eventuali altri pulsanti

else { ultimotasto = 0; }
}

richiami checktasto ad ogni ciclo di while e fai un check su ultimotasto, se è 9 il pulsante è premuto.

è un po come ho fatto io dall’altra, in pratica ti restituisce solo una volta per ciclo il valore non so se mi spiego (comunque l’ho battuto ora, ci saranno errori magari)