Difficoltà a capire il problema di questo while

Ciao a tutti

Ho passato 2 giorni di prove prima di decidere a scrivere qui, ho letto guide e post ma senza trovarne la soluzione, il problema è tanto banale che ho finito le armi... oltre ad essere alle prime armi naturalmente.

Se eseguo uno scrip analogo a questo su ArduinoUnoR3 programmandolo dall'IDE offline funziona tutto come mi immagino.
Una volta che lo porto sul coud di arduino e su una MKRWiFi1010 invece si comporta in modo anomalo.

Sicuramente sto sbagliando qualcosa di banale ma fondamentale ma prima di continuare a scervellarmi provo a chiedervi un aiuto visto che sono alle prime armi e ho già perso 2giorni con la funzione scheduler scoprendo poi che era colpa di un bug.

Lo scopo di tutto questo?
Quando attivo il selettore "Manuale" allora "Stato" si deve attivare (true) per 1 minuto e poi spegnersi(false).
Ora il valore di millisecondi nel wile l'ho messo a caso, è una delle tante prove, ma non riesco a farlo funzionare con nessun valore.
In realtà i millis li avrei confrontati con time_now+intervallo . Intervallo avrei settato il 1minuto di attesa.
"Abilitato" serviva ad altro come si vede dal codice, l'ho usato solo per questo esempio per resettare il "var" che ho inserito nel programma solo per visualizzare cosa succedeva alla variabile "time_now"

unnamed

void onAbilitatoChange()  {
  if (abilitato == true) {
    stato = true;
    var = 0; //only for test
  }
  if (abilitato == false) {
    stato = false;
  }
}


