Cercasi funzione

salve ragazzi nel mio progetto sto usando un sensore di vibrazione solo che ho un piccolo problema. Una volta che il sensore cambia il suo stato,voglio che se quest'ultimo sia tale per circa 4 secondi, il programma può variare lo stato e quindi procedere alle altre istruzioni. Inoltre se tale periodo è minore di 4 secondi il tutto sia ignorato senza interferire nel conteggio millis.che funzione posso usare?

millis() :smiley: millis() la puoi usare tutte le volte che vuoi, se serve crei una variabile diversa

E usando millis(), nel caso in cui il valore sia meno dei quattro secondi come faccio ad ignorarla senza interferire con la funzione Millis iniziale?

millis() è solo una funzione che ritorna in valore in ms dall'avvio di Arduino, non puoi interferire con questo valore chiamando millis(), fa solo una lettura, non scrive nulla.

Devi fare un programma a stati:

  • Nello stato 0 iniziale testi lo stato del sensore di vibrazione. Quando lo stato cambia, setti una variabile millis() e passi nello stato 1
  • Nello stato 1 testi lo stato del sensore di vibrazione. Quando lo stato cambia, calcoli la variabile millis() per vedere se sono o no trascorsi i 4 secondi. Se non sono trascorsi torni nello stato 0, se sono trascorsi i 4 secondi puoi "procedere alle altre istruzioni" e ritornare nello stato 0.
    Ciao,
    P.

E il conteggio riprende senza interrompere lo stato0? Nel senso, se lo Stato 0 scatta ogni 20 secondi ed è arrivato a 5 e cambia lo Stato del sensore che dura per meno di 4 secondi si riprende lo Stato 0 ma ripartendo ovviamente da 5 secondi?

Certo, se lo programmerai per fargli fare questo, farà questo.

Lo stato 0 è lo stato iniziale e quello in cui il tuo programma testa la variazione del sensore di vibrazione e, se non c'è variazione, svolge le "istruzioni normali". Se c'è la variazione viene settata una variabile col valore corrente di millis() e lo stato passa a 1.
Nello stato 1 testi per prima cosa se sono passati 4 secondi attraverso il confronto fra la variabile impostata nello stato 0 e il valore corrente di millis(). Se non sono passati 4 secondi testi la variazione del sensore di vibrazione. Se il sensore è rimasto invariato continui con le "istruzioni normali" nello stato 1. Se lo stato del sensore è cambiato setti lo stato a 0. Se sono passati 4 secondi procedi alle "altre istruzioni" e ritorni allo stato 0.

Ho ipotizzato che lo stato 0 valga sia per il passaggio diciamo LOW->HIGH del sensore, sia per il passaggio HIGH->LOW. Altrimenti devi prevedere anche uno stato 2.

Tutte le volte che ritorni nello stato 0 la variabile che contiene il valore di millis() perde importanza; verrà riposizionata alla successiva variazione del sensore di vibrazione e servirà per riconteggiare gli eventuali successivi 4 secondi.

Non so se sia importante per te, ma tieni presente che la funzione millis() si azzera, creando un punto di discontinuità, ogni 50 giorni circa.

Ciao,
P.

questo è il programma,ho bisogno di attendere 4 secondi,solo quando lo stato del sensore è HIGH...mi fate capire meglio Sul campo come fare?gentilmente...ovviamente se il sensore è High ma per meno di 4 secondi,non devo intaccare il conteggio del sensore Low...

const byte pinSensore = 9;
const byte pinPiezo = 11;
byte statoPiezo = LOW;

unsigned long previousMillis = 0;
unsigned long intervallo = 1200;

void setup() 
{ delay(1000);
  Serial.begin(9600);
  Serial.println("avvio programma");
  pinMode(pinSensore, INPUT);
  pinMode(pinPiezo, OUTPUT);
  statoPiezo=HIGH;  // per forzare a fare primo cambio di stato
}

