Cosiglio per ottimizzazione codice per uso su display 4D Systems

Salve ragazzi, innanzitutto, scusatemi per il lungo post, ma è difficile dirlo in 4 parole (e non sapevo nemmeno come metterlo in Subject!)

ho un quesito per voi esperti. Sono alle prime armi con Arduino e la programmazione in C/C++, sto tentando di imparare ogni giorno quancosa di nuovo, adesso sto "giocando" (a "Wrestling" direi) con arduino ed un display della 4D Systems, un uLCD144 che tenevo nel cassetto da oltre 1 anno e che con il picaxe non ne aveva voluto sapere di funzionare (ma ci ho anche perso poco tempo, per la verità). Adesso, avendo trovato uno sketch dove veniva usato il mio stesso display, ho deciso di provare, ho collegato tutto come da istruzione "ET VOILA" il tutto funziona al primo colpo. Quindi mi studio la struttura dei comandi e decido di crearmi i miei per provare. Dopo svariate "grattate" finalmente ho incominciato ad "ingranare" e dopo qualche giorno, sono riuscito ad ottenere una "specie di menu" (nel senso che visualizzo una serie di opzioni a schermo e mediante un pulsante incremento un contatore che mi fa comparire un rettangolo rosso sullo sfondo della voce corrispondente e questo si muove al premere il pulsante tra le varie voci e sotto al display, va a scrivere in caratteri più piccoli una specie di GUIDA - HELP di cosa fa quella voce del menù. Esteticamente tutto è molto carino e promette bene. il mio problema, se così posso chiamarlo è:

Quale di questi 4 metodi secondo voi è il migliore per far visualizzare dati ripetitivi dove solo uno cambia (il testo da visualizzare) visto che posizione, dimensioni, fonts ecc sono gli stessi?

//******************************************************************************************************************************
/* Esempio 1:	questo è stato il mio primo approcio "GREZZO" il quale si ripete per altre 3 function identiche tranne che il "testo" string da visualizzare.  FUNZIONA BENE.
*/
void Help_1(){

Serial.write(0x53);			//cmd,
Serial.write(0x01);			//coordinata X,
Serial.write(0x5E);			//coordinata Y,
Serial.write(0x00);			//font,
Serial.write(0xF8);			//colore_MSB,
Serial.write(0x00);			//colore_LSB,
Serial.write(0x01);			//width,
Serial.write(0x01);			//height,
Serial.write("testo da visulizzare 1");	//testo da visualizzare,
Serial.write(0x00); 			//terminatore

}
//**************************************************************************************************************
/* Esempio 2:    ho creato un'array che contiene tutti i dati tranne che gli ultimi 2, poi in un ciclo FOR invio al display i comandi in sequenza usando solo 3 "Serial.write()"...    ANCHE QUESTO FUNZIONA.
*/

void Help_1(){   //di queste function ce ne sono altre 3, numerate Help_2, Help_3 e Help_4...
    
  int i;
  int var;

  char Array_Help_1[8]={0x53,0x01,0x5E,0x00,0xF8,0x00,0x01,0x01};  

//{cmd,X,Y,font,String_Color_MSB,String_Color_LSB,width,height}

  for (i=0; i<8; i++) {  

  Serial.write(var=Array_Help_1[i]);
  }
  Serial.write("testo da visualizzare 1); 
  Serial.write(0x00);   //terminatore                                   
  }
}
//*******************************************************************************************************************
/* Esempio 3:	l'array dell'esempio precedente invece di ripeterlo per 4 functions, ho creato un'unica function e solo la variabile string -  Testo_Help (global) viene aggiornata durante le operazioni di "selezione" della variabile "Selezione_Attiva", quindi in loop() ho un ciclo if...else if che in base al contatore del pulsante mi va a chiamare le function corrispondenti.   ANCHE QUESTO FUNZIONA.
*/

void Help(){

  int i;
  int var;
  char Array_Help_1[8]={0x53,0x01,0x5E,0x00,0xF8,0x00,0x01,0x01};              //{cmd,X,Y,font,String_Color_MSB,String_Color_LSB,width,height}


  for (i=0; i<8; i++) { 
  
  Serial.write(var=Array_Help_1[i]);
    }
  
  Serial.print(Testo_Help); //questa string viene di volta in volta aggiornata in base all'assegnazione alla variabile del testo da visualizzare

  Serial.write(0x00);   //terminatore                                   
  }
//************************************************************************************************************
/* Esempio 4:	Questa è l'ultima evoluzione nella compattazione del codice, o almeno così credevo.  un'unica function, in base al contatore "Selezione_Attiva" che mi dice quale voce del menù è attiva, un switch case mi selezione i testi da assegnare ad una variabile locale.  ANCHE QUESTA FUNZIONA BENE!!
*/

void Help() {

 String Testo_Help;   //variabile string locale
  
  switch (Selezione_Attiva) {	//variabile del contatore posizione menu
    case 1:
      Testo_Help="Testo 1    "; //testo da visualizzare se Selezione_Attiva=1
      break;
    case 2:
      Testo_Help="Testo 2    "; //testo da visualizzare se Selezione_Attiva=2

      break;
    case 3:
      Testo_Help="Testo 3    "; //testo da visualizzare se Selezione_Attiva=3

      break;
    case 4:
      Testo_Help="Testo 4    "; //testo da visualizzare se Selezione_Attiva=4

      break;  
    default: 
      Testo_Help="Selezzionare una voce"; //se nessuno dei precedenti applicasse...
      // default is optional
  }

  int i;			//variabile locale usata solo per il FOR.

  int var;			//variabile locale usata solo per prelevare i dati dall'array.

  char Array_Help[8]={0x53,0x01,0x5E,0x00,0xF8,0x00,0x01,0x01}; 	//{cmd,X,Y,font,String_Color_MSB,String_Color_LSB,width,height}


  for (i=0; i<8; i++) {  
  
  Serial.write(var=Array_Help[i]);
    }
  
  Serial.print(Testo_Help); //variabile con il testo da visualizzare..

  Serial.write(0x00);   //terminatore                                   
  }
}

