Un GO TO per Nextion display

Salve a tutti, spero che il titolo sia esaustivo...
Sono Radioamatore e posseggo un controller per un rotore Yaesu G-450c il quale mi ha abbandonato.
In questo controller sono presenti ingranaggini e cinghiette di dubbia qualità e così ho deciso di asportare tutta la parte e sostituirla con un bel display Nextion da 7'.
Solitamente con Arduino riesco a cavarmela anche se in maniera molto prolissa, infatti sono arrivato a buon punto.
Ora sono bloccato in una pagina dove vorrei digitare le due cifre della zona verso cui puntare l'antenna (DXCC), dare invio e fare in modo (previa creazione di una lista di gradi che corrispondano alle varie zone) che il rotore raggiunga i gradi senza toccare i "pulsanti" AVANTI e INDIETRO sulla prima pagina.
Che comando devo scrivere sullo sketch? Ringrazio chiunque abbia voglia di aiutarmi.
Lanfranco
Il video della mia creazione per ora provvisoria nella grafica (anche se la sto già usando con successo):

Il mio sketch:

byte PotentiometerPin = A0;  // Set the pin for the potentiometer.

int PotentiometerValue;  // This variable stores the value of the potentiometer.
int GaugeValue;  // This variable stores the value that we are going to send to the gauge on the display.
int ProgressBarValue;  // This variable stores the value that we are going to send to the progress bar on the display.
int ProgressBar2Value;
int Numerogradi;// visualizza sul display il numero dei gradi di rotazione
int ZoneNumber; //Valore digitato sul tastierino numerico
int CurrentPage = 0;  // Create a variable to store which page is currently loaded







#include <Nextion.h>  

NexButton b0 = NexButton(0, 15, "b0");  // Button added 
NexButton b1 = NexButton(0, 16, "b1");  // Button added

//Tastierino numerico
NexButton b20 = NexButton(2, 2, "b20");  // Button added
NexButton b21 = NexButton(2, 3, "b21");  // Button added
NexButton b22 = NexButton(2, 4, "b22");  // Button added 
NexButton b23 = NexButton(2, 5, "b23");  // Button added
NexButton b24 = NexButton(2, 6, "b24");  // Button added
NexButton b25 = NexButton(2, 7, "b25");  // Button added 
NexButton b26 = NexButton(2, 8, "b26");  // Button added
NexButton b27 = NexButton(2, 9, "b27");  // Button added 
NexButton b28 = NexButton(2, 10, "b28");  // Button added
NexButton b29 = NexButton(2, 11, "b29");  // Button added
NexButton b30 = NexButton(2, 12, "b30");  // Button added
NexButton b31 = NexButton(2, 13, "b31");  // Button added
NexButton b212 = NexButton(2, 15, "b212");  // Button added
NexText t0 = NexText(2,14, "t0");         // Valore digitato su tastierino
NexPage page0 = NexPage(0, 0, "page0");  // Page added as a touch event
NexPage page1 = NexPage(1, 0, "page1");  // Page added as a touch event
NexPage page2 = NexPage(2, 0, "page2");  // Page added as a touch event
NexPage page3 = NexPage(3, 0, "page3");  // Page added as a touch event

NexTouch *nex_listen_list[] = 
{
  
  &b0,  // Button added
  &b1,  // Button added
  &b20, // ----------------------
  &b21,  // Button added        |
  &b22,  // Button added        |
  &b23,  //                     |
  &b24,  // Button added        |
  &b25,  // Button added        |
  &b26,  //                     |  //Tastierino numerico
  &b27,  // Button added        |
  &b28,  // Button added        |
  &b29,  //                     |
  &b30,  //                     |
  &b31,  //                       |
  &b212,   //-------------------- Tasto RETURN
  &page0,  // Page added as a touch event
  &page1,  // Page added as a touch event
  &page2,  // Page added as a touch event
 
  NULL  // String terminated
};  // End of touch event list


// Pulsanti Avanti e indietro Rotore:

void b0PushCallback(void *ptr)  
{
  digitalWrite(2, HIGH);  // Rotore gira in senso Orario CW
}  // End of press event
void b0PopCallback(void *ptr)  
{
  digitalWrite(2, LOW);  // Rotore stop
} 




