codice per realizzare sistema antifurto

Ciao a tutti, devo affrontare un lavoro per me difficile, ma per i più esperti una cosa molto semplice.
Vorrei realizzare uno sketch che abbia diversi livelli es:
appena acceso lo strumento, siamo in modalità riposo. Mantengo premuto un pulsante per 3 secondi parte una temporizzazione di tot secondi per arrivare alla modalità "attivato".

Se immetto un codice di 4 caratteri prima del tempo, riporto la centralina in riposo altrimenti, vado in modalità "attivato"

in modalità "attivato", se ricevo una segnalazione da un sensore, vado ad aggiungere+1 ad una variabile X e parte una temporizzazione. A tempo esaurito, se la variabile X è maggiore di di tre, suona l' allarme, se inferiore di 3, ritorno alla modalità "attivo"

Quello che non conosco del C, è la logica di come dovrei gestire queste funzioni, mi spiego meglio:
Potrei usare gli switch case per le modalità?
Come dovrei gestire i blocchi di codice, io conosco gli switch case, es:
se il tempo impostato è arrivato a 10, vai a case switch "attivato" e dentro a quel case switch ci sono le istruzioni per passare al case switch successivo oppure a quello iniziale.
Scusatemi se non ho detto una eresia, non uccidetemi ma vorrei conoscere la struttura del programma che devo realizzare. Ci sono migliaia di esempi, ma ci sono molti modi per realizzare questo e vorrei solo un' aiuto per realizzarlo.
Datemi almeno qualche dritta su come iniziare o come dovrei gestire le funzioni, poi studierò bene tutto il codice.
Grazie comunque :slight_smile:

Ho visto che c'è una strada più semplice:

void loop() {
  // quando premo il pulsante:
  while (digitalRead(buttonPin) == HIGH) {
    PRE ARMATO(); 
  }
 
}

void PRE ARMATO() {
  // istruzione per codice  tempo che arriva a 10
  if TIME ==10;
ARMATO();
}
}

void ARMATO() {
  // istruzione per rilevare intrusione 
  (digitalRead(buttonPin) == HIGH) {
    SCATTATO(); 
  }
}
}

void SCATTATO() {
  // istruzione che fa suonare allrme 
  if (istruzioni per lo sblocco con codice sono vere)
STAND BY();
}
}

Potrebbe andare bene?

edstarink:
in modalità "attivato", se ricevo una segnalazione da un sensore, vado ad aggiungere+1 ad una variabile X e parte una Quello che non conosco del C, è la logica di come dovrei gestire queste funzioni, mi spiego meglio:
Potrei usare gli switch case per le modalità?
Come dovrei gestire i blocchi di codice, io conosco gli switch case, es:
se il tempo impostato è arrivato a 10, vai a case switch "attivato" e dentro a quel case switch ci sono le istruzioni per passare al case switch successivo oppure a quello iniziale.

Non ho capito benissimo. Comunque lo switch() lavoro su numeri e non su stringhe.
Ma la cosa diventa semplice usando enum oppure una serie di costanti e la tua modalità sarà una semplice variabile int.
Esempio:

#define K_ATTIVATO 1
#define K_DISATTIVO 0
#define K_ALTROSTATO 2
...
int modalità=K_DISATTIVO;
...
switch(modalità)
{ case K_ATTIVATO:
   ...  // codice per attivato
   break;
 case K_ALTROSTATO:
   ..
  break;
 case ....
 default:
   Serial.println("NON PREVISTO!!");  // errore di stato
   break;
}

Inizialmente avevo espreoo un mio giudizio sugli switch case, ma non avendo trovato risposta, ho pensato avessi detto una cavolata pazzesca degna di non risposta :slight_smile:
Leggendo ho trovato i cicli while che sono usati anche per questo.
Devo realizzare funzioni, dei blocchi di codiche che funzionano solo se richiamati.

FUNZIONE O stand by
FUNZIONE 1 PRE ARMO
FUNZIONE 2 ARMATO
FUNZIONE 3 ALLARME

Naturalmente solo le funzioni che stanno nel gruppo attivo, devono essere lette, tutti le altre funzioni devono essere "spente"

I case mi sembravano ideali, ma il Break finale non fa chiudere le funzioni al' interno?
Dentro quel case, ci sono cicli e temporizzazioni e da quanto ho letto, i case eseguono quelle funzioni una volta e subito e chiudono il case stesso raggiunto ilbreack, non aspettano che per esempio un sensore abbia attivato un qualcosa o che un tempo raggiunga il valore stabilito.
sbaglio ?

Quel switch non è altro che una serie di if, non è un ciclo