void loop() 
{ // verifica piezo e gestione stato
  if(digitalRead(pinSensore)==LOW)
  { if(statoPiezo == HIGH)   // cambio di stato
    { previousMillis=millis();
      statoPiezo=LOW;
      intervallo=18000;
      Serial.println("Stato low");
    }
  } else 
  { if(statoPiezo == LOW)   // cambio di stato 
    { previousMillis=millis();
      statoPiezo=HIGH;
      intervallo=2000;
      Serial.println("Stato high");
    }
  }
  // gestione tempo con millis  
  if (millis() - previousMillis > intervallo) 
  { // scatta tempo 
    if(statoPiezo==LOW)
    { tone(pinPiezo, 1397, 600); //pin,frequenza(fa-re),durata
Delay(600);
      tone(pinPiezo, 1175, 600);
    }    
    else
    { tone(pinPiezo, 1175, 600);
Dalay(600);
      tone(pinPiezo, 1397, 600);
    }
    previousMillis=millis();
  }
}
[code]

Io non ho ben capito come dovrebbe integrarsi il tutto con il codice che hai postato, ma comunque per:

  • attendere che qualcosa vada HIGH
  • controllare che ci resti per 4 secondi
  • se ci resta fare qualcosa
  • attendere che ritorni a LOW

basta uno switch a tre stati come questo:

byte sens = digitalRead(pinSensore);
switch (sensStat)
{
    case 0:  // attende sensore HIGH
        if (sens) 
        {
            sensTime = millis();  // memorizza tempo attuale
            sensStat = 1;         // passa a stato 1
        }
        break;

    case 1:  // conteggio 4 sec, torna a stato zero se sens LOW
        if (!sens)
            sensStat = 0;
        else if (millis() - sensTime >= 4000)  // se timeout 4 secondi
        {
            //...fa qualcosa (una sola volta)...
            sensStat = 3;
        }
        break;

    case 3:  // attende sensore LOW, poi torna a stato zero
        if (!sens) sensStat = 0;
}

Nel codice si usano due variabili esterne sensStat e sensTime definite in questo modo:

byte     sensStat = 0;  // stato processo controllo sensore
uint32_t sensTime;      // variabile tempo  per controllo sensore

Ora mi spiego meglio...si tratta di un piccolo sensore di movimento.. In movimento deve emettere due suoni consecutivi a distanza di 18sec,fermo ogni 2 sec...quando pero è fermo il sensore, voglio che affinche cambi lo stato del programma, questo deve essere fermo per 4 sec(in modo tale da accertarsi della ferma) e poi cambiare stato.. Nel caso è meno di 4 sec ,voglio che il conteggio dei 18 sec non si fermi ma riprenda da dove rimasto...con il tuo esempio si può fare?

millis() o più precisamente BlinkWithoutDelay ne puoi usare anche 100
basta che non hanno i nomi uguali (le variabili)

OK provo a farlo e vi posto il programma

Emanuele1993:
Ora mi spiego meglio...
...si può fare?

Mamma mia, ma è possibile che io non riesca a capire?

Vediamo se riesco a estrapolare qualcosa da quello che hai detto:
A- C'è un sensore di movimento montato su un oggetto che può muoversi
B- Finché l'oggetto si muove emette 2 suoni consecutivi ogni 18 secondi (bip, bip e aspetta 18 secondi)
C- :fearful: Che significa "fermo ogni 2 sec"? Significa che l'oggetto si muove per 2 secondi e poi si ferma?
D- Poi ogni tanto (?) l'oggetto si ferma e poi riprende a muoversi
E- Se l'oggetto si ferma per meno di 4 secondi, il conteggio dei 18 secondi, che si era fermato quando l'oggetto si era fermato, deve riprendere dal valore che aveva quando l'oggetto si era fermato.
F- E se si ferma per più di 4 secondi che deve succedere?
Mi dici dove ho capito male o non ho capito del tutto?

Ci sono alcune ipotesi che mancano:
1- All'inizio del programma, l'oggetto si muove o no?
2- Se l'oggetto non si muove i 18 secondi non partono?
3- Se l'oggetto si ferma per meno di 4 secondi il tempo durante il quale è stato fermo si perde, perché il conteggio riparte dal valore che aveva quando si è fermato?
4- Se l'oggetto si ferma per più di 4 secondi che cosa deve succedere? E da dove riparte il tempo?

Puoi rispondere a queste domande?

Ciao,
P.