void b1PushCallback(void *ptr)  // Press event for button b1
{
  digitalWrite(3, HIGH);  // Rotor turn left
}  
void b1PopCallback(void *ptr)  // Release event for button b1
{
  digitalWrite(3, LOW);  // Rotor stop
}  // End of release event



// Page change event:
void page0PushCallback(void *ptr) 
{
  CurrentPage = 0;  
}  

//
void page1PushCallback(void *ptr)  
{
  CurrentPage = 1;  
} 

void page2PushCallback(void *ptr)  // If page 1 is loaded on the display, the following is going to execute:
{
  CurrentPage = 2;  
} 
void page3PushCallback(void *ptr)  // If page 1 is loaded on the display, the following is going to execute:
{
  CurrentPage = 3;  
}  // End of press event


void setup()  // Start of setup
{

  pinMode(PotentiometerPin, INPUT);  
  Serial.begin(9600);  


  b0.attachPush(b0PushCallback);
  b0.attachPop(b0PopCallback);  
  b1.attachPush(b1PushCallback); 
  b1.attachPop(b1PopCallback); 
  page0.attachPush(page0PushCallback);  // Pagina controllo rotazione
  page1.attachPush(page1PushCallback);  // Pagina cartina zone DXCC
  page2.attachPush(page2PushCallback);  // Pagina tastierino numerico
  page3.attachPush(page3PushCallback);  // Pagina Elevazione


  pinMode(13, OUTPUT); // Led overlap
  pinMode(2, OUTPUT);  //Rotazione in senso orario CW
  pinMode(3, OUTPUT);  //Rotazione in senso antiorario CCW

}  // End of setup

void loop()  // Start of loop
{

  delay(100);  



  PotentiometerValue = analogRead(PotentiometerPin);  // leggi il potenziometro da 0 a 1023






  if(CurrentPage == 0){ 
  

Numerogradi = map(PotentiometerValue, 9, 1023, 0, 450);
 if(Numerogradi > 359)  // If gauge value is above 359...
  {
    Numerogradi = Numerogradi - 360;  // Sottrai 360° e riparti da 0° in overlap
  }

  Serial.print("n0.val=");  
  Serial.print(Numerogradi);  
  Serial.write(0xff);  
  Serial.write(0xff);
  Serial.write(0xff);







  GaugeValue = map(PotentiometerValue, 9, 1023, 90, 540);  

  if(GaugeValue > 359)  // se il valore di rotazione supera i 360°
  {
    GaugeValue = GaugeValue - 360;  // ricomincia da 0° (overlap)
  }

 

 
  Serial.print("z0.val=");  
  Serial.print(GaugeValue); 
  Serial.write(0xff);  
  Serial.write(0xff);
  Serial.write(0xff);



  Serial.print("va0.val=");  
  Serial.print(GaugeValue);  
  Serial.write(0xff);  
  Serial.write(0xff);
  Serial.write(0xff);


  ProgressBarValue = map(PotentiometerValue, 9, 818, 0, 100); 
  Serial.print("j0.val="); 
  Serial.print(ProgressBarValue);  
  Serial.write(0xff);  
  Serial.write(0xff);
  Serial.write(0xff);
  
 if(ProgressBarValue < 1)
 {
  digitalWrite (3, LOW); // Blocco software alla rotazione in senso antiorario
 }
 

  ProgressBar2Value = map(PotentiometerValue, 819, 1023, 0, 100);
  Serial.print("j1.val="); 
  Serial.print(ProgressBar2Value);
  Serial.write(0xff);  
  Serial.write(0xff);
  Serial.write(0xff);
  
if(ProgressBar2Value > 2)
 {
  digitalWrite(13,HIGH); // Se la barra di OVERLAP si accende, accendi il led
 }
else
 {
  digitalWrite(13,LOW);}  

if(ProgressBar2Value > 99)
  {
 digitalWrite(2,LOW);  // Blocco software alla rotazione in senso orario
  } 



  nexLoop(nex_listen_list);  // Check for any touch event

 }}

Cerco di indovinare il funzionamento desiderato visto che senza il progetto Nextion è difficile capire esattamente quali sono i pulsanti interessati (magari al posto dei commenti Button added se tu mettessi cosa fa il pulsante...)
Quando premi il pulsante "invio" nella sua callback puoi richiamare N volte la funzione associata al pulsante avanti o indietro, provo a fare un esempio che potrebbe non essere calzante in quanto l'argomento è poco chiaro a me:
Mettiamo che adesso l'antenna è orientata a 115°, dalla tua pagina indichi 42° e premi invio e che ad ogni pressione del pulsante avanti fai un grado:

byte passiDaEsguire = gratiAttuali - gradiDaRaggiungere; //Si non è accurato ma è solo un esempio, se dovessi andare da 360° a 2° sarebbe meglio girare al contarrio e cose così
while(passiDaEseguire >0 )
{
  b0PushCallback();
  delay(XXX);
  b0PopCallback();
  passiDaEseguire--;
}

il delay l'ho inserito anche se non è detto che serva, in ogni caso serve a simulare il dito che tiene premuto il pulsante che va avanti o indietro e sta a te determinare se serve e nel caso quanti millisecondi restare fermo
Come indicato anche nel codice è solo un esempi da otimizzare/rivedere è per spiegare il concetto.
Ovvio che mentre muovi l'antenna con questo sistema Arduino è bloccato li e non può fare altro (Es. non sentirà le pressioni di altri tasti sul Nextion)

Se ho visto male argomenta meglio il funzionamento

Grazie mille per la risposta che vedo solo ora dopo 24 ore di impossibilità a connettersi causa maltempo...
Hai ragione, devo spiegarmi meglio.
Io ho già i due pulsanti che mi fanno ruotare il rotore "manualmente" , ma se devi ruotare di 300° devi stare col dito sul display per un bel pezzo..... La mia idea era quella di digitare su un tastierino numerico un numero (di gradi o di zona) e premendo invio (go to) fare in modo che il rotore giri fino ai gradi digitati senza tenere premuti i pulsanti.
Comunque quello che mi hai scritto è già un buon punto di partenza e ti ringrazio... se ti viene in mente qualcosa di più adatto fammi sapere.
Grazie mille per l'aiuto.
lanjazz

Mettiamo il caso semplice, devo andare a 300° e sono a 2°, premo il bottone avanti, come fai a sapere quando sei arrivato a 300° per togliere il dito dal pulsante? Ovvero Arduino sa in che posizione è l'antenna o stai con il dito finché guardando l'antenna non è nella giusta posizione (spero proprio di no :slight_smile: )?

Nel display ho una "lancetta" che mi indica dove è puntata l'antenna e una finestra che mi mostra i gradi.

display.jpg

Qui :

Il video su Youtube dove puoi vedere a che punto sono.
Grazie ancora.

Mi scuso ma ho omesso una informazione importante. Il rotore in questione non è passo passo ma un normale motore con collegato meccanicamente un potenziometro. Originariamente nel controller c'era un altro potenziometro e il circuito leggeva la differenza di resistenza tra i due muovendo una lancetta meccanica. Ora Arduino legge il valore del potenziometro dentro al rotore.

Se è così allora ti basta, nella funzione di callback del pulsante "invio", leggere i valore in gradi settato sul display, leggere la posizione del potenziometro, calcolare se conviene andare a destra o a sinistra e una volta deciso questo fai quello che fa la pressione del pulsante destra/sinistra (ovvero accendi il rotore), leggi continuamente la posizione del potenziometro e la confronti con quella desiderata, quando è uguale spegni il rotore

digitalWrite(2, HIGH);  // Rotore gira in senso Orario CW
while(posizioneAttualePotenziometro!=posizioneDesiderata)
{
  posizioneAttualePotenziometro = leggi_il_potenziometro;
  //eventualmente se dovesse servire metti un delay
}
digitalWrite(2, LOW);

Il codice d'esempio soffre di un possibile problema ovvero verifica solo che la posizione attuale sia diversa da quella desiderata, se per caso tra una lettura e l'altra il grado viene saltato l'antenna continuerebbe a girare
Es.
PosizioneDesiderata=100°
Attuale=90°
Muovi
91
92
94
95
97
99
101
102
103
105
Non leggendo tutti i valori il grado 100 non è stato letto e quindi resteresti nel while all'infinito (o fino ad un giro completo se hai fortuna e il giro dopo leggi il grado 100), quindi dovrai rendere il codice più sicuro controllando che, in base alla direzione, tu non abbia superato il grado desiderato, nel caso inverti la rotazione finché non arrivi al grado desiderato
Se poi questo caso a te non si presenta allora puoi lasciare così com'è, in ogni caso prevederei un pulsante che interrompa lo spostamento (non si sa mai)