if(modalità==K_ATTIVATO)
{   ...  // codice per attivato
} else if(modalità==K_ALTROSTATO)
{ ...
}
else
{  Serial.println("NON PREVISTO!!");  // errore di stato
}

Quindi si puo fare anche con i cicli di if?

cioè potrei realizzare n if quante sono le funzioni?
Per funzioni io intendo stati del software, come per una lavatrice (Lavaggio, risciacquo, centrifuga)

Quindi, creo una condizione (Tramite If) , che se valida, effettua il codice al suo interno con altri if annidati.

gli altri If non sono chiamati in causa perchè potrei utilizzare una variabile come si usa nei "case switch".

if(funzione==0) // STANDBY
{

//svolgo tutto quello che sta dentro

}

if(funzione==1) // PRE ARMO
{

//eseguo codice che sta dentro

}

if(funzione==2) // ARMATO
{

//eseguo codice che sta dentro

}

Quindi la differenza tra usare Cicli If e usare cicli While?
Si puo fare con tutti e due, ma le differenze dove stanno?

Veramente si puo fare anche con i void

void loop() {
  if (funzione)==1) {
    PRE ARMO();
  }
}

void PRE ARMO() {
//Eseguo codice al' interno
}

Per favore, fatemi chiarezza, ho letto che si può fare in diversi modi, ma quello più indicato?

if NON è un ciclo. Mentre while() è un ciclo come for()

La if fa delle cose solo se è verificato il test. Una volta sola. Poi se è dentro la loop() la if magari viene eseguita tante volte.

Il while fa delle cose quando è verificato il test, ma CONTINUA a fare quelle cose finchè il test è verificato (vero).
Quindi il while è un ciclo.

int x=1;
if(x<5) { Serial.print(x); x=x+1 }

output: 1

int x=1;
while(x<5) { Serial.print(x); x=x+1 }

output: 1 2 3 4 ovvero continua finchè x è minore di 5

Si, lo so che l' if non è un ciclo, ma una condizione :stuck_out_tongue:
Per fortuna, mi stavo incasinando, ho interpretato male uno dei tuoi primi interventi.
Allora come devo procedere per fare questa struttura? vanno bene i cicli while?

vorrei avere piu chiarezza. Faccio un' esempio piu semplice:

La mattina mi alzo dal letto, mi lavo, poi faccio colazione, mi preparo e poi vado al lavoro.

Nella funzione "vado al lavoro", posso aver dimenticato qualcosa e quindi potrei ritornare nella condizione "preparazione", ma sono tutte funzione che solamente una deve essere attiva.

Quello che voglio, è creare delle funzioni e devo richiamarle in qualche modo, per esempio con il valore di una variabile, oppure con la fine di una funzione per passare al' altra.
I while vanno bene? se sono per esempio al lavoro, tutte le altre funzioni al momento non servono, non posso essere al lavoro e contemporaneamente a casa.
Esiste un modo che arduino "salti" quelle istruzioni per leggere solo quelle nella funzione che è stata chiamata?

Scusami, ma non è semplice...

Ho provato a scrivere i due sketch, ma ottengo sempre il solito risultato

int x=1;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

while(x<5) { Serial.print(x); 
x=x+1; }
}

Questo codice, stampa 1234 una volta sola come quello sotto:

int x=1;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

if(x<5) { Serial.print(x); 
x=x+1; }
}

Non vedo la differenza...tutti e due stampano 1234 e basta

Sembrano uguali ma prova a portare fuori dal while e dall'if x=x+1 e vedi cosa succede.

Comunque per rispondere alla tua domanda: non esiste una funzione regina con cui scrivere il codice, un esempio sono proprio i due sketch precedenti. Funzione diverse ma stesso risultato. Siccome sei alle prime armi in programmazione (come me) il consiglio che posso darti è di buttare giù uno sketch con le funzioni che conosci e successivamente lo vai ad affinare.

Chiaro che un programmatore esperto probabilmente individua subito le funzioni più giuste ma non credo ne escluda alcune a prescindere..

edstarink:
Ho provato a scrivere i due sketch, ma ottengo sempre il solito risultato
Non vedo la differenza...tutti e due stampano 1234 e basta

Furorviante, perchè la loop() è già un ciclo (nascosto) while infinito; aggiungi in tutte e due le loop() una Serial.println():

