Ok, quindi sarebbe più corretto fare cosi?
char parteRipetuta[14] = "btnStartCalPh"; //globale
char messaggio1[6] = "Calib";
myNextion.setComponentText(parteRipetuta, messaggio1)
Ok, quindi sarebbe più corretto fare cosi?
char parteRipetuta[14] = "btnStartCalPh"; //globale
char messaggio1[6] = "Calib";
myNextion.setComponentText(parteRipetuta, messaggio1)
NO, così occupi SRAM ... con la macro F() sposti in Flash ... non so più come dirtelo ... :
Guglielmo
Porta pazienza ma probabilmente argomenti che per te sono ovvi per altri non lo sono, come sicuramente varrà lo stesso discorso con te in altri ambiti. Di certo non voglio spazientirti, mi scuso se le domande sono ripetute o se dò l'impressione di non provare a capirle ma non è così, di mestiere faccio altro e l'impegno che provo a metterti per capire questo genere di argomenti non è poco.
Quello che non capisco, quello che mi crea confusione è questo:
gpb01:
La macro F() può essere utilizzata SOLO con stringhe costanti (quindi NON con variabili di tipo char array o altro) e con null'altro.Guglielmo
Perfetto, solo stringhe costanti.
gpb01:
Ok, quindi sarebbe più corretto fare cosi?
Code: [Select]
char parteRipetuta[14] = "btnStartCalPh"; //globale
char messaggio1[6] = "Calib";
myNextion.setComponentText(parteRipetuta, messaggio1)
NO, così occupi SRAM ... con la macro F() sposti in Flash ... non so più come dirtelo ... :Guglielmo
Ok, quindi è meglio usare la macro F().
Ma allora se è meglio usare la macro F() perchè l'esempio fatto qui
char parteRipetuta[14] = "btnStartCalPh"; //globale
myNextion.setComponentText(parteRipetuta, F("Calib"));
Non viene fatto così dato che sto scrivendo una stringa costante ?
myNextion.setComponentText(F("btnStartCalPh"), F("Calib"));
Grazie per il tempo che mi dedichi
Chiedi a fabpolli perché ha usato una certa logica ... il codice è il suo ... magari la prima parte gli serve variabile e quindi non lo può fare o la funzione chiamata (che NON conosco) è in grado di usare la macro F() (... perché oltre a metterla la funzione deve sapere cosa farci) solo nel secondo parametro ... non ho idea ... :
Guglielmo
Allora non è che non puoi usarlo è che se fai così:
myNextion.setComponentText(F("btnStartCalPh"), F("Calib"));
myNextion.setComponentText(F("btnStartCalPh.bco=9"), ...);
Occupi più del doppio della flash. Se hai spazio e prefersci fare così puoi anche vedere se la setComponentText accetta come primo parametro il risultato della funzione F, io non usando la libreria non so dirtelo.
Se non dovesse supportarlo hai già modificato la libreria seguendo la soluzione del vecchio topic puoi vedere se si riesce ad adattare la libreria alla tua esigenza, ma quello dipende dalle tuo conoscenze.
Tutto qusto però non esula dal dover rimuovere la classe String, risparmiare dieci byte di SRAM e mantenere le String è come andare a caccia di leoni (quelli liberati in Russia ) con una foglia di salvia.
Io preferisco avere tutti char di array che riuso definiti come globali e avere certezza della SRAM impiegata piuttosto che altre soluzioni, qualcuno storcerà il naso (le globali vanno limitate il più possibile di solito), a me piace di più così.
Certo in alcune funzioni definisco degli array temporanei per assemblare le stringhe da inviare ma quelli non sono un problema, lasciare la SRAM libera serve proprio a permettere al programma di funzionare allocando memoria quando e dove serve.
Grazie a tutti per l'aiuto.
Provo a fare un riassunto per capire se ce ne vengo fuori.
Utilizzando la macro F() o comunque la classe String in generale, porterà a sicuri problemi a causa della continua allocazione e riallocazione dinamica della memoria, quindi in un momento o in un altro arduino potrebbe crashare.
Di contro andare a dichiarare char array globali da utilizzare nel programma, mi va ad aumentare la memoria utilizzata appunto dalle variabili globali, però dichiarandole inizialmente si evita il problema dell'utilizzo della classe String e i suoi problemi di cui sopra.
Quanti cavolate ho detto sto giro? :
bubba21:
Utilizzando la macro F() o comunque la classe String in generale, porterà a sicuri problemi a causa della continua allocazione e riallocazione dinamica della memoria, quindi in un momento o in un altro arduino potrebbe crashare.
Ma le leggi con attenzione le cose che ti si scrivono o no ? ? ? :o :o :o
Cosa ha a che vedere la macro F() con la classe String() ? ? ? ... e perché la macro F() dovrebbe creare problemi ? ? ?
Rileggiti TUTTI gli interventi in merito, ma con attenzione, perché mi sembra che tutto quello che ti abbiamo scritto lo hai letto piuttosto male ... :
Guglielmo
E' evidente che l'argomento va oltre alle mie capacità non avendo le conoscenze di base, non voglio farvi perdere ulteriore tempo.
Grazie comunque per l'aiuto e buona giornata.
No, mi spiace ma NON sono d'accordo e non l'accetto ... NON è affatto questione di conoscenze, è questione di leggere con attenzione ciò che gli altri scrivono ...
gpb01:
La macro F() è solo per le stringhe classiche del 'C' (char array).In pratica puoi SOLO usarla quando hai una situazione di F( "stringa_di_caratteri" ) ovvero una serie di caratteri racchiusi tra doppi apici.
gpb01:
La macro F() ha il solo scopo di ridurre l'occupazione della SRAM (sposta le strighe costati dalla SRAM alla Flash, liberando quindi la SRAM) e ... più SRAM hai libera, minore è la probabilità di avere problemi per esaurimento di essa.
gpb01:
NO, così occupi SRAM ... con la macro F() sposti in Flash ...
... come vedi NON si tratta di avere conoscenze, si tratta di leggere attentamente perché, cosa fa la macro F() e quale è il suo scopo, è scritto più che chiaramente.
Guglielmo
La macro F() memorizza ciò che metti nelle "variabili" nella memoria FLASH, che può solo essere scritta in fase di programmazione, perciò diventano delle costanti, che non puoi più modificare durante l'esecuzione del programma.
Le variabili, viceversa, sono scritte nella RAM, che può essere scritta durante l'esecuzione del programma, ma ha una capacità molto inferiore alla FLASH.
gpb01, grazie per la pazienza e grazie Datman per l'ulteriore spiegazione.
Sto inserendo la macro F() in ogni posto dove ho stringhe di caratteri costanti e sto mettendo mano a tutte le conversioni che facevo utilizzando per esempio
unsigned int EC; //dichiarata globale
myNextion.setComponentText(F("txtEC"), String(EC));
sostituendole con le funzioni classiche del c
unsigned int EC; //dichiarata globale
char bufferHMI[10]; //dichiarata globale
itoa(EC, bufferHMI, 10);
myNextion.setComponentText(F("txtEC"), bufferHMI);
Nel caso io abbia dichiarato globali
byte conteggi;
char bufferHMI[10];
La conversione da byte a char come sarebbe meglio farla? Non ho trovato una funzione come la itoa(), anche se ho visto che non mi dà errore utilizzandola anche in questo caso. Così come la funzione sprintf(), in entrambi i casi funziona la conversione
sprintf(bufferHMI, "%d", conteggi);
itoa(conteggi, bufferHMI, 10);
Ma quale sarebbe il metodo più opportuno in caso di conversione da byte?
Il byte (non segnato) ed il char (segnato) si possonio considerare un sotto insieme del int (segnato) quindi usi la itoa().
Guglielmo
Sto andando avanti con l'eliminazione di quelle che riguarda la classe String nella parte di gestione dei messaggi in arrivo dal touch via seriale.
Ho modificato i vari .substring con memcpy come qui sotto
//subStr = messaggioSeriale.substring(0,2);
memcpy(subStrHMI, message, 2);
e stessa cosa con le comparazioni
//if (subStr == "68" && IDpagina == 0) {
if (strcmp(subStrHMI, "68") == 0 && IDpagina == 0) {
Mi ritrovo un attimo bloccato per quanto riguarda l'estrapolazione delle sottostringhe che partono da una posizione intermedia. Per esempio
String subStr = messaggioSeriale.substring(3,8);
Non trovando una funzione ad hoc nella libreria string.h, ho fatto una cosa del genere.. Funziona, ma non mi sembra molto elegante
char subStr2[8];
for (byte index = 0; index < 3; index++) {
subStr2[index] = message[index+2];
}
Esiste qualcosa di fatto meglio?
Tralasciando il problema di performnce, ecc. il tuo sistema va bene e può essere più chiaro da interpretare all'inizio quando la logica dei puntatori delle stringhe è cosa poco conosciuta/ostica. Per copiare le stringhe si usa la funzione
strncpy che copia un certo numero di caratteri (terzo parametro) dall'origine (secondo parametro) alla destinazione (primo parametro). Quando tu fai una cosa del tipo:
char temp[5];
strncpy(temp, origine, 2);
stai dicendo copiami due caratteri dall'indirizzo di memoria dove è memorizzato origine nella memoria dove posso contenere i dati di temp.
Una stringa classica del C è un array di caratteri che, per definizione, sono contigui, ovvero se origine parte dalla posizione di memoria 123 il suo elemento zero ha tale indirizzo di memoria, l'elemento uno avrà indirizzo 124 e così via.
Tu nella tua funzione copi gli elementi sfruttando le posizione dell'indice dell'array (giustissimo), stessa cosa la puoi far fare alla funzion standard indicandogli da che elemento partire:
char temp[5];
strncpy(temp, origine + 2,2);
o anche (che magari è più chiaro da leggere)
strncpy(temp, &origine[2],2);
Vedi che nel primo caso indico di partire da un indirizo di memoria noto più un numero di posizioni, mentre nel secondo caso indicando l'indice devo mettere la e commerciale per dire al compilatore che voglio possare l'indirizzo di memoria e non il valore in esso contenuto.
Grazie fabpolli, sei stato molto chiaro.
Non sapevo si possero gestile gli indirizzi in questa maniera, effettivamente ieri cercando qua e là ho trovato molti esempi dove mettevano la & ma non avevo capito il funzionamento.
Vado a implementare le modifiche che mi hai suggerito subito, grazie!
Ok implementato e funzionante.
Praticamente inserendo la macro F() e ottimizzando il tutto lo sketch è passato da:
39256 byte 15% di spazio disponibile
6243 byte 76% di memoria dinamica
a
40146 byte 15% di spazio disponibile
4302 byte 52% di memoria dinamica
e ho eliminato ogni String utilizzando le funzioni classiche.
Grazie a tutti per l'aiuto e per la pazienza e scusate se vi ho fatti un po' disperare
Sto graficando su Nextion un array di 420 elementi e siccome prima usavo la classe String per inviarli, adesso li sto modificando con le funzioni classiche.
Vorrei capire se è corretto fare una cosa del genere, la prima volta andavo ogni volta a dichiarare la variabile bufferDaInviare dentro al ciclo for pensando che si inizializzasse ogni volta ma non funzionava, allora uso il memset per svuotarla, è corretto fare così?
// dichiarate globali
const unsigned int dimensioneTabella_Temperatura = 420;
unsigned int arrayStorico_Temperatura[dimensioneTabella_Temperatura];
char bufferDisegnoGrafici[9] = "add 1,0,";
// Disegno trend
char bufferValore[5];
char bufferDaInviare[15];
for(unsigned int h = 0; h < dimensioneTabella_Temperatura - 1; h++) {
memset(bufferDaInviare, 0, 15);
byte calcolo = arrayStorico_Temperatura[(progressivoGrafico_Temperatura + 1 + h) % dimensioneTabella_Temperatura];
itoa(calcolo, bufferValore, 10);
strcat(bufferDaInviare, bufferDisegnoGrafici);
strncat(bufferDaInviare, bufferValore, strlen(bufferValore));
myNextion.sendCommand(bufferDaInviare);
delay(5);
}
La memset() non fa altro che riempire con il valore 0x00 tutti gli elmenti del vettore "bufferDaInviare" ... ma ti serve veramente farlo?
Dato che tu usi quella variabile con le funzioni della <string.h>, se metti a 0x00 solo il primo elemento, "bufferDaInvire[0]" hai, per il linguaggio 'C', già creato una stringa vuota su cui puoi tranquillamente operare con le suddette funzioni.
Guglielmo
Sto facendo qualche prova, ma quindi andando a impostare a 0x00 un indice (non necessariamente il [ 0 ]), tutti quelli successivi vengono valorizzati a zero?
Perchè ho modificato il codice così in modo da risparmiare un concatenamento e funzionerebbe
// dichiarate globali
const unsigned int dimensioneTabella_Temperatura = 420;
unsigned int arrayStorico_Temperatura[dimensioneTabella_Temperatura];
char bufferDisegnoGrafici[9] = "add 1,0,";
// Disegno trend
char bufferValore[5];
char bufferDaInviare[15];
// Concateno qui una volta sola senza farlo ad ogni ciclo
strcat(bufferDaInviare, bufferDisegnoGrafici);
for(unsigned int h = 0; h < dimensioneTabella_Temperatura - 1; h++) {
bufferDaInviare[8] = 0x00;
byte calcolo = arrayStorico_Temperatura[(progressivoGrafico_Temperatura + 1 + h) % dimensioneTabella_Temperatura];
itoa(calcolo, bufferValore, 10);
strncat(bufferDaInviare, bufferValore, strlen(bufferValore));
myNextion.sendCommand(bufferDaInviare);
delay(5);
}