Allora mi spiego:
Ho un piezoelettrico ed un sensore di vibrazioni.
L oggetto si muove e il programma emette 2 suoni consecutivi a distanza di 18 sec(bep bep 18 sec, bep bep 18 sec,ecc)
L oggetto si ferma ogni tanto ed emette 2 suoni consecutivi a distanza di 2 sec.
Siccome il cambio di stato è immediato , voglio che quando l oggetto si ferma ,prima che il programma cambi lo stato di movimento in stato di ferma, vengano contati 4 sec.
Se l oggetto rimane fermo per 4 sec ,cambia lo stato (da movimento a fermo)ed emette 2 suoni consecutivi a distanza di 2 sec,se invece durante questi 4sec l oggetto si muove , interrompe questo tempo(anche se non arriva a 4sec) e continui con i 18sec.
Ovviamente è importante che nel momento in cui si contano i 4 sec, i 18 sec vadano avanti parallelamente e vengano stoppati solo ed esclusivamente se avviene il cambio di stato(da movimento a fermo) e quindi se l'oggetto rimane fermo per 4 secondi almeno per poi emettere i suoni ogni 2 secondi.
Appena l oggetto torna a muoversi,deve ritornare immediatamente ad emettere suoni ogni 18 sec (cambiare stato da fermo a movimento) e così via...L oggetto all' avvio si muove..

Ahhhh finalmente PENSO di vedere un po'più chiaro. Allora per quello che ho capito dovrebbe andare così:

SETUP
- oggetto in movimento
- emette bip bip
- carica millis18 per i 18 secondi
- Stato = 0

LOOP
Stato 0 //OGGETTO IN MOVIMENTO
- SE passati 18 secondi ALLORA
   - emette bip bip
   - carica millis18 per i 18 secondi
- SE oggetto si ferma ALLORA
   - emette bip bip
   - carica millis2 per i 2 secondi
   - carica millis4 per i 4 secondi
   - Stato = 1

Stato 1 //OGGETTO APPENA FERMATO
- SE passati 2 secondi ALLORA
   - emette bip bip
   - carica millis2 per i 2 secondi
- SE oggetto si muove ALLORA
   - Stato = 0
- SE passati 4 secondi ALLORA
   - oggetto in stato di fermo
   - Stato = 2

Stato 2 //OGGETTO IN STATO DI FERMO
- SE passati 2 secondi ALLORA
   - emette bip bip
   - carica millis2 per i 2 secondi
- SE oggetto si muove ALLORA
   - oggetto in movimento
   - Stato = 0

Ciao,
P.

I 18 sec,sono contati parallelamente alla 4 sec seguendo le condizioni descritte?io ora provo a scriverlo:)grazieeee

Attenzione! Il listato è stato buttato giù di fretta e per quello che ho capito. Rivedilo anche alla luce delle tue esigenze.

I 18 secondi sono contati parallelamente alla 4 secondi. Se però scadono mentre vengono contati i 4 secondi per il fermo, non si hanno i bip bip. Se devono comunque esserci, DOPO aver implementato lo sketch, prova a inserirli.

Ciao,
P.

P.S. L'unità di misure dei secondi è il 'secondo' = s. Il 'sec' che usi tu è un'abbreviazione comprensibile, ma non prevista; quindi per 18 secondi si deve scrivere 18 s, anziché 18 sec.

pgiagno:
I 18 secondi sono contati parallelamente alla 4 secondi. Se però scadono mentre vengono contati i 4 secondi per il fermo, non si hanno i bip bip. Se devono comunque esserci, DOPO aver implementato lo sketch, prova a inserirli

Appunto, il problema in sè non è complesso, ma ci sono diversi tempi da far quadrare, compresi quelli realizzati con le istruzioni delay(600) che bloccano (anche se per poco) il loop principale. A me ad esempio piacerebbe sentire i suoni non solo allo "scadere naturale" del tempo, ma immediatamente a partire da ogni cambio di stato. Fare tutto con un solo switch diventa pesante, mentre la suddivisione in due "sottoprocessi", uno che legge solo l'input (impostando la variabile statoPiezo HIGH o LOW con i tempi di ritardo voluti), e l'altro che si occupa solo dei suoni (leggendo la variabile statoPiezo) rende tutto più semplice.

Emanuele1993:
Nel caso è meno di 4 sec ,voglio che il conteggio dei 18 sec non si fermi ma riprenda da dove rimasto...con il tuo esempio si può fare?

Non ci sono problemi di tempi "da riprendere" se ogni processo usa una personale variabile di tempo. L'esempio del mio switch si può usare paro paro in modo concreto per impostare la variabile statoPiezo con i tempi voluti (passaggio da HIGH a LOW immediato, passaggio da LOW a HIGH ritardato di 4 secondi dall'ultima lettura HIGH stabile):