void loop() {
 // put your main code here, to run repeatedly:
 Serial.println("in loop...");
...

edstarink:
vorrei avere piu chiarezza. Faccio un' esempio piu semplice:
La mattina mi alzo dal letto, mi lavo, poi faccio colazione, mi preparo e poi vado al lavoro.
Nella funzione "vado al lavoro", posso aver dimenticato qualcosa e quindi potrei ritornare nella condizione "preparazione", ma sono tutte funzione che solamente una deve essere attiva.
Quello che voglio, è creare delle funzioni e devo richiamarle in qualche modo, per esempio con il valore di una variabile, oppure con la fine di una funzione per passare al' altra.
I while vanno bene? se sono per esempio al lavoro, tutte le altre funzioni al momento non servono, non posso essere al lavoro e contemporaneamente a casa.
Esiste un modo che arduino "salti" quelle istruzioni per leggere solo quelle nella funzione che è stata chiamata?
Scusami, ma non è semplice...

In teoria quello che vuoi fare è una macchina a stati finiti. E basta uno switch() o tante if.
www.lucadentella.it/2013/04/30/macchina-a-stati-finiti-e-arduino/

Non tieni conto di una cosa fondamentale, la loop() è già UN CICLO INFINITO !!
In poche parole dietro alle quinte esiste una main() come per ogni programma in C:
Quello di Arduino è qualcosa del genere (mancano alcune cose):

int main()
{ setup();
 while (1) loop();
}

Ho capito ma in parte.
le strade per fare una cosa sono molte, quello che mi fossilizza sono questi case.
Li ho sempre usati, ma per altri scopi es:
ho un numero casuale o lettura di una dato in ingresso

Come switch metto una variabile che prende il valore dinamico.

switch (valoreDinamico) {
    case 1:
      //accendi il relè 1
      break;
    case 2:
      //accendi il relè 2
      break;

è molto semplice la logica degli switch case, come se avessimo un selettore a tot uscite e una sola entrata. posso mandare in run solamente uno alla volta, ma una volta terminato, deve essere richiamato perchè le funzioni al suo interno non saranno più in esecuzione per via del break.

Voglio provare con il ciclo while o void, ma non mi avete supportato per questa mia scelta quindi, immagino che non sia la strada giusta. Comunque provo, devo batterci di naso :wink:

edstarink:
è molto semplice la logica degli switch case, come se avessimo un selettore a tot uscite e una sola entrata. posso mandare in run solamente uno alla volta, ma una volta terminato, deve essere richiamato perchè le funzioni al suo interno non saranno più in esecuzione per via del break.

Non capisco questo discorso del break. Fa parte della sintassi dello switch, serve, se omesso, ad avere più case con stesso codice, esempio:

switch(valore) {
case 1:
case 2: codiceA(); break;
case 3: codiceB(); break;
...

codiceA() eseguito per case 1 e 2 mentre codiceB() eseguito solo per case 3
Ora NON esiste in Arduino e in queste MCU il concetto di multitasking !! Non puoi avere una funzione in esecuzione e poi un altro pezzo di programma che fa altro. Spero che questo sia chiaro. Se serve una specie ci multitasking te lo devi simulare sfruttando il timer della millis(). Ci sono librerie che fanno queste simulazioni.
Mi pareva però di aver letto nei tuoi post precedenti che dovevi scrivere codice per un qualcosa che ha UN solo stato "attivo" alla volta.
Per una specie di multitasking vedi la libreria LeOS di Leonardo Miliani: http://www.leonardomiliani.com/2012/leos-un-semplice-so-per-arduino/

Ciao, si, conosco il multitasking e la funzione millis che ho usato piu volte in diversi sketch.
Immaginavo mi parlassi del multitasking visto quanto da me descritto :slight_smile:

Quello che voglio dire è questo:

Dentro un "case", non ho mai visto condizioni If ecc, o forse si possono mettere, ma non ho mai visto parti di codice complessi dentro un "case"

Si usano per fare determinate cose come accendere led, stampare da seriale, o cose simili che vengono eseguite solo una volta al richiamo del "Case"

Dovrei rileggermi tutto il post....aspetta, mi sa che dentro alla mie testa piena di gruppi, rileggendo, credo di aver capito.

Hai usato i case switch per richiamare le funzioni?

Se è cosi, ho fatto fatica a capire perchè io solitamente uso il valore di una variabile nel mio sistema
es:

int funzione=1
Attiva gruppo funzione (Codice A)
int funzione=2
Attiva gruppo funzione (Codice B)
Ecc

Tu insistevi con i case switch per dire:
switch 1, vai a codice A
switch 2, vai a codice B
switch 3, vai a codice C
... ecc

Ti prego, dimmi che ho capito :frowning:

Se è cosi, queste funzioni che tu hai chiamato "codice A" per intenderci, sarebbero delle funzioni void?
Questa parte è ancora oscura...

Nell'esempio che ti ho fatto, codiceA() e codiceB() possono essere delle funzioni void oppure molte righe di codice anche complesso, con if, while, etc. Non ci sono restrizioni.
Di solito se il codice è molto lungo si preferisce "accorparlo" in una funzione void, migliorando la leggibilità del switch

Ok, adesso è piu chiaro.
Ora mi sorge un dubbio, se io ho tre funzioni

FUNZIONEA
FUNZIONEB
FUNZIONEC

Se voglio iniziare con la funzione A dovrei anche escludere o ignorare B e C, ma come si fa?
è una cosa che fa arduino, quando selezioni una modalità, esclude tutte le altre?

Ho creato due Funzioni prese dalla rete che ho modificato, ma aiutami a capire (int i) cosa fa di preciso.
i è una variabile...

void STANDBY (int i)
{ 
// blocco funzioni da aggiungere
 }
 
 void PREALLARME (int i)
{ 
// blocco funzioni da aggiungere
 }
  1. Arduino NON fa nulla, se vuoi escludere qualcosa devi usare if() in base ad un test e ad una logica.
    FUNZIONEA();
    if( una qualche condizione) FUNZIONEB(); // eseguita solo se...
    FUNZIONEC();

  2. quello che c'e' tra parentesi dopo il nome della funzione sono parametri.
    Se tu hai
    void STANDBY()
    non passi nessun parametro

Se hai
void STANDBY( int i)
la funzione VUOLE un parametro (un numero) di tipo intero. Questo fa in modo che la funzione faccia qualcosa di diverso a secondo di quel numero. Dipenderà logicamente dal codice dentro la funzione, se poi nella funzione non usi quella i, non serve a un tubo e non ha senso.

Ok, ci sono arrivato :slight_smile:

Ho fatto un' aesempio che, in relazione alla varibile "funzione", scelo lo switch case relativo alla funzione da richiamare. La funzione richiamata farà anche escludere le altre. la funzione stampa il suo nome sulla seriale come debugger, funziona...ma è va bene come strada?

const int  buttonPin = 2;
const int ledPin = 13;
int funzione = 1;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  Serial.begin (9600);


}

void loop() {

  switch (funzione)
  {

    case 1:
      STANDBY();
      break;
    case 2:
      PREALLARME();
      break;

  }
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

void STANDBY()
{
  Serial.print("STANDBY");
}

void PREALLARME()
{
  Serial.print("ALLARME");
}

Si, va bene, ho gia realizzato la prima parte del codice... :smiley: :smiley:
In modalità STANDBY, se mantengo premuto per tot secondi il pulsante, passo alla modalità PRE ALLARME.

Era questo quello che chiedevo :slight_smile:

Vi posto il codice che ho realizzato, tra l' altro ho usato la funzione millis per non bloccare lo sketch anche se non ci sono altre funzioni interessate.

unsigned long contatore;
unsigned long contaimpulsi;
const int  buttonPin = 2;
const int ledPin = 13;
int funzione = 0;
unsigned long time = 0;
int  setModeTime = 2000;
int SOGLIA = 2000;
//ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
//ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
//ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
//ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss



void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  contatore = millis();
  contaimpulsi = 0;
  Serial.begin (9600);


}

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------


void loop() {

  switch (funzione)
  {

    case 0:
      STANDBY();
      break;


    case 1:
      PRE_ARMO();
      break;

    case 2:
      ARMATO();
      break;

    case 3:
      PRE_ALLARME();
      break;

    case 4:
      ALLARME();
      break;

  }
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


//0000000000000000000000000000000


void STANDBY() {
  if (contatore != millis()) {
    contatore = millis();
    if (digitalRead(buttonPin)) {  //se mantengo premuto il pulsante ++ a contaimpulsi
      contaimpulsi++;
    }
    else
    {
      contaimpulsi = 0; // azzero se rilascio
    }
    if (contaimpulsi > SOGLIA) { // se contaimpulsi è maggiore di soglia, vai a PRE ALLARME
      Serial.print("MODALITA PRE ARMO ATTIVATA");
      funzione=1;
      contaimpulsi = 0;
    }
  }
}

//1111111111111111111111111111111



void PRE_ARMO()
{
  Serial.print("PRE_ARMO");
}

//2222222222222222222222222222222


void ARMATO()
{
  Serial.print("ARMATO");
}


//333333333333333333333333333333


void PRE_ALLARME()
{
  Serial.print("PRE_ALLARME");
}

//444444444444444444444444444444

void ALLARME()
{
  Serial.print("ALLARME");
}