Adesso, dove sta il problema? Semplice, sono sconcertato dal fatto che a discapito di quello che credevo, l'aver "ottimizzato" in lunghezza codice in termine di linee si è rivelato un dispendio enorme di risorse di memoria flash durante la compilazione!

per Esempio 1: non ricordo i bytes occupati, ma leggermente superiore all' Esempio 2 lo era (sui 7080 bytes circa).
per Esempio 2: 6984 bytes. (i testi string da inviare sono presenti solo nei comandi Serial.write() )
per Esempio 3: 8296 bytes. (i testi string da inviare erano global)
per Esempio 4: 8272 bytes. (i testi string da inviare erano locali)

Quindi credendo di ottimizzare, ho incasinato il programma?? Pensavo che riducendo il numero di Serial.write() ad un minimo avrei ridotto di un bel po i byte di codice compilato, ma ho scoperto che è così solo per i comandi dove NON vi sono STRING come variabili, e qui ho appreso, dolorosamente, che le string sono un vero flagello per la memoria (flash e RAM).

La mia domanda ora è questa: Secondo voi, la soluzione giusta, quale sarebbe?

1- la GREZZA, ed avere un codice lunghissimo che renderebbe tedioso il suo aggiornamento...
2- la mini ottimizzata (esempio 2) che ridurrebbe un po l'estensione delle linee di codice occupate e ridurrebbe un po i bytes di compilazione...
3- l' ottimizzata con variabile string=>global, molto compatta ma dispendiosa di FLASH?
4-l' ottimizzata con variabili string=>locale, ugualmente compatta e leggermente meno dispendiosa di FLASH della soluzione 3?

Ovviamente Voi avreste ottimizzato molto meglio, io fin qui arrivo per ora. E pensare che ho speso almeno 6-7 ore per rivedere il codice dalla soluzione 1 alla 4, se avessi saputo, mi tenevo la GREZZA!!

Scusate del lungo post per una questione così BANALE, ma voglio imparare e capire la sottile differenza che c'é tra "tentare" di imparare e rimanere un "ignorante" in materia. A voi la parola!!

edit by mod: per favore includi il codice usando gli appositi tag

x il Mod: Grazie e scusa, non sapevo come fare (il codice lo avevo scritto direttamente non copia e incolla). Vedrò di ricordarmelo per i prossimi post!

Non so rispondere, più o meno l'una vale l'altra. Dove usi Case/switch devi sapere a priori ciò che verra stampato e quindi perdi in flessibilità. Poi potresti voler risparmiare ram anziché flash e allora devi rivedere alcune cose, in quando le stringhe da stampare devi saperle a priori e le conservi in flash con PROGMEM.

Questa riga di codice potrebbe essere scritta diversamente:

Serial.write(var=Array_Help[i]);

Se la variabile "var" non ti serve, puoi scrivere il codice così:

Serial.write(Array_Help[i]);

