Go Down

Topic: Far coesistere millis con Arduino Timer Interrupts è possibile? (Read 391 times) previous topic - next topic

ziopippo

Ho provato a sostituire delay con millis senza successo.
Ho anche pubblicato un post con il quale chiedevo dove sbagliavo ma senza trovare soluzione.
Ora il mio dubbio è che millis non funziona bene perchè utilizzo anche questa funzione:
Code: [Select]

// Funzione per il Contatore Kwh
ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 64535;            // preload timer

  //*** POTENZA TOTALE ***
  totPulseStatus = digitalRead(PORT_POWER_TOT);
  if (totLastPulseStatus == HIGH && totPulseStatus == LOW) {
    totPowerPulseCounter++;
    totPulseMillis = millis();
    totPulseTime = totPulseMillis - totLastPulseMillis;
    totPowerValue = (1800000 / totPulseTime);
    totLastPulseMillis = millis();
  }
  if (totPulseStatus != totLastPulseStatus)
    totLastPulseStatus = totPulseStatus;
}

E' possibile che la funzione di cui sopra mi blocchi il conteggio di questa?

[code]
// Funzioni per la tenda
void tenda() //Funziome per l'apertura o la chiusura totale della tenda
{
  while ((millis() - t_tenda) > 1800) // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.
  {
    t_tenda = millis();
    Serial.print("t_tenda ");
    Serial.println(t_tenda);
    Serial.print("millis ");
    Serial.println(millis());
    Serial.print("(millis() - t_tenda)");
    Serial.println((millis() - t_tenda));
   
    digitalWrite(RCHT, LOW);//Abbasso la tenda
  }
  //Operazione necessaria per simulare la pressione del tasto altrimenti la centralina non riceve correttamente il comando
  digitalWrite(RCHT, HIGH);
}

[/code]

brunello22

E perchè dovrebbero disturbarsi...
La funzione Kwh lavora sul Timer1
La millis() sul Timer0

ziopippo

Ciao brunello, ben riletto e ne approfitto anche per augurati un buon anno.


E perchè dovrebbero disturbarsi...
La funzione Kwh lavora sul Timer1
La millis() sul Timer0

Non saprei, non ancora riesco a capire in toto la funzione millis per cui ho pensato di dare la colpa a millis visto che non riuscivo a trovare soluzione al mio problema: https://forum.arduino.cc/index.php?topic=520666.0

Etemenanki

