Buongiorno, dovrei far svolgere la seguente funzione:
all'accensione il microcontrollore, legge lo stato di un pin, se è basso non fa nulla.
Se è alto attiva un relè per 2 secondi, poi finché resta alto non fa nulla.
Quando rileva che il pin è basso accende di nuovo il relè per 2 secondi
e cosi via, cioè ad ogni cambiamento di stato eccita il relè per 2 secondi.
Negli esempi ho trovato uno sketch che sembra fare al caso mio, ma vedo che interviene dopo 4 volte che viene premuto il pulsante. Lo dovrei modificare, basta solo mettere 1 al posto del 4?
Grazie.
/*
State change detection (edge detection)
Often, you don't need to know the state of a digital input all the time, but
you just need to know when the input changes from one state to another.
For example, you want to know when a button goes from OFF to ON. This is called
state change detection, or edge detection.
This example shows how to detect when a button or button changes from off to on
and on to off.
The circuit:
- pushbutton attached to pin 2 from +5V
- 10 kilohm resistor attached to pin 2 from ground
- LED attached from pin 13 to ground (or use the built-in LED on most
Arduino boards)
created 27 Sep 2005
modified 30 Aug 2011
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/ButtonStateChange
*/
// this constant won't change:
const int buttonPin = 2; // the pin that the pushbutton is attached to
const int ledPin = 13; // the pin that the LED is attached to
// Variables will change:
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
void setup() {
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the LED as an output:
pinMode(ledPin, OUTPUT);
// initialize serial communication:
Serial.begin(9600);
}
void loop() {
// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);
} else {
// if the current state is LOW then the button went from on to off:
Serial.println("off");
}
// Delay a little bit to avoid bouncing
delay(50);
}
// save the current state as the last state, for next time through the loop
lastButtonState = buttonState;
// turns on the LED every four button pushes by checking the modulo of the
// button push counter. the modulo function gives you the remainder of the
// division of two numbers:
if (buttonPushCounter % 4 == 0) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
Questo codice interviene ogni quattro pressioni (la % è il modulo del valore diviso 4) a te basta verificare se il valore è uguale a 1, dentro l'if lo resetti a zero e fai quel che devi.
Sto provando, all'avvio e senza modificare nulla, il led è acceso, ma voglio spento.
E naturalmente funziona dopo 4 colpi di pulsante.
Poi ho messo a 0 fisso la variabile buttonPushCounter, ma non va più nulla.
Non capisco come possa funzionare, stai usando la ricorsione (una funzione che chiama se stessa) senza alcuna condizione di terminazione, quindi lo stack dovrebbe crashare immediatamente.
Nel video puoi vedere che all'inizio do alimentazione (led rosso) e il verde si accende per 2s perché
il pin in ingresso è già a +5.
Poi vedi tutti gli step, e alla fine riaccendo con il pin a zero e il led non si accende .Ed è così che volevo.
Non metto in dubbio che per qualche oscuro motivo (cioè per caso) funzioni. Il problema non è che sia maccheronico, è che stai usando le chiamate a funzione come se fossero dei GOTO, il che non è solo concettualmente sbagliato, ma manda in crash qualsiasi sistema in pochi istanti. Perché qui non accada è la cosa incomprensibile :o
Il GOTO è un "salto a", mentre una call (chiamata a funzione) occupa spazio sullo stack ad ogni chiamata e lo libera ad ogni ritorno. Se continui a chiamare e basta lo stack SI DEVE riempire corrompendo i dati in memoria.
Strutturando la logica a salti come hai fatto, almeno avresti dovuto usare i veri GOTO e non chiamate a funzione:
Ma la domanda rimane: come è possibile che non vada in crash? Lo specifico micro usato ha uno stack hardware, che anche quando va in overflow non sovrascrive altre parti di memoria?
Non volevo chiedere la pappa bella è pronta, ho cercato di sforzarmi con i miei mezzi, ma visto
che la "pappa" me la fornite va bene così.
Poi ci torno su e vedo come va con i vs suggerimenti.
Comunque per ora funziona.
Non ho preso in considerazione i goto perchè so che sono molto sconsigliati in tale ambiente.
Anch'io come già anticipato ho capito che non è uno sketch fatto in modo ortodosso.
Ho usato un Attiny 85, ciao.
Il GOTO è un "salto a", mentre una call (chiamata a funzione) occupa spazio sullo stack ad ogni chiamata e lo libera ad ogni ritorno. Se continui a chiamare e basta lo stack SI DEVE riempire corrompendo i dati in memoria.
In effetti 2+2 fa 4, però stranamente tanto tempo addietro indagammo assieme a leo72 e astro e altri ma non ricordo più con precisione e ho perso tanti file. Io ricordo che lavorava e nello stack non veniva spinto nulla.
Ora non potendo compilare e disassemblare non possiamo dire altro, fatto sta che se funziona e per lungo tempo nel codice non ci deve essere alcuna istruzione push, se c'è ne almeno una o prima o poi lo stack sconfina e patatrac.
Se nella funzione ci sono molte variabili locali (inclusi argomenti) ci devono essere tanti push che eseguiti ricorsivamente rapidamente riempiono la ram fino a oltre il limite e patatrac, ma non essendoci variabili locali cosa viene spinto nello stack?
Io penso ci debba essere il push per salvare l'indirizzo del punto di ritorno e quindi solo 2 byte.
Esatto, almeno i push degli indirizzi di ritorno (anche se non vengono usati) dovrebbero essere effettuati, e la RAM si riempirebbe in pochi millisecondi corrompendo tutte le variabili presenti (e, forse, i registri SFR?). Sto ipotizzando anche che quel programma (post #7) non usando gli indirizzi di ritorno lavori permanentemente in crash dati. All'accensione funzionerebbe correttamente, ma la rilevazione delle successive aperture/chiusure invece non dovrebbe avvenire, perché almeno le variabili 'button' e 'led' dovrebbero corrompersi. O c'è qualche particolarità dello stack dell'ATTiny85 che non conosco (tipo essere un segmento ridotto dell'intera memoria disponibile usato in modo circolare).