RISOLTO - Array di const char* inzia da elemento 1???

Buon pomeriggio,

il tempo è tiranno, ma nel fare le modifiche di cui vi ho chiesto in un altro post (non ho ancora finito) mi sono accorto di una cosa che non mi spiego.

Usavo questo array per i giorni della settimana:

String Giorni[] = {"", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"};

e ovviamente visto che l'RTC1307 da' il DoW nel range 1-7 il giorno visualizzato era giusto.

Nei giorni scorsi tra tante altre ho cambiato in

const char* Giorni[] = {"", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"};

risparmiando un po' di memoria, ma adesso mi accorgo che visualizzando "oggi" (mercoledì) sul display esce "Mar".
E in effetti se tolgo la prima stringa vuota (a idx 0) torna "correttamente" a visualizzare "Mer" con indice 3.

Sicuramente mi sfugge qualcosa, non è possibile che quell'array abbia come primo indice 1 invece di zero... o si?

Tra l'altro anche se lo riporto ad array String l'elemento 0 sembra sparito.
La variabile in cui tengo il dato letto dall'RTC è byte (e lo è sempre stata!).

Sono sicuro che ci sia un errore nel codice, ma non so dove.
E' da sabato che osservo e tengo tutto sotto controllo, e anche se ci fosse un mio errore in fase di set dell'RTC poi lo stesso RTC correggerebbe a mezzanotte (stando al datasheet), quindi sbaglio io. :frowning:

Suggerimenti?
Grazie

Karellen:
Tra l'altro anche se lo riporto ad array String l'elemento 0 sembra sparito.

Secondo me, visto che rimettendo String (come la prima riga) non ritorna a funzionare, hai toccato qualcosa d'altro.

Non mi sembra una soluzione "furba" lasciare il primo elemento vuoto.
Io ricaverei l'indice con una semplice sottrazione, se ottieni i gironi con valori 1 a 7, per ricavare l'indice giusto dell'array ti basta sottrarre 1.

giorno=2, array[giorno-1];

...e ovviamente postare anche lo sketch o almeno TUTTE le parti dove fa queste operazioni aiuterebbe a non dover acquistare una sfera di cristallo... :wink:

Scusate, sto leggendo tutto e provando a pensarci, ma non posso aprire l'editor adesso o smetto di lavorre :smiley:

Nel pomeriggio o serata recupero le parti interessate, lo schetch è ancora pieno di 10 righe commentate/di debug per ogni una riga eseguita

Karellen:
Scusate, sto leggendo tutto e provando a pensarci, ma non posso aprire l'editor adesso

Comunque sia, ti confermo:

  1. Gli array iniziano sempre da 0, e non da 1. Punto.
  2. La classe dell'array non influisce sugli indici, come ha detto nid69ita la spiegazione è in qualche altra linea di codice;
  3. In quell'array, come ha detto torn24, se hai 7 elementi non ha comunque senso mettere il primo vuoto, basta usare come indice il codice del giorno - 1

Se vuoi farti una tua verifica dei primi 2 punti fai girare questo e vedrai che danno lo stesso risultato:

void setup() {
  Serial.begin(9600);
  String Giorni1[] = {"", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"};  
  const char* Giorni2[] = {"", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"};
  
  Serial.println(Giorni1[3]);
  Serial.println(Giorni2[3]);
}

void loop() { 
  
}

docdoc:
3) In quell'array, come ha detto torn24, se hai 7 elementi non ha comunque senso mettere il primo vuoto, basta usare come indice il codice del giorno - 1

Su questo NON mi trovate del tutto d'accordo ...
... vero che si occupa UN byte di memoria in più (essendo char array, ovvero stringhe, comunque viene memorizzato almeno lo 0x00 di fine stringa), ma è altrettanto vero che il codice diventa, anche se di poco, più veloce visto che non deve fare ad ogni accesso una sottrazione (carica il registro, decrementa, usa il risultato come valore del puntatore).

Naturalmente, qui probabilmente i pochi μsec in più sono ininfluenti, in altri casi ... potrebbero non esserlo. ::slight_smile:

Guglielmo

gpb01:
Naturalmente, qui probabilmente i pochi μsec in più sono ininfluenti, in altri casi ... potrebbero non esserlo. ::slight_smile:

Naturalmente qui è sempre il bilanciamento tra velocità di esecuzione, occupazione di memoria, leggibilità del codice. In linea di massima i primi due aspetti sono generalmente più importanti del terzo, e tra loro due a seconda del contesto si deve scegliere cosa preferire.
Visto che non abbiamo indizi sui primi due, per il terzo (leggibilità del codice) è sempre preferibile mantenere una certa logica, tutto qui... :wink:

docdoc:
Comunque sia, ti confermo:

  1. Gli array iniziano sempre da 0, e non da 1. Punto.
  2. La classe dell'array non influisce sugli indici, come ha detto nid69ita la spiegazione è in qualche altra linea di codice;
  3. In quell'array, come ha detto torn24, se hai 7 elementi non ha comunque senso mettere il primo vuoto, basta usare come indice il codice del giorno - 1

Ciao, la 1) e la 2) mi confermano che ho cannato qualcosa da qualche parte; mi son deciso a scrivere dopo qualche giorno che guardicchiavo il codice giusto perché mi era balenato il dubbio di qualche eccezione per C (che non conosco ancora).

Di fatto quell'elemento vuoto è un refuso alla fin fine. Tenderei a lasciarlo, ma mi serviva solo per far partire la scelta dell'utente in fase di set data perché il datasheet dice che l'RTC aggiorna a mezzanotte e non al volo quando riceve dati, poi ho cmq implementato il calcolo.

Per la 3) leggo Guglielmo mentre vedo il preview della risposta, e in effetti era proprio quella l'idea.
Considerando che l'obbiettivo finale è di ficcare 16KB di codice e 1045B di sdram (al momento) in un ATTiny a 1MHz ... chiaramente dopo opportuna e pesantissima cura dimagrante :smiley:

Che poi per mia forma mentis questi micro/nano secondi tento a risparmiarli in JavaScript/PHP figuriamoci qua! :smiley: :smiley: :smiley:

Karellen:
... Considerando che l'obbiettivo finale è di ficcare 16KB di codice e 1045B di sdram (al momento) in un ATTiny a 1MHz ...

Che ATTiny intendi utilizzare ?

Guglielmo

gpb01:
Che ATTiny intendi utilizzare ?

Guglielmo

ATTiny85
Ho comprato solo quelli, d'accordo che senza sfide non mi diverto però... :slight_smile:

Mmm ... gli ATTiny85 hanno solo 8KB di flash per il programma e 512 bytes di SRAM ...
... ho idea che dovrai fare una bella cura dimagrante al tuo codice :smiley: :smiley: :smiley:

Guglielmo

Hmm... Direi allora che intanto "String" è da considerare veleno, da eliminare completamente. Poi una bottarella di PROGMEM per quell'array dei giorni (dal quale togliere l'elemento iniziale vuoto) e tutti gli altri eventuali e costanti varie, usare F(), macro per i numeri di pin, convertire in byte variabili che contengono valori interi non superiorei a 255, eccetera.
Ma stiamo ora facendo accademia, senza aver visto il codice non ci sono molte indicazioni più specifiche da poter dare. Se poi si aggiunge che non ho mai programmato ATTiny85... :wink:

docdoc:
... Poi una bottarella di PROGMEM per quell'array dei giorni (dal quale togliere l'elemento iniziale vuoto) e tutti gli altri eventuali e costanti varie, usare F(), macro ...

Mah ... considerando che il suo codice attualmente occupa (come afferma) 16KB e che dovrà farlo stare in 8KB ... NON mi sembra il caso di consigliargli altra roba in flash :smiley: :smiley: :smiley:

Guglielmo

P.S.: Certo che pure con la SRAM sta messo maluccio ... deve far stare 1KB di roba in 512 bytes ... ::slight_smile:

Bella sfida
Si narra che Hilbert, alla domanda su quale sarebbe stata secondo lui la più grande conquista del ventesimo secolo abbia risposto: "andare a caccia farfalle sulla Luna"
E poi abbia spiegato che avrebbe richiesto lo sviluppo di talmente tanta tecnologia da giustificare uno sforzo cosi apparentemente futile.
Questa è una sfida del genere.
Obbiettivo apparentemente impossibile, ma occasione di imparare tanto.
Piatto ricco mi ci ficco
Come posso aiutare?

RISOLTO mannaggiammè!

Beh, ovviamente il problema non stava nel chip a base silicio, ma nella macchina umanoide a base carbonio :smiley:

Sarò prolisso, ma come errore da principiante non è niente male e può servire ad altri.
Anche se io avrei dovuto evitarlo :frowning:

Nella funzione di set della data, per scrivere direttamente corretto il DoW, avevo trasportato questa procedura (Sakamoto's method) quando l'array ValoriIniziali (che conserva i valori in fase di modifica) era ancora int, quindi con range da interi.
Ed è cominciato tutto quando ho iniziato a passare variabili ed array da int a byte

Questo è il codice che ricalcola il DoW quando viene impostata la data per l'RTC; vari pezzi coinvolti:

int DOW2RTCConv[] = {7, 1, 2, 3, 4, 5, 6};  
int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
int y=ValoriIniziali[0]; // --- (*)
y -= ValoriIniziali[1] < 3;
dw = (y + int(y/4) - int(y/100) + int(y/400) + t[ValoriIniziali[1]-1] + ValoriIniziali[2]) % 7;
...
dw = decToBcd(DOW2RTCConv[dw]);
...
Wire.write(dw); //4° byte GIORNO della settimana da 0x01 a 0x07
...
...
// Conversione normali numeri decimali in binario decimale
byte decToBcd(byte val)
 {
 return ( (val/10*16) + (val%10) );
 }

Sulla riga con (*) torno subito, il problema stava tutto li.

ValoriIniziali[] ha questa struttura:

byte ValoriIniziali[] = {18, 02, 15, 21, 44, 0}; // --- A Runtime dall'RTC - Anno-Secondi (no dow)

e come da commento viene aggiornata ogni volta che viene letto l'RTC (ogni secondo).

Però finché era int ad ogni lettura dell'anno (RTC1307 fornisce 00-99) veniva incrementata subito di 2000, mentre quando l'ho passata a byte l'incremento l'ho tolto ed aggiungo alternativamente la stringa "20" o il valore 2000 a seconda che sto scrivendo il display o modificando l'anno.
E dato che ValoriIniziali[0] era già "2000+qualcosa" lo riprendevo pari pari nell'istruzione (*)

Ha funzionato tutto bene, anche dopo aver cambiato nel codice gli int in byte, perché il valore letto dall'RTC e le varie vislualizzazioni erano coerenti
Finché (dopo aver cambiato int a byte) ho dovuto appunto aggiungere 2000 al valore visualizzato sul display durante la modifica anno e non ho riscritto per la prima volta l'RTC.
L'RTC prendeva il giusto valore (00-99) e continuava a lavorare con il giusto valore per l'anno, ma nel calcolo del DoW (che va scritto o verrebbe aggiornato/corretto solo a mezzanotte) mi ero dimenticato di aggiungere 2000 in quella riga, quindi veniva calcolato e scritto male, e io non mi ritrovavo più con gli indici dell'array :frowning: :frowning: :frowning:

Quel pezzo di codice, quindi, diventa corretto in questo modo:

int DOW2RTCConv[] = {7, 1, 2, 3, 4, 5, 6};  
int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
int y=ValoriIniziali[0]+2000; // --- (***)
y -= ValoriIniziali[1] < 3; // --- Anno è byte devo aggiungere 2000 (*)
dw = (y + int(y/4) - int(y/100) + int(y/400) + t[ValoriIniziali[1]-1] + ValoriIniziali[2]) % 7;
...
dw = decToBcd(DOW2RTCConv[dw]);
...
Wire.write(dw); //4° byte GIORNO della settimana da 0x01 a 0x07
...
...
// Conversione normali numeri decimali in binario decimale
byte decToBcd(byte val)
 {
 return ( (val/10*16) + (val%10) );
 }

e ovviamente l'array dei giorni DEVE essere

const char* Giorni[] = {"", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"};

Prima di postare ho fatto varie prove sia di setting data che verifica anche simulando il passaggio dalla mezzanotte, ed ora funziona correttamente e l'array va popolato come sapevo essere corretto.

Grazie a tutti per l'aiuto, fra poco quoto un'ultima cosa da una delle risposte perché mi è nuova.

Morale della favola: quando tocchi una variabile controlla sempre millemila volte dove e come la usi, pure se scrivi codice da tanti anni :grin:

docdoc:
... macro per i numeri di pin ...

"macro" mi sfugge, cosa significa?
Grazie.

gpb01:
Mah ... considerando che il suo codice attualmente occupa (come afferma) 16KB e che dovrà farlo stare in 8KB ... NON mi sembra il caso di consigliargli altra roba in flash :smiley: :smiley: :smiley:

Guglielmo

P.S.: Certo che pure con la SRAM sta messo maluccio ... deve far stare 1KB di roba in 512 bytes ... ::slight_smile:

Ho ottimissime speranze (passatemi l'itaglianese).
300B di flash e 64 di SDRAM vanno via già evitando di scrivere giorno/data/ora in 3 String appena lette dall'RTC he poi per il 99% del tempo servono solo a mostrarle sul display. Basterà fare lcd.print() a manetta.
Inoltre ho ancora tanti unsigned long per debug che non servono più.

Forse strettissimo, ma dovrei farcela; sistemo l'ultima cosa che non funziona come mi aspetto e poi ripulisco e vi mostro lo sketch in tutto il suo "splendore" :smiley:

Mi piacerebbe mostrarvi anche uno schema, mi suggerite per un editor per schemi elettrici che dia dei disegni "belli" come quelli che faceva Nuova Elettronica?

O magari come faccio a disegnare quelle belle immagini che si vedono con tanto di scheda Arduino che non ho ancora capito come si fanno?

In calce una foto del progettino, col dito ho coperto due led che saturavano la fotocamera.

nid69ita:
Secondo me, visto che rimettendo String (come la prima riga) non ritorna a funzionare, hai toccato qualcosa d'altro.

;D

Karellen:
O magari come faccio a disegnare quelle belle immagini che si vedono con tanto di scheda Arduino che non ho ancora capito come si fanno?

Si usa quella schifezza (opinione del tutto personale) di Fritzing!

Ma invece di usare certi "giocattoli" (sempre opinione personale), impara ad usare un programma "vero", tipo Eagle (gratuito per board fino ad una certa dimensione di circuito stampato) o Kicad :wink:

Guglielmo