Ed elimini la dichiarazione della variabile "var"

Se invece "var" ti serve, meglio la chiarezza così:

var=Array_Help[i]      // in questo modo puoi commentare anche questa riga, ma viene consigliato anche per altri motivi
Serial.write(var);

Guarda che scrivere codice non ti fa affatto male, anche perché così puoi cogliere le sfumature tra le varie versioni
e scegliere secondo necessità.

Ciao.

Grazie Mauro, mi fa molto piacere ricevere tuoi consigli. Visto che sto agli inizi, e voglio imparare il più possibile e purtroppo lo devo fare da autodidatta, mi sto procurando anche dei libri che però fatico a leggere per mancanza di tempo libero, e la sera, quando mi dedico ai programmi sul computer non mi va molto di leggere, ho qualche problema (patologico) di concentrazione e memorizzazione, quindi il tuo consiglio e proprio quello che solitamente faccio: Ripeter più volte le stesse cose in modo da fare tanta pratica, così è più facile che mi resti memorizzato, altrimenti, nel giro di qualche mese dimentico una buona parte.

Anche per me è più importante riservare la RAM rispetto alla flash, tant' è che ho controllato uno degli schetch la RAM libera con freeRam() ed era ok (libera sui 1300 bytes circa) ma considerando che lo schetch è all'inizio proprio, vedo che già queste prove di codice sono già dispendiose, ed è per questo che ho passato ad "ottimizzare" un po, in realtà, e solo grazie all' Open Source di gente come voi che donano il loro prezioso lavoro a tutti quelli come me alle prime armi che ci sto capendo qualcosa in più, specie nel come organizzare un programma a livello di logica e dell'uso delle varie tecniche, e quindi da questo imparo ogni giorno qualcosina nuova e che io stesso mi rendo conto i passi che ho fatto avanti rispetto ai primi programmi fatti alla "grezza" .

Per quanto riguarda il PROGMEM, avevo un'altra idea, quella di usare l' EEPROM interna o addirittura una esterna (tipo 24LC08/16/128/256/512 per esempio che ho già usate in passato con i Picaxe), usando un protocollo di comunicazione che mi consenta di aggiornare questa memoria da PC con tutti i testi utili, così lascio libera la FLASH per il programma e mi consente anche di creare, all'occorrenza diverse versioni e/o lingue, non è che sia necessario questo ma non guasterebbe poterlo fare ed ovviamente, servirebbe ad imparare. Cosa ne pensi?

In sostanza, il PC invia un comando ad arduino, il quale lo percepisce corretto ed esegue, si mette in ascolto e riceve i dati da seriale, li salva in un'array buffer e poi li copia in EEPROM in una sequenza prestabilita, devo solo studiare come fare con le string/char visto che con i numeri a 8 bit ho già fatto delle prove e funziona bene. Con l'uso dell' EEPROM devo solo tenere in considerazione i tempi di accesso ad essa che sono più alti rispetto a quelle della RAM (da datasheet ATMEL, sui 3,3ms ma non sono sicuro del tutto, io sapevo fosse di almeno 20ms) e quindi dovrò prendere in considerazione anche questo per evitare rallentamenti vari. Ovviamente, poi potrò usare questi dati in variabili locali e quindi che non andranno ad occupare troppa RAM.

Una curiosità: ma un'array creata dentro una function (quindi locale) viene creata/distrutta all'interno dell'esecuzione di tale function come le variabili vero? mi sembra di si, ma volevo esserne certo e non darlo per scontato.

Grazie di nuovo per l'aiuto, Ciao,
Antonio

Salve,

mi sto dilettando da qualche tempo con Arduino, dopo aver provato a scrivere qualche sketch mi sto cimentando nella realizzazione di un codice per fare accendere dei led ad Arduino con un comando che arriva dal display touch screen 4DSystem ma partendo dal comando più semplice non riesco a farlo funzionare...
avete un esempio semplice che posso provare per capire come avviene lo scambio dati Arduino UNO e 4Dsystem e viceversa ?

grazie a tutti.!!!

Ovviamente hai scaricato la libreria.

Parti dagli esempi che forniscono loro, sono anche ben commentati sui file pdf che puoi scaricare sempre dal sito.

grazie,

ho caricato la libreria ma non avevo dato un'occhiata agli esempi....

grazie ancora spero di trovare qualcosa che mi possa aiutare

ciao