Quello su cui molti (ed all'inizio pure io :D) fanno ancora confusione, e' che delay e' un'istruzione che "ferma" il programma per il tempo indicato, mentre millis e' semplicemente un "contatore", che contiene il numero di millisecondi dal momento in cui lo sketch ha iniziato a girare, ma "di per se" non fa niente altro ... non si puo "usare" millis come se fosse un comando, bisogna usare il suo valore per farci altre cose ... quindi per "sostituire" millis a delay, potrebbe essere necessario riscrivere uno sketch da zero, in alcuni casi ... ad esempio, il tuo:

digitalWrite(RCH2, LOW);
delay(1800); // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.


per farlo con millis, devi prima di tutto dichiarare una variabile byte da usare come flag, inizialmente a zero, ed una unsigned long per i controlli del tempo, poi creare un ciclo di controllo con degli if dove, se la flag ha un certo valore (diverso da zero, che verra' impostato dal resto dello sketch solo quando il rele' dovra' scattare, diciamo uno), attiva il rele' , memorizza il valore che millis ha in quell'istante in una unsigned long, ed imposta la flag ad un diverso valore ancora (diciamo due), e poi se la flag ha il nuovo valore ED INSIEME il tempo che vuoi e' trascorso (e questo lo controlli con millis e la unsigned long, in un'altra if o con un'else successivo), riposiziona il rele' e mette la flag di nuovo a zero ... e tutto questo per ogni diverso delay da sostituire ... per questo molto spesso risulta piu semplice riscrivere l'intero programma da zero strutturandolo in modo differente, piuttosto che cercare di modificarne uno esistente ... ;)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Etemenanki

Quello che intendo dire e' che, se hai una struttura dove spegni un rele', attendi un tot di tempo, e lo riaccendi, come quella che usi tu nello sketch, ad esempio per RCH2 come nelle righe:

Code: [Select]

  if (value_int > Apertura)
  {
    digitalWrite(RCH2, LOW);
    delay(1800);
    digitalWrite(RCH2, HIGH);
  }


per poterla sostituire con dei controlli fatti con millis, va riscritta con una struttura diversa, come, ad esempio, questa (nota bene, io non sono un programmatore, quindi il mio sistema al 99% NON sara' quello piu elegante o piu efficente, e' solo il primo che mi e' venuto in mente da usare come esempio):

Code: [Select]

variabili, setup, ecc

unsigned long temporele2;
byte flag02=0;

Void loop()
{
  ......
  resto dello sketch
  ......
 
  if (value_int > Apertura)      //se devi eseguire le operazioni
  {
  flag02 = 1;        //cambi la flag per dire alla struttura di controllo di farlo
  }
 
  ......
  resto dello sketch
  ......
 
  if (flag02 == 1)       //struttura di controllo
  {
    digitalWrite(RCH2, LOW); 
    temporele2 = millis();    //memorizza istante
    flag02 = 2;      //cambia valore di flag02
  }
  else if ((millis() - temporele2 >= 1800) && (flag02 == 2))
  {
    digitalWrite(RCH2, HIGH);
    flag02 = 0;     //cambia valore flag02
  }
}


... cioe', devi usare una struttura di controllo differente, che risponde a condizioni differenti, per cambiare lo stato del rele' e controllare lo scorrere del tempo (struttura che puoi mettere in qualsiasi punto del loop, tanto non verra' mai eseguita a meno che tu non imposti la flag ad 1), e farla attivare nel momento in cui ti serve cambiando appunto il valore della flag ... se poi il tutto dovra' fare anche altre cose, o in modo diverso, ovviamente anche il resto andra' riscritto con la nuova struttura ... tipo, se lo stesso rele' dovesse fare cicli con tempi diversi, potresti usare un'altra variabile per impostare anche i diversi tempi, da settare subito prima di mettere la flag ad 1 ... a quel punto, e' molto piu semplice riscrivere tutto da zero prevedendo la struttura nuova, piuttosto che cercare di modificare quella vecchia ... ;)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Claudio_FF

Quote from: Etemenanki
se poi il tutto dovra' fare anche altre cose, o in modo diverso, ovviamente anche il resto andra' riscritto con la nuova struttura
Quote from: Etemenanki
e' molto piu semplice riscrivere tutto da zero prevedendo la struttura nuova, piuttosto che cercare di modificare quella vecchia
Quoto e riquoto  ;)

Inutile modificare una sola funzione (trasformandola giustamente in logica a stati non bloccante) se poi tutto il resto funziona ancora con la stessa logica sequenziale monoprocesso bloccante (che non è in grado di far funzionare o usare correttamente la nuova funzione).

La struttura è già stata descritta qui.
L'indentazione errata fa perdere tempo e rende difficile trovare gli errori:
formattare sempre il codice (con CTRL+T sull'IDE, a mano, o in lavatrice) prima di postare sul forum.

ziopippo

Scusate un'attimo. Ma allora come mai nell'esempio Blink without Delay è stato suffciente un ciclo mon millis per eliminare delay?
Inoltre @Claudio_FF se noti il mio ultimo post nel thread da te linkato noterai che ho provato a fare come dici tu però, non ottengo ciò che voglio. ;) :(

nid69ita

E vorrei vedere. BlinkWithoutDelay è molto semplice.
Il tuo codice NON solo è molto più complesso, ma lavora in rete con un client che passa i dati a un browser web,
non un semplice codice che gestisce della elettronica, quindi, ma gestisce anche la parte server. Una struttura moolto più complessa di un semplice codice di gestione sensori o una macchina a stati finiti.  Mettere insieme server/web più macchina a stati NON è semplice. La logica del programma va rivista.
my name is IGOR, not AIGOR

ziopippo

Ok, d'accordo.
Continuo però a non capire. Alla fin fine il dell'auto devo solo solstituirlo per accendere un relè per pochi secondi per simulare la pressione di un tasto.
Ovviamente non capisco come poter affrontare al meglio la cosa ed un aiuto sarà molto gradito. ;)

Etemenanki

... hai provato a considerare l'esempio che ho buttato giu al volo ? ... o comunque un sistema simile ?
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Claudio_FF

Quote from: ziopippo
Alla fin fine il dell'auto devo solo solstituirlo per accendere un relè per pochi secondi
Il blink senza delay mostra solo come usare e come funziona millis, non come scrivere programmi multitasking (usando millis o altro).

Quello che chiedi è far eseguire contemporaneamente dei compiti diversi (intanto che il programma fa altro, il relé viene comandato con i suoi tempi), il che in un modo o nell'altro vuol dire scrivere  un programma multitasking, e quindi una cosa ben più complessa del "devo solo sostituire delay".

Siccome gli esempi/tutorial riportano sempre la normale logica monoprocesso "un'operazione dopo l'altra in sequenza", non credo ci siano esempi non banali su come scrivere in questo modo.

Prima di tutto è fondamentale avere la funzione 'loop' che gira il più velocemente possibile (ad esempio non va bene che 'json' ad ogni ciclo blocchi tutto per qualche secondo per leggere i DHT, meglio leggere il singolo valore solo quando richiesto).

Poi non ci deve essere un while (o un for) dentro cui rimanere magari per diversi secondi in attesa di qualcosa. Fondamentalmente ogni "punto di attesa" della logica attuale deve essere trasformato in uno stato che controlla rapidamente se si è verificato un certo evento, se non c'è nessun evento il programma prosegue.

EDIT: inoltre non si scrive una funzione di oltre 500 righe come 'json' (non conosco l'uso dell'ethernet e volevo studiarne la logica per vedere se era modificabile "a stati"). Diventa un incubo da leggere (appunto, ci ho rinunciato), modificare, correggere. Le parti che svolgono uno specifico compito si spezzano in diverse funzioni più brevi. Lo "zen" della programmazione vorrebbe funzioni non più lunghe di una decina di righe, e contenenti solo un if, o un for o un while, ma ritengo che un'eccessiva scomposizione arriva a produrre di nuovo codice illeggibile, per cui cerco se possibile di scrivere strutture (if/while/for) il cui inizo e la cui fine siano almeno visibili nella stessa schermata, e con meno livelli di indentazione possibili.
L'indentazione errata fa perdere tempo e rende difficile trovare gli errori:
formattare sempre il codice (con CTRL+T sull'IDE, a mano, o in lavatrice) prima di postare sul forum.

ziopippo

Ok. Recepito il messaggio.
Cercherò di ragionare su come poter riorganizzazione il tutto e se non mi riesce vorrà dire che lo lascierò con i delay anche se la cosa mi va a genio. ;)

ziopippo

EDIT: inoltre non si scrive una funzione di oltre 500 righe come 'json' (non conosco l'uso dell'ethernet e volevo studiarne la logica per vedere se era modificabile "a stati"). Diventa un incubo da leggere (appunto, ci ho rinunciato), modificare, correggere. Le parti che svolgono uno specifico compito si spezzano in diverse funzioni più brevi. Lo "zen" della programmazione vorrebbe funzioni non più lunghe di una decina di righe, e contenenti solo un if, o un for o un while, ma ritengo che un'eccessiva scomposizione arriva a produrre di nuovo codice illeggibile, per cui cerco se possibile di scrivere strutture (if/while/for) il cui inizo e la cui fine siano almeno visibili nella stessa schermata, e con meno livelli di indentazione possibili.
Hai perettamente ragione però volevo sottolineare che poi alla fini fine sono due "enormi blocchi" che si ripetono con quasi le medesime istruzioni dove cambiano soltanto le variabili.
Mi spiego meglio: ho fatto il copia/incolla per visulizzare le temperature di ogni stanza e per ogni temperatura ho cambiato solo la descrizione della stanza e la relativa variabile.
Presumo che il tutto potrebbe essere trasformato in una funzione come sto provando a fare con il delay ma a suo tempo non mi venne in mente. ;)
Usare il case potrebbe snellire e velocizare il tutto?
Se qalcuno poi si vuole prendere la briga di instradarmi sulla strada giusta è ben accetto perchè comunque è ancora un progetto iniziale sul quale vorrei implementare tante altre cose che negli anni causa lavoro ho dovuto abbandonare. ;)
GRAZIE A TUTTI per l'aiuto! ;)

ziopippo

... hai provato a considerare l'esempio che ho buttato giu al volo ? ... o comunque un sistema simile ?
Hai ragione scusa, il tuo intervento successivo mi era sfuggito.
Leggendo le risposte da smartphone non l'avevo vista.
La controllo il prima possibile, la testo, e poi ti faccio sapere.
Grazie.

Go Up