Ottimo spunto. Grazie.
Nel caso qualcosa non funzioni il rotore ha un blocco a micro sui 0°, mentre sui 90° (360+90) in overlap ha un blocco software che mette bassa la porta D2 che comanda lo shield dei relè. Quindi mi divertirò a sperimentare senza (speriamo) che cada il traliccio €

Su i controlli che menzioni (tranne quello dello zero che è hardware se non ho capito male) sono quelli del loop ricorda che mentre sei nel tuo while che legge il movimento a seguito dell'invio il loop non gira e quindi tali controlli non sono operativi, o li sposi in una funzione che richiami sia nel loop sia all'interno del while oppure devi considerare tali controlli non operativi.

ahhh. Capito. Grazie per avermelo ricordato.

Mi chiedevo....
Con quale linguaggio posso dire ad Arduino:

Leggi il numero digitato, (ad esempio 200°)
if(numero digitato<numero ora scritto sul display)
{
digitalWrite(senso orario)
} else
{
digitalWrite(senso antiorario)
}

Cosa posso aggiungere per dire ad Arduino che se per caso salta un grado e si trova con un numero maggiore (o minore) di quello digitato deve tornare indietro (o avanti)?

Se riesco a fare ciò vorrei anche mettere un pulsante HOME che mi porti l'antenna nella posizione NORD 0° che è anche la posizione dove posso calare il carrello in caso di forti venti.... e in questi giorni il forte vento è giornaliero sull'Altopiano di Asiago....
Grazie
Lanfranco