Salve, spero ci sia qualcuno disponibile ad aiutarmi, ho provato a seguire gli esempi ma mi trovo in una situazione strana perché non mi da errori nella compilazione ma non riesco lo stesso ad accendere con un pulsante sul touchscreen accendere una uscita ed avere un feedback sul LED dello schermo, che tra parentesi è il 4D Systems uLCD-32PT ....

non riesco a capire dov'è l'errore.....

#include <genieArduino.h>


boolean Button0;
boolean Button1;
boolean Button2;
boolean Button3;
boolean Button4;
boolean Button5;
boolean Button6;
boolean Timer_Var;
boolean LED_1 = 13;


Genie genie;
#define RESETLINE 4
void setup()
{

  Serial.begin(9600);
  genie.Begin(Serial);
  genie.AttachEventHandler(myGenieEventHandler);


  pinMode(RESETLINE, OUTPUT);
  pinMode(LED_1, OUTPUT);
  digitalWrite(RESETLINE, 1);
  delay(100);
  digitalWrite(RESETLINE, 0);

  delay (3500);


  genie.WriteContrast(1);



  genie.WriteStr(0, GENIE_VERSION);
}

void loop() {

  {
    if (Button0 == 1) {
      digitalWrite(LED_1, HIGH);
    }
    else {
      digitalWrite(LED_1, HIGH);
    }
  }


}


void ledUpdate()

{
  genie.WriteObject (GENIE_OBJ_DIPSW, 0, Button0);
  genie.WriteObject (GENIE_OBJ_WINBUTTON, 0, Button6);
  genie.WriteObject (GENIE_OBJ_LED_DIGITS, 1, Timer_Var);
  genie.WriteObject (GENIE_OBJ_USER_LED, 0, Button1);
  genie.WriteObject (GENIE_OBJ_USER_LED, 1, Button2);
  genie.WriteObject (GENIE_OBJ_USER_LED, 2, Button3);
  genie.WriteObject (GENIE_OBJ_USER_LED, 3, Button4);
  genie.WriteObject (GENIE_OBJ_USER_LED, 4, Button5);
}



void myGenieEventHandler(void)
{
  genieFrame Event;
  genie.DequeueEvent(&Event);





  if (Event.reportObject.cmd == GENIE_REPORT_EVENT)
  {
    if (Event.reportObject.object == GENIE_OBJ_DIPSW)
    {
      if (Event.reportObject.index == 0)
      {

        genie.WriteObject(GENIE_OBJ_USER_LED, 0x00, Button0);

      }
    }
  }

  {
    if (Button0 == 1) {
      digitalWrite(LED_1, HIGH);
    }
    else {
      digitalWrite(LED_1, HIGH);
    }
  }

}

Per come lo hai scritto, sarebbe strano se funzionasse :grin:

Inizia da una cosa semplice, sullo schermo due pulsanti ed un led, un pulsante per accendere il led e l'altro per spegnerlo.

Ricordati di mettere nel loop il geniedoevents e di mettere fra le proprietà dei pulsanti nell'IDE quando disegni le schermate di generare il report quando vengono azionati.

Hai ragione ma sto cercando di imparare sfruttando anche gli esempi essendo autodidatta !!!!
forse ho fatto il passo più lungo della gamba......
E' una cosa nuova per me che arrivo da progetti semplici come la realizzazione di un ascensore a re piani per la casetta di mia figlia cose cosi senza interfacce grafiche....

grazie per il consiglio partirò da quello.

X iscrizione

??????

....????

Salve,
ho provato realizzare un semplice comando pulsante da display 4DSystem a ARDUINO accendere un uscita e ricevere un feedback per accendere un LED sul display, ma mi rovo in questa condizione:

  • il comando ON arriva subito, ma quando spengo ci mette tanto a spegnere l'uscita ed il LED sul display.

Quale può essere il problema o il mio errore ?

grazie !!!

#include <Picaso_Const4D.h>
#include <Picaso_Serial_4DLib.h>


#include <genieArduino.h>
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>


Genie genie;




#define TERMOREGOLATORE 6
#define RESIST_GRIL 7
#define RESIST_FORNO 9
#define MOTORE_GRIL 13
#define VENTIL_TOTALE 10
#define VENTIL_CENTRALE 11
#define LUCE_FORNO 12
#define LED_FORNO 8
#define LED_FORNO1 12