void onManualeChange()  {
  if (manuale == true) {
    timer_now = millis();
    var = timer_now; //only for test
    while (millis() < 40000) {
      stato = true;
    }
    stato = false;
    manuale = false;
  }
  if (manuale == false) {
    stato = false;
  }

Grazie a chiunque mi dia un qualche consiglio
Ciao

Quale è il tipo di queste variabili?

(È meglio pubblicare l'intero codice...)

Hai ragione, mi sembra fosse troppo dispersivo, rimedio subito:

/*
  Sketch generated by the Arduino IoT Cloud Thing "Untitled"
  https://create.arduino.cc/cloud/things/3a098327-9bd4-451c-a93e-6c01f50ae8c5

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float humidity;
  float pressure;
  float temperature;
  float vaso1;
  CloudSchedule prog;
  bool abilitato;
  bool manuale;
  bool stato;
  CloudTime time_read;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include <Arduino_MKRENV.h> //rs aggiunta per led integrato

//rs variabili interne
const int intervallo = 5000;     // Tempo in millisecondi accensione manuale
unsigned long timer_now = 0;


void setup() {
  // Initializza serial
  Serial.begin(9600);
  // lasciare il tempo che si connetta
  delay(1500);

  // vedi thingProperties.h
  initProperties();

  // Connetti IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);


  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();


  //ENV
  if (!ENV.begin()) {
    Serial.println("Failed to initialize MKR ENV shield!");
    while (1);
  }

  stato = false; //spegne stato nel caso fosse rimasto acceso
  var = 0; //solo per test

  //definizione del led rgb integrato
  WiFiDrv::pinMode(25, OUTPUT); //define red  pin
  WiFiDrv::pinMode(26, OUTPUT); //define green pin
  WiFiDrv::pinMode(27, OUTPUT); //define blue pin
}

void loop() {
  ArduinoCloud.update();

  if (ArduinoCloud.connected()) {
    time_read = ArduinoCloud.getLocalTime();
  }

  // leggi valori dei sensori
  temperature = ENV.readTemperature();
  humidity    = ENV.readHumidity();
  pressure    = ENV.readPressure();
  //leggi valori pin analogici
  vaso1 = analogRead(A1);

}




void onAbilitatoChange()  {
  if (abilitato == true) {
    stato = true;
    var = 0; //only for test
  }
  if (abilitato == false) {
    stato = false;
  }
}


void onManualeChange()  {
  if (manuale == true) {
    timer_now = millis();
    var = timer_now; //only for test
    while (millis() < 40000) {
      stato = true;
    }
    stato = false;
    manuale = false;
  }
  if (manuale == false) {
    stato = false;
  }


}
void onProgChange()  {
    if (prog.isActive()) {
      stato = true;
    } else {
      stato = false;
    }
    if (ArduinoCloud.connected()) {
      time_read = ArduinoCloud.getLocalTime();
    }
}

void onStatoChange()  {
//niente
}
void onTimeReadChange()  {
//niente
}

Cosa vi aspettate da queste 3 righe di codice?


P.S.: var non è dichiarato nel codice precedente

Che esegua il tratto tra parentesi {} finchè la condizione è vera e il controllo venga fatto prima che venga eseguita.

Errore mio, dovevo riportare anche thingProperties.h

// Code generated by Arduino IoT Cloud, DO NOT EDIT.

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

const char SSID[]     = SECRET_SSID;    // Network SSID (name)
const char PASS[]     = SECRET_OPTIONAL_PASS;    // Network password (use for WPA, or use as key for WEP)

void onProgChange();
void onAbilitatoChange();
void onManualeChange();
void onStatoChange();
void onTimeReadChange();

float humidity;
float pressure;
float temperature;
float vaso1;
int var;
CloudSchedule prog;
bool abilitato;
bool manuale;
bool stato;
CloudTime time_read;

void initProperties(){

  ArduinoCloud.addProperty(humidity, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(pressure, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(temperature, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(vaso1, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(var, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(prog, READWRITE, ON_CHANGE, onProgChange);
  ArduinoCloud.addProperty(abilitato, READWRITE, ON_CHANGE, onAbilitatoChange);
  ArduinoCloud.addProperty(manuale, READWRITE, ON_CHANGE, onManualeChange);
  ArduinoCloud.addProperty(stato, READWRITE, ON_CHANGE, onStatoChange);
  ArduinoCloud.addProperty(time_read, READWRITE, ON_CHANGE, onTimeReadChange);

}

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);

Ero partito da questo che su l'arduino UNO funzionava bene:

stato_pulsante=digitalRead(pulsante);

 if (stato_pulsante==HIGH){
  timer_now=millis();

  do { 
      digitalWrite(LEDR, HIGH);
  } while (millis()<timer_now+intervallo);    
      digitalWrite(LEDR, LOW);

Ma nel cloud non sono riuscito a farlo funzionare,

stato_pulsante=digitalRead(pulsante);

 if (manuale == true){
  timer_now=millis();

  do { 
      stato = true;
  } while (millis()<timer_now+intervallo);    
      stato = false;

cosi ho ripiegato su un while più semplice, ma evidentemente continuo a sbagliare qualcosa...

Non ha senso. Se vedi il codice che tu stesso hai postato come punto di partenza vedi che quando si lavora con millis() si fa sempre verificando una differenza tra valore attuale di millis() e un valore precedente. Millis() < 40000 non ha molto senso. Appena accendi Arduino per un pò millis() è sotto 40000 ma dopo 40 secondi... millis() supera quel valore.

OK, questa è la definizione di un ciclo while :slight_smile: Quello che intendevo era assicurarmi che capisci che non stai testando una durata con

while (millis() < 40000) { stato = true; }

Stai dicendo di aspettare fino a 40 secondi dopo l'avvio di Arduino e di mantenere lo stato a true durante quel periodo (quando una volta sarebbe sufficiente).

Grazie ad entrambi… avete ragione, sono arrivato quella prova dopo infiniti tentativi con:

while (millis()<timer_now+intervallo);

Che immagino abbia più senso ma che comunque non riesco a far funzionare

Dovresti fare qualcosa del genere

•••
unsigned long tempoCambioManuale;
•••

void onManualeChange()  {
  if (manuale) { // l'utente ha attivato la modalità manuale
    tempoCambioManuale = millis();
  }
}

void loop() {
  •••
  if (manuale && (millis() - tempoCambioManuale >= 60000ul)) manuale = false;
  •••
}

Se cambiate manuale a true nel vostro codice e volete anche lo spegnimento automatico dopo 60 secondi, allora ricordatevi di registrare millis() anche in tempoCambioManuale affinché il loop possa tenerne conto.

1 Like

La forma corretta, a prova di overflow, è:
while (millis()-intervallo < timer_now);

1 Like

hum...

while (millis() - timer_now < intervallo) {•••}

1 Like

Grazie a tutti per le risposte, ho fatto varie prove ed il ciclo while quando parte blocca la lettura di tutti i sensori finchè non termina, giustamente, quindi forse meglio usare un if.

Ma evidentemente il mio problema con i millis() è più grave del previsto =) ...

void loop() {
....blablabla....

  if (stato == true) {
    if (millis() - tempo_accensione < tempo_on)
      stato = false;
    manuale = false;
    delay(200);
  }

....
}



void onManualeChange()  {
  if (manuale == true) {
    tempo_accensione = millis();
    delay(200);
    stato = true;
  }

Quando si attiva il selettore "manuale" lo stato deve diventare true per il tempo "tempo_on" e poi tornare false.

La variabile manuale può essere impostata a true in modo diverso rispetto all'interfaccia utente?

Al momento no ma è una prova che posso fare, la collego ad un pin!

Quello che intendo è che se manuale cambia solo attraverso l'interfaccia cloud, l'approccio di attivare il timeout durante la sua modifica e verificare se il tempo è trascorso nel ciclo dovrebbe funzionare.

Ho provato ad inserire una sorta di log e non è molto incoraggiante.
Il programma allo start manda subito il primo messaggio, ma questo ci potrebbe anche stare forse è il funzionamento stesso del tasto "cloud" normalmente spento (false) quando viene letto la prima volta.

tempo_on= 10000;

void loop() {
  ArduinoCloud.update();

  if (stato == true) {
    if (millis() - tempo_accensione < tempo_on)
    stato = false;
    manuale = false;
    var = "è passato il tempo_on quindi stato&manuale=false";
  }
}


void onManualeChange()  {
  if (manuale == true) {
    var = "onManualeChange: manuale true (1)";
    tempo_accensione = millis();
    delay(200);
    stato = true;
    var = "onManualeChange: manuale true (2)";
  }
 if (manuale == false) {
  var = "onManualeChange: manuale false";
  stato = false;
  }
}

immagine

La variabile var viene esportata solo quando si esegue ArduinoCloud.update();.

Ok chiaro, grazie.
Ma perchè l'if non attende i 10 secondi impostati?