Esattamente come l'hai scritto, ovvero devi leggere dal Nextion il valore imputato dall'utente (nell libreria c'è sicuro qualcosa che ti permette di leggere il valroe di un testo/numero sul display ma io non la uso quindi non so aiutarti) lo metti in una variabile (numero digitato) e lo controlli con la posizione attuale dell'antenna (che poi è quella che invii al nextion che tu indichi con numero ora scritto sul display).
La seconda domanda è di logica ovvero una volta che hai avviato la rotazione (orario o antiorario) la mantieni finché serve (Es. ero a 88° devo andare a 122° finché posattuale<122° giro) quando i gradi sono uguali o maggiori (o minori se antiorario) ti fermi, dopo esserti fermato verifichi se i gradi sono uguali, se si fine altrimenti ruoti al contrario e ripeti finché non raggiungi i gradi corretti, ma questo dovrebbe essere una soluzione estrema ovvero sarebbe meglio che tu riuscissi a scrivere un codice tale da leggere tutti i gradi di movimento dell'antenna.
In ogni caso prevedi (con una variabile) un numero massimo di aggiustamenti in modo da essere sicuro di uscire da un eventuale problema, ovvero sono a 88° devo andare a 122° arrivo a 124° torno indietro ma salto i 122° e vadi a 121°, vado avanti ma salto i 122° e allora torno indietro e così via all'infinito, dopo chessò 5/6 aggiustamenti esci comunque.
Se tutto quello indicato sopra lo infini in una funzione che accetta come parametro i gradi da ragggiungere e dentro la funzione ha tutta la logica necessaria andare a 120°, 23° o 0° (per abbassare l'antenna) sarà la solita cosa, ovvero anche il pulsante che ti riporta a zero richiamerà la solita funzione

OK Fabpolli.. chiaro.
Il ragionamento è lo stesso a grandi linee che ho fatto io. Ma in pratica mi accade questo:
Normalmente senza Nextion, una volta impostate le porte, passi al SETUP e dici se quella porta è alta fai questo, se è bassa fai altro... se la tensione in quella porta analogica è tot fai quest'altro...
Col Nextion sono in difficoltà perchè le varie definizioni sono (per me profano) sparse qua e la'.
Nel caso del mio sketch devo mettere cosa fa il "pulsante" premuto prima del SETUP altrimenti ho un errore, e se utilizzo if e else mi da errore in quanto le definizioni dello stato del potenziometro che manda i gradi sono situati dopo tutto questo, appunto nel SETUP.... insomma in pratica ti sto chiedendo di darmi una mano se puoi. Questo progetto è per sopperire ad un guasto del controller e vorrei finirlo per rimettere in funzione la mia stazione radio. Lo sketch lo vedi nel primo post il software dell'editor Nextion non è allegabile ma posso passartelo in qualche altro modo...... mi faresti un gran bel regalo e dalla soluzione capirei come si comporta il Nextion con Arduino..... se vuoi/puoi.
Grazie in ogni caso.

Ciao, stai facendo confusione, provo a chiarirti un paio di cose prima di procedere.
Allora non devi mai concepire il programma come eseguito dall'alto in basso (in realtà le righe di codice di una funzine vengono elaborate così ma le varie funzioni vanno in esecuzione quando richiamate e non come appaiono nel codice) nel tuo caso usando la libreria Nextion (che ripeto io non uso quindi posso darti supporto limitato) devi definire i vari oggetti che hai disegnato sul nextion e indicare la pagina,il loro id e il loro nome

NexButton b20 = NexButton(2, 2, "b20");  // Button added

Bottone in pagina 2 con id 2 nominato b20. La libreria a fronte di quest'oggetto sa che quando il pulsante viene premuto dovrà richiamare la sua funzione di callback, ad esempio hai definito per i pulsante b0

void b0PushCallback(void *ptr)

All'interno di queste funzioni non esiste nulla che ti impedisca l'uso di if o qualsivoglia altra istruzione così come l'interrogazione uso di variabili definite nel programma soprattutto se queste sono globali.
Quindi se tu definisci un pulsante sul nextion che su Arduino fa partire la funzione "HoPremutoInvia" li dentro puoi andare a leggere il valore impostato in gradi e eseguire gli spostamenti necessari.
Come leggere i gradi impostati non so dirtelo di preciso, credo che nella libreria Nextion ci sia la possibilità di farsi inviare (o ricevere) il dato di un oggetto di tipo numeric o text ma per questo devi studiarti i metodi disponibili nella libreria.
Se poi puoi essere più preciso circa gli errori/problemi che hai incontrato magari riesco a darti un consiglio più preciso

Gentilissimo....
Domani mi ci rimetto... purtroppo ci sono pochi esempi online e i pochi video che potrebbero spiegare sono senza... spiegazioni (non capisco a cosa serve un video You Tube senza spiegazioni.....).
Ero riuscito a far partire il rotore tramite 4 "pulsanti" (NORD, EST, SUD e OVEST) ma una volta giunti ai gradi voluti la definizione (ruota finch'è == Gradi) non funziona e il rotore continua a girare. Funzionava anche la funzione (se posizione attuale < posizione richiesta gira in senso orario) mentre (se posizione attuale >posizione richiesta gira in senso antiorario). Ma poi non funzionavano più i due "pulsanti" manuali CW e CCW (clock e controclock ).

Del Nextion posso dirti che flaggando una casella ogni azione touch invia un codice seriale.
Quindi una volta che ho digitato 100° sulla tastierina touch e ho dato invio, vedo l'invio del seguente messaggio:
31 30 30 ossia da pagina 3 sono stati inviati i numeri 1, 0 e 0.
Ora il problema è farli vedere e gestirli su Arduino.....

Il problema dell'== è quello a cui facevo riferimento alcuni post fa, ovvero se tar lo spostamento e la lettura dell'encoder esiste la possibilità che non tutti i gradi vengono rilevati non puoi (e in linea generale non è mai una buona cosa fare) usare l'== ma < o >, alla peggio sei quanche grado in più o in meno che si va a sistemare con una procedura di orientamento fine ovvero piccoli spostamenti volti a raggiungere il grado desiderato, ma come farla dipende dall'hardware quindi casomai si affronta a tempo debito

Suppongo tu abbia fatto un "tastierino numerico" sul display, hai previsto un campo che fa vedere all'utente il numero digitato e eventualmente un tasto che permetta di cancellare eventuali errori? Se si puoi disattivare l'invio dei singoli pulsanti lasciandolo solo nel pulsante "invio" e quando Arduino riceve il segnale "invio premuto" nella sua callback leggi il valore del campo visualizzato sul Nextion e dovresti essere a posto
Mi scordavo casomai se servisse allegare il codice e/o il file del nextion il forum accetta i file zip

Si, tastierino numerico con visualizzazione dei dati, la possibilità di cancellare errori e il dato viene inviato dal pulsante INVIO.
Per il programma dell'editor Nextion ho provato ad inviarlo come .zip ma non vuole partire...

Ecco il file .zip che potrai aprire con Nextion Editor.
Ancora grazie.

Controller Rotore K3NG2+elevazione2.zip (1.62 MB)