Valore strano variabile INT

Buongiorno, sto progettando un sistema di irrigazione con 4 rele tastiera e display, ho finito il codice ma chiaramente non funziona... (tra collegamenti provvisori ed errori di codice).
Quindi ho iniziato il debugging, ho inserito la stampa su seriale di tre variabili: debug (tiene il conto delle volte che viene premuto un tasto (funziona, dopo aver sistemato i cavi), Output(mi dovrebbe dare il valore del tasto premuto, non funziona ma da rivedere) e Stato (dovrebbe avere i valori di 0 e 1 ma dopo il primo loop il suo valore diventa 13622 !!! e resta tale fino a che non premo un tasto dopodiche correttamente diventa 1).

Non riesco a capire da dove provenga quel valore

Inserisco il codice con il timore di venire redarguito per la lunghezza la poca eleganza del codice :slight_smile:
Eccedendo la quantità massima di caratteri allego il file .ino

IrrigOne_C.ino (27.2 KB)

Ciao un problema potrebbe essere questo:

#define M       5   // Locazione iniziale Eeprom

se non sbaglio così il compilatore sostituirà ogni "M" maiuscola con 5 prima di compilare il codice e quindi ti sballerà un po' tutto.. prova a sostituire quel define con un valore che sia univoco e non ambiguo.

Scusa ma M è il nome della variabile perchè dovrebbe generare problemi?

well66:
Scusa, ma M è il nome della variabile. Perchè dovrebbe generare problemi?

No! M non è una variabile! Tu stai definendo in una macro il carattere M come 5! Perciò, prima di compilare, il preprocessore dell'IDE sostituirà 5 a ogni M che trova scritta nel programma!
Credo che sia proprio come un "Cerca e sostituisci"!...

Esatto Datman! Qui spiega proprio questo:

#define is a useful C++ component that allows the programmer to give a name to a constant value before the program is compiled. Defined constants in arduino don’t take up any program memory space on the chip. The compiler will replace references to these constants with the defined value at compile time.

This can have some unwanted side effects though, if for example, a constant name that had been #defined is included in some other constant or variable name. In that case the text would be replaced by the #defined number (or text).

Ok, avevo capito male il concetto di #define, ho sostituito

#define M 5 con
const byte M =5;

in questo modo M è diventata una costante e dovremmo aver superato quel problema, però il risultato non cambia: al secondo loop Stato passa da 0 a 13622

la variabile Stato essendo usata all'interno di una funzione di interrupt è dichiarata come volatile, è corretto?
Ho provato anche ad usare solo INT ma non cambia

Nel tuo programma io vedo un'altro problema, che NON so può essere la cusa di ciò che riscontri ...

La variabile Stato è una variabile che, in un momento indefinito, può essere aggiornata da un interrupt e tu NON sai quando questo avviene. Essa è di tipo int quindi occupa DUE bytes e ogni suo aggiornamento richiede una serie di cicli macchina ... ecco, ora pensa che mentre tu la stai leggendo nel loop() scatta magari l'interrupt ...

... il tuo codice per la lettura della variabile, visto in assembler, si compone di varie fasi, lettra del primo byte, shift, lettura del secondo byte, composizione del int, assegnazione del valore, ecc ... che succede se dopo che il tuo codice compilato, ha letto il primo byte e scatta l'interrupt? ... te lo dico io ... che ti trovi con un valore corrotto, metà precedente all'interrupt e metà seguente all'interrupt che l'ha aggiornato. :confused:

Come si risolve ... usando una variabile d'appoggio che legge la variabile Stato in una condizione NON interrompibile ed usando poi, nei vari test, tale variabile d'appoggio che NON viene alterata fino alla successiva assegnazione "sicura".

In pratica dovrai fare, in un punto del loop() la seguente cosa:

...
...
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
   Stato_copia = Stato;
}
...
...
if (Stato_copia == 0) {
...
...

... spero sia chiaro il concetto :slight_smile:

Guglielmo

Riguardo l'interrupt era venuto qualche dubbio pure a me,
adesso però ho ricablato tutto e mi sono accorto con mia sorpresa che adesso il valore è corretto, perche prima avevo scollegato display rtc e sensori.
E' possibile che avendo dei pin configurati ma aperti arduino non esegua in modo corretto il codice dando valori a vanvera?
E' la prima volta che creo un codice un po' complesso con tanti sensori e dispositivi collegati, probabilmente devo procedere step by step...

... quanto ti ho detto è indipendente da tutto ed è SEMPRE valido quando si usano gli interrupts, quindi, se vuoi avere una cosa affidabile, è ... obbligatorio :wink:

Guglielmo

E' possibile che avendo dei pin configurati ma aperti arduino non esegua in modo corretto il codice dando valori a vanvera?

Non ci hai detto che arduino stai usando perché l'interrupt tu lo hai configurato cosi':

  attachInterrupt(0, Read_Data, FALLING);

Interrupt 0 che se è un arduino uno è il pin 2. Nel tuo codice non vedo configurato il pin 2 o allora non ho capito come hai fatto! ::confused:

well66:
Inserisco il codice con il timore di venire redarguito per la lunghezza la poca eleganza del codice :slight_smile:

Beh più che "poca eleganza" ti suggerirei di cercare di prendere pratica con gli array e soprattutto con un minimo di programmazione strutturata... :wink: Quindi non ti si "redarguisce", ti si dà eventualmente solo qualche consiglio "stilistico" per rendere la vita più facile a te (e a noi), cosa che spero ti possa risultare gradita. :wink:

Intanto quando il programma diventa abbastanza lungo converrebbe dividerlo in più file, dei *.ino per raggruppare le funzioni per categoria, e dei *.h per le configurazioni e costanti.

Poi per fare un esempio del discorso array, se le tue schermate le mettessi in un array le cui dimensioni rappresentino il numero schermata e il numero di riga potresti non solo avere definizioni più compatte ma anche usare un semplice indice. Ossia invece di :

// Definizione Schermate
//              01234567890123456789
#define A00    "***** IrrigOne *****"
#define A01    "*    by WELL 2017  *"
#define A02    "*                  *"
#define A03    "** vs 03.05.2020 ***"
...
... e tutti i punti dove mostri la schermata come qui: ...
  
  if (Stato == 0) // Schermata A1
  {
    lcd.setCursor(0, 0); lcd.print(A10);
    lcd.setCursor(0, 1); lcd.print(A11);
    lcd.setCursor(0, 2); lcd.print(A12);
    lcd.setCursor(0, 3); lcd.print(A13);
...
... eccetera eccetera ...

una cosa del tipo:

...
// Definizione Schermate
const char scr[7][4][21] = {
// 01234567890123456789
{ "***** IrrigOne *****",
  "*    by WELL 2017  *",
  "*                  *",
  "** vs 03.05.2020 ***" },
{ "                    ",
  "   /  /             ",
  "T   ° Umd   %       ",
  "                    " },
...
};
...
void disegnaPagina(int p) {
  for (int r=0; r<4 ; ++r) {
    lcd.setCursor(0, r);
    lcd.print(scr[p][r]);
  }
}
...
  // con una sola istruzione aggiorni la schermata:
  disegnaPagina(Stato);
...

Inoltre un loop() lungo 700 righe non è proprio il massimo né della leggibilità né della modularità, e soprattutto ti si "incrociano gli occhi" quando cerchi di fare debug! Se il loop() fa varie cose, crea una funzione per ogni "blocco" di operazioni e nel loop() metti solo la chiamata a tale funzione!
Ad esempio una cosa del tipo:

...
void loop()
{
  mostraValori();

  aggiornaOrario();

  disegnaPagina(Stato);

  switch ( Stato ) {
    case 0: // Schermata 0 (ex A1)
      scriviOrario();
...
}

void mostraValori() {
  Serial.println (debug);
  Serial.println (Stato);
  Serial.println (Output);
  delay (10000);
}

void aggiornaOrario() {
  DateTime now = RTC.now();
  Giorno = now.dayOfTheWeek();  
}

void scriviOrario() {
    // Orario
    lcd.setCursor(2, 0); if (now.hour() < 10) lcd.print("0");
    lcd.print(now.hour());
    lcd.setCursor(5, 0); if (now.minute() < 10) lcd.print("0");
    lcd.print(now.minute());
    // Lampeggio due punti ":"
    lcd.setCursor(4, 0); if (now.second() % 2 == 0) lcd.print (" "); else lcd.print(":");

    // Giorno della settimana
    lcd.setCursor(8, 0);
    lcd.print(daysOfTheWeek[Giorno]);
}
...

Grazie per tutti i consigli, mi ero accorto anche io che tutti quegli if erano un po' "incasinati" ma quando sono partito erano altri gli obbiettivi, adesso cerco di fare tesoro dei vari appunti ed inizio a correggere qualcosa.
Poi vi aggiorno sui progressi.

Nessuno però mi ha risposto sulla domanda se esistono Pin configurati ma non collegati possono creare valori strani ad altre variabili, è una mia curiosità perché ho riprovato più volte con lo stesso codice, ricaricandolo più volte e il risultato era sempre quel valore strano, poi ricollegato tutto il valore è cambiato magicamente

Scusa, ma non riesco a capire la domanda, e non è solo questione di punteggiatura...
La domanda è questa?

Nessuno però mi ha risposto sulla domanda: se esistono Pin configurati ma non collegati, possono creare valori strani ad altre variabili? È una mia curiosità...

Che cosa intendi per configurati?

Perché dovrebbero "creare valori strani ad altre variabili"? Una variabile prende il valore che le dai, non può prendere valori a caso. È matematica, una scienza esatta! A quali altre variabili ti riferisci?

Scusa, forse mi sono espresso male perché la richiesta era già inserita nel primo post, nel quale dicevo che la variabile Stato dopo il primo loop da 0 assumeva il valore di 13622, questo risultato l'ho ottenuto più volte in più giorni, compilando e ricaricando lo sketch più volte per capire dove fosse il problema.
Senonché dopo aver ricollegato tutti i pin relativi a display, RTc e sensori che avevo scollegato per comodità (visto che la parte hardware è ancora provvisoria) il valore è risultato sempre corretto.
Quindi mi chiedevo se la causa fosse aver lasciato liberi dei pin configurati come Input, Output o SDA SCL
oppure da ricercare da qualche altra parte.

savoriano:
Non ci hai detto che arduino stai usando perché l'interrupt tu lo hai configurato cosi':

  attachInterrupt(0, Read_Data, FALLING);

Interrupt 0 che se è un arduino uno è il pin 2. Nel tuo codice non vedo configurato il pin 2 o allora non ho capito come hai fatto! ::confused:

Iniziamo da qui, avevo provato uno sketch di controllo tastiera e funzionava benissimo così, però effettivamente controllando le specifiche del comando attachinterrupt sconsigliano tale metodo, così ho corretto:

const byte INTERR  = 2;
…..
attachInterrupt(digitalPinToInterrupt(INTERR), Read_Data, FALLING);

poi proverò se migliora qualcosa...

[/quote]

gpb01:
... quanto ti ho detto è indipendente da tutto ed è SEMPRE valido quando si usano gli interrupts, quindi, se vuoi avere una cosa affidabile, è ... obbligatorio :wink:

Guglielmo

Ho sistemato anche questo ed ho pensato di aggiungere anche una sospensione dell'interrupt

detachInterrupt(digitalPinToInterrupt(INTERR));

all'interno del ciclo di controllo del tasto premuto per evitare che una successione troppo rapida mi potrebbe variare il valore del tasto all'interno del ciclo

well66:
ho riprovato più volte con lo stesso codice, ricaricandolo più volte e il risultato era sempre quel valore strano, poi ricollegato tutto il valore è cambiato magicamente

Scusa, ma anche a me era poco chiara la tua domanda (i "pin configurati ma non collegati") e soprattutto non si capisce neanche ora cosa intendi con "ricollegato tutto il valore è cambiato magicamente".

Tra l'altro avevi anche scritto in precedenza cose che sembravano intendere che quel problema tu lo avessi risolto:

adesso però ho ricablato tutto e mi sono accorto con mia sorpresa che adesso il valore è corretto, perche prima avevo scollegato display rtc e sensori.

Se (sembra) risolto ma vuoi comunque capire perché in precedenza ci sia stato quel problema credo che tu debba ricercarlo in cosa tu abbia fatto quando hai "ricablato tutto", come pensi che noi ti si possa rispondere, al di là delle varie cose che ti hanno detto sugli interrupt ad esempio? :wink:

Al di là di questo, nel codice la variabile "Stato" la imposti a 0 od 1 (questo nell'ISR) quindi intanto io lo definirei "bool", non "int". :wink: ma vedrei anche la Output. Nella ISR ReadData() vedo che fai questo:

  Output = 0;
  Output = Output | digitalRead(10);
  Output = Output << 1;
  Output = Output | digitalRead(11);
  Output = Output << 1;
  Output = Output | digitalRead(3);

Di fatto tu stai cercando di "impacchettare" le letture di 3 ingressi ed avere un valore bitmapped ossia sommando 1 per il pin 3, 2 per il pin 11 e 4 per il pin 10. Intanto visto che ci sono le costanti, perché non dai un nome a questi pin così si capisce meglio a cosa servano? Tu hai queste belle costanti, quindi usale:

const byte PIN_A   = 10;   // PIN A tastiera
const byte PIN_B   = 11;   // PIN B tastiera
const byte PIN_C   = 3;   // PIN C tastiera

E tra l'altro nell'ISR puoi anche usare questo:

  Output = digitalRead(PIN_A)*4 + \
    	   digitalRead(PIN_B)*2 + \
           digitalRead(PIN_C);

Comunque sia, con questa codifica avresti 7=ABC, 6=AB, 5=AC, 4=A, 3=BC, 2=B, 1=C, 0= nessuno.
Ma tu nel codice intanto lo inizializzi al valore 8 che non è tra quelli previsti, poi hai una lunghissima (e sinceramente illeggibile) sequenza di if() che confrontano Output con tutti i valori tra 0 e 7 (misteriosamente tranne il 6) per cui la variabile "Output" mi pare gestita malissimo.
Se tu assumi che venga premuto solo un tasto alla volta (visto che non sei un polipo ;)) dovresti considerare solo i valori A=4, B=2, C=1, se invece vuoi prevedere più tasti premuti contemporaneamente ti consiglierei di definire dei simboli appositi per questo o almeno dei commenti e rendere così il codice più leggibile e gestibile.
Ad esempio:

...
#define TASTO_A 4
#define TASTO_B 2
#define TASTO_C 1

...
      //if (Output == 1) Cursore ++;
      if (Output == TASTO_C) Cursore ++;
...
      //if (Output == 2) Stato2 == Cursore + 1 ;
      if (Output == TASTO_B) Stato2 == Cursore + 1 ;
    }
      if (Output == TASTO_A+TASTO_B+TASTO_C) 
      {

...

Sempre se questa è la codifica che intendevi realizzare.

Fermo restando comunque che a me appare inspiegabile quel valore 13622 per Stato, l'unica spiegazione che in genere c'è è nello sforamento dell'indice di qualche array. Faccio un esempio: la variabile "j" a cosa serve? Vedo che viene usata come indice per alcuni array, però dovrebbe avere valori tra 0 e 2 (?), però mentre qui c'è questa verifica:

            if (j == 2)
            {
              Stato3 = 4;
              j = 0;
            }
            else j++;

vedo questa riga che non ha alcun controllo di sforamento:

      if (Output == 2) j++;

Vedi tu...

Inoltre, ciò che fa nella ISR si può fare in 1/10 del tempo con un PIN mascherato!

docdoc:
Se (sembra) risolto ma vuoi comunque capire perché in precedenza ci sia stato quel problema credo che tu debba ricercarlo .......

Si era per capire una cosa che trovavo inspiegabile

docdoc:
Al di là di questo, nel codice la variabile "Stato" la imposti a 0 od 1 (questo nell'ISR) quindi intanto io lo definirei "bool", non "int". :wink: ma vedrei anche la Output. Nella ISR ReadData() .....

si quello era un refuso che avevo già sistemato

docdoc:
Comunque sia, con questa codifica avresti 7=ABC, 6=AB, 5=AC, 4=A, 3=BC, 2=B, 1=C, 0= nessuno.
Ma tu nel codice intanto lo inizializzi .....

No questo sinceramente non l'ho spiegato: ho utilizzato una tastiera con chip MM74C922N e siccome mi servivavo solo 7 tasti (i miei Output)ho utilizzato solo 3 bit, quindi resterebbe una codifica libera non utilizzata

docdoc:
Fermo restando comunque che a me appare inspiegabile quel valore 13622 per Stato, l'unica spiegazione che in genere c'è è .....

Grazie della verifica di j non mi ero accorto, rimedio

>well66: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso. :slight_smile:

Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho troncato io i "quote" del tuo post qui sopra :wink: