Buona Sera a tutti.
Sto cercando di accendere un led con un pulsante (interrupt). questo led dovrebbe stare acceso per un tempo prestabilito di tempo si deve spegnere.
Uso la funzione millis() per evitare di bloccare il programma poiché Arduino dovrà fare altro nel frattempo.
Quello che succede però è che tutto questo funziona la prima/seconda volta, poi il led rimane sempre acceso.
Questo è il codice:
bool state = true;
unsigned long previousMillis = 0;
const long interval = 5000;
unsigned long currentMillis;
const int led = 8;
void setup()
{
attachInterrupt(0, interruptLed, RISING);
pinMode(led, OUTPUT);
}
void loop()
{
if (state)
{
currentMillis = millis();
//lcd.backlight();
digitalWrite(led, HIGH);
}
if (currentMillis - previousMillis >= interval) {
{
state = !state;
digitalWrite(led, LOW);
}
}
}
void interruptLed() {
state = !state;
previousMillis = millis();
}
Qualcuno può aiutarmi a capire dove ho commesso errori?
bool state = false;
unsigned long previousMillis = 0;
const long interval = 5000;
//unsigned long currentMillis; non serve
const byte led = 8;
void setup() {
attachInterrupt(0, interruptLed, RISING);
pinMode(led, OUTPUT);
}
void loop() {
if (state) {
state = false;
previousMillis = millis();
//lcd.backlight();
digitalWrite(led, HIGH);
}
if (millis() - previousMillis >= interval) {
digitalWrite(led, LOW);
}
}
void interruptLed() {
state = true; // meglio così altrimenti hai problemi di debounce
}
void loop() {
if (state) {
state = false;
previousMillis = millis(); //lcd.backlight();
digitalWrite(led, HIGH);
}
if (millis() - previousMillis >= interval) {
digitalWrite(led, LOW);
}
}
void interruptLed() {
state = true; // meglio così altrimenti hai problemi di debounce
}
Perfetto. Ora funziona tutto a meraviglia.
Standardoil:
Forse, solo forse, devi dichiarare volatile le variabili che usi nella ISR
Siccome non ho ben capito neanche nella reference dell'interrupt di Arduino cosa sia la variabile ISR, seguendo l'intuito ho impostato volatile l'unica variabile che passa per la funzione che richiama l'interrupt:
bool volatile state = false;
In ogni caso ora funziona tutto, come già detto, a meraviglia.
Grazie ad entrambi per il vostro tempo.
Le variabili che in una funzione ISR ( che sarebbe quella funzione che è richiamata quando scatta un Interrupt ) devono essere dichiarate volatile se dette variabili sono usate anche in un'altra parte del programma
Se la variabile è solo nella ISR, non vanno dichiarate volatile
Patrick_M:
scusa brunello22 una domanda... ma se era gia dichiarata global non deve dichiararla volatile o no?
Le variabili usate dentro una ISR ed anche fuori vanno SEMPRE dichiarate "volatile" ...
Variables shared between ISR functions and normal functions should be declared "volatile". This tells the compiler that such variables might change at any time, and thus the compiler must reload the variable whenever you reference it, rather than relying upon a copy it might have in a processor register.
... altrimenti rischi di NON vedere i valori aggiornati.
Una domanda: in linea di principio perché "scomodare" un interrupt per accendere un led? Certamente é soluzione, ma personalmente userei una macchina a stati, o qualcosa del genere, lasciando gli interrupt per incarichi più complessi, dove serva precisione elevata.
Poi, ripeto, gli interrupt sono soluzione al problema, quindi complimenti
brunello22:
Le variabili che in una funzione ISR ( che sarebbe quella funzione che è richiamata quando scatta un Interrupt ) devono essere dichiarate volatile se dette variabili sono usate anche in un'altra parte del programma
Se la variabile è solo nella ISR, non vanno dichiarate volatile
gpb01:
Le variabili usate dentro una ISR ed anche fuori vanno SEMPRE dichiarate "volatile" ...
... altrimenti rischi di NON vedere i valori aggiornati.
Guglielmo
Grazie mille per il chiarimento. Di conseguenze essendo la variabile 'state' quella usata nella ISR, è corretto impostare quella come volatile, almeno così avevo intuito leggendo le reference e trovo conferma nelle vostre risposte
Silente:
Una domanda: in linea di principio perché "scomodare" un interrupt per accendere un led? Certamente é soluzione, ma personalmente userei una macchina a stati, o qualcosa del genere, lasciando gli interrupt per incarichi più complessi, dove serva precisione elevata.
Poi, ripeto, gli interrupt sono soluzione al problema, quindi complimenti
Ho scelto la soluzione degli interrupt per due motivi:
Le conoscenze da studente e autodidatta nel campo Arduino non sono, come si può evincere, sufficienti per poter arrivare alla soluzione della macchina a stati, soluzione che allo stato attuale non saprei neanche come implementare. (cercherò di risolvere la lacuna quanto più presto possibile).
Il programma in realtà sarà parte di un progetto (di un amico che sto aiutando) che prevede l'uso di un pannello lcd 16x2 e della retroilluminazione attivata da pulsante solo quando l'utente vuole leggere i dati su di esso. Per le mie conoscenze l'unica cosa che mi è venuta in mente, per accendere la retroilluminazione del display, è stata quella dell interrupt.
Questo è il codice che questo mio amico dovrà implementare:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2 );
bool volatile sBackLight = true; // il display dev'essere attivo all'avvio
unsigned long previousMillis = 0;
const long interval = 5000;
void setup() {
lcd.begin();
attachInterrupt(0, interruptBackLight, RISING);
}
void loop() {
if (sBackLight) {
sBackLight = false;
previousMillis = millis();
lcd.backlight();
}
if (millis() - previousMillis >= interval) {
lcd.noBacklight();
}
}
void interruptBackLight() {
sBackLight = true; // meglio così altrimenti hai problemi di debounce
}