#define       pinSensore 9
byte          statoPiezo = LOW;
byte          sensStat = 0;
unsigned long sensTime;
//-----------------------------------------------------------------------------
void setup()
{
    delay(1000);
    Serial.begin(9600);
    Serial.println("avvio programma");
    pinMode(pinSensore, INPUT);
}
//-----------------------------------------------------------------------------
void loop()
{
    gestSens();
}
//-----------------------------------------------------------------------------
void gestSens()
{
    byte sens = digitalRead(pinSensore);
    switch (sensStat)
    {
        case 0:  // attende sensore HIGH
            if (sens)
            {
                sensTime = millis();  // memorizza tempo attuale
                sensStat = 1;         // passa a stato 1
            }
            break;

        case 1:  // conteggio 4 sec, torna a stato zero se sens LOW
            if (!sens)
                sensStat = 0;
            else if (millis() - sensTime >= 4000)  // se timeout 4 secondi
            {
                statoPiezo = HIGH;
                Serial.println("Stato high");
                sensStat = 3;
            }
            break;

        case 3:  // attende sensore LOW, poi torna a stato zero
            if (!sens)
            {
                statoPiezo = LOW;
                Serial.println("Stato low");
                sensStat = 0;
            }
    }
}

Basta aggiungere un altro processo per generare i suoni (comandato da statoPiezo):

#define       pinSensore 9
#define       pinPiezo   11
byte          statoPiezo = LOW;
byte          sensStat = 0;
unsigned long sensTime;
byte          soundStat = 0;
unsigned long soundTime;
//-----------------------------------------------------------------------------
void setup()
{
    delay(1000);
    Serial.begin(9600);
    Serial.println("avvio programma");
    pinMode(pinSensore, INPUT);
    pinMode(pinPiezo, OUTPUT);
}
//-----------------------------------------------------------------------------
void loop()
{
    gestSens();
    gestSound();
}
//-----------------------------------------------------------------------------
void gestSens()
{
    byte sens = digitalRead(pinSensore);
    switch (sensStat)
    {
        case 0:  // attende sensore HIGH
            if (sens)
            {
                sensTime = millis();  // memorizza tempo attuale
                sensStat = 1;         // passa a stato 1
            }
            break;

        case 1:  // conteggio 4 sec, torna a stato zero se sens LOW
            if (!sens)
                sensStat = 0;
            else if (millis() - sensTime >= 4000)  // se timeout 4 secondi
            {
                statoPiezo = HIGH;
                Serial.println("Stato high");
                sensStat = 3;
            }
            break;

        case 3:  // attende sensore LOW, poi torna a stato zero
            if (!sens)
            {
                statoPiezo = LOW;
                Serial.println("Stato low");
                sensStat = 0;
            }
    }
}
//-----------------------------------------------------------------------------
void gestSound()
{
    switch (soundStat)
    {
        case 0:
            if (statoPiezo) { soundStat = 3; break; }
            tone(pinPiezo, 1397, 600);
            soundTime = millis();
            soundStat = 1;
            break;

        case 1:
            if (statoPiezo) { soundStat = 3; break; }
            if (millis() - soundTime >= 600)
            {
                tone(pinPiezo, 1175, 600);
                soundStat = 2;
            }
            break;

        case 2:
            if (statoPiezo) { soundStat = 3; break; }
            if (millis() - soundTime >= 18000) soundStat = 0;
            break;

        case 3:
            if (!statoPiezo) { soundStat = 0; break; }
            tone(pinPiezo, 1175, 600);
            soundTime = millis();
            soundStat = 4;
            break;

        case 4:
            if (!statoPiezo) { soundStat = 0; break; }
            if (millis() - soundTime >= 600)
            {
                tone(pinPiezo, 1397, 600);
                soundStat = 5;
            }
            break;

        case 5:
            if (!statoPiezo) { soundStat = 0; break; }
            if (millis() - soundTime >= 2000) soundStat = 3;
    }
}

gestSound continua a ciclare gli stati 0 1 e 2 se statoPiezo è LOW, e 3 4 e 5 se è HIGH
Ogni stato controlla sempre se statoPiezo è cambiato ed eventualmente transita alla terna opposta, questo permette di emettere i suoni immediatamente al riconoscimento di un cambio stato di statoPiezo.

Scusami il secondo viene indicato con "s":).
Comunque in quest'ultimo modo, non è bloccante niente nel programma... Lo provo e vi faccio sapere... Grazie ragazzi