boolean START;
boolean START1;
bool UserLed0_val ;
boolean Dipswitch_0;
boolean Dipswitch_1;
boolean Dipswitch_2;
boolean Dipswitch_3;
boolean Dipswitch_4;
boolean Dipswitch_5;
boolean Dipswitch_6;
boolean Dipswitch_7;
boolean Dipswitch_8;
boolean Dipswitch_9;
boolean TIMER;
int TEMP = A1;
int LEDDIGIT;
boolean USER_LED_GRIL;
boolean USER_LED_FORNO;
boolean USER_LED_LUCE;
boolean USER_LED_VENTIL_TOTALE;
boolean SLIDER_FUNZIONE_GRIL = false;
boolean SLIDER_FUNZIONE_GRIL1 = false;
boolean SLIDER_FUNZIONE_FORNO = false;
boolean SLIDER_FUNZIONE_VENTILAZIONE_TOT = false;
boolean SLIDER_ACCENSIONE_LUCE = false;





void setup()
{

  Serial.begin(200000);  
  genie.Begin(Serial);  

  genie.AttachEventHandler(myGenieEventHandler);



  pinMode(TEMP, INPUT);
  pinMode(TERMOREGOLATORE, INPUT);
  pinMode (RESIST_GRIL, OUTPUT);
  pinMode (RESIST_FORNO, OUTPUT);
  pinMode (MOTORE_GRIL, OUTPUT);
  pinMode (VENTIL_TOTALE, OUTPUT);
  pinMode (VENTIL_CENTRALE, OUTPUT);
  pinMode (LUCE_FORNO, OUTPUT);
  pinMode (LED_FORNO, OUTPUT);
  pinMode (LED_FORNO1, OUTPUT);


 
  genie.WriteContrast(1); 

}

void loop()
{

  genie.DoEvents();
  
//  genie.AttachEventHandler(myGenieEventHandler); 

  genie.WriteObject (GENIE_OBJ_USER_LED, 0, SLIDER_FUNZIONE_GRIL);



  {
    if (SLIDER_FUNZIONE_GRIL == 1)
    {
      digitalWrite(LED_FORNO, HIGH);
      genie.WriteObject (GENIE_OBJ_USER_LED, 0, 1);
    }
    else {
      digitalWrite(LED_FORNO, LOW);
      genie.WriteObject (GENIE_OBJ_USER_LED, 0, 0);
    }
  }




}
void dangerShield() {

  TEMP = analogRead(A1);
 
  LEDDIGIT = map(analogRead(A1), 0, 1024, 1024, 0);
  
  SLIDER_FUNZIONE_GRIL = genie.ReadObject (GENIE_OBJ_4DBUTTON, 0);
 


}

void lcdUpdate() {


  SLIDER_FUNZIONE_GRIL == genie.ReadObject (GENIE_OBJ_4DBUTTON, 0);
 

}





void myGenieEventHandler(void)
{
  genieFrame Event;
  Event.reportObject.object;
  genie.DequeueEvent(&Event);
  Event.reportObject.cmd;
  Event.reportObject.index;
  SLIDER_FUNZIONE_GRIL = genie.ReadObject (GENIE_OBJ_4DBUTTON, 0);

}

Prova a togliere i primi due include.

Ci vorrebbe una sistemata generale... comunque per il momento, vedi come è la proprietà temporary del 4DBUTTON0. Sarebbe stato meglio usare un interruttore a 2 stati...

Grazie.....

Provato ma nulla....

il 4DBUTTON è impostato come interruttore on/off

mi rendo conto che il percorso è lungo......wow!!!

grazie per il tuo tempo.

Semplifica il codice.

Togli tutti quegli include.
Lascia il genie.

Elimina per adesso tutte quelle variabili, define, ... lascia solo quello che serve per ottenere il primo risultato.
Il primo risultato dovrebbe essere semplice. Sullo schermo un button (per ora metti un fancybutton, il primo) ed un userled. Collega un LED ad una digital out.
Faremo accendere il LED e l'userled sullo schermo quando premi il button, li faremo spegnere quando lo premi e sono accesi.

Schermo: metti un button ed un userled, lascia tutto come lo trovi, tranne che nelle proprietà del button negli eventi alla onchange metti report message e ricordati di mettere nelle generali del progetto la stessa velocità seriale che poi userai nella serial begin.

Collega lo schermo alla tua UNO (e dimmi COME lo stai collegando)

Sulla UNO lascia solo l'essenziale, come abbiamo visto.
Quindi solo l'eventhandler come funzione.
Vediamo un po'....

Sto facendo tutto quello che mi hai scritto. Lo schermo è collegato tramite il suo adattatore per ARDUINO UNO.

Fatto..!!

Funziona?

Riesci a fare accendere e spegnere l'userled?