Ciao,
ho usato poche volte gli interrupt, prima di fare vorrei capire se è possibile.
Utilizzo arduino nano, 2 sensori hall in ingresso che attiveranno i 2 interrupt (non saranno mai sovrapposti).
La prima cosa che devo fare è vedere il cambio di stato da HI a LOW, quindi FALLING; se possibile poi vorrei anche vedere il successivo cambio da LOW a HI.
Nel setup del programma faccio questo:
No, attachInterrupt permette un solo tipo di attivazione per pin alla volta.
La soluzione è probabilmente usare solo CHANGE e, nell'interrupt, rileggere lo stato. Se leggete HIGH, significa che c'è stata una transizione da LOW a HIGH, se leggete LOW, era la transizione opposta.
Ciao,
ho fatto alcune prove, sostanzialmente il programma funziona, noto però una differenza di tempo sullo stato on dell'uscita impulso, alcune volte è più lungo, alcune più stretto, ecco lo sketch:
#define hall1 2 // pin ingresso sensore hall 1
#define hall2 3 // pin ingresso sensore hall 2
#define bob1 6 // pin uscita bobina 1
#define bob2 7 // pin uscita bobina 2
#define imp 9 // pin uscita impulsi
#define rele 11 // pin uscita relè
volatile byte giri = 0; // var incrementata da impulsi interrupt
volatile unsigned long t_bobine = 0;
volatile unsigned long t_impulso = 0;
bool rele_off = false; // per sapere se staccare il relè
void setup()
{
pinMode(hall1, INPUT); // imposta il pin come ingresso
pinMode(hall2, INPUT);
pinMode(bob1, OUTPUT); // imposta il pin come uscita
pinMode(bob2, OUTPUT);
pinMode(imp, OUTPUT);
pinMode(rele, OUTPUT);
digitalWrite(bob1, HIGH); // a riposo, alto perchè c'è tr
digitalWrite(bob2, HIGH); // a riposo
digitalWrite(imp, LOW); // porto basso l'impulso
digitalWrite(rele, HIGH); // eccito il relè
attachInterrupt(0, sens1, CHANGE); //int pin 2, quando cambia stato
attachInterrupt(1, sens2, CHANGE); //int pin 3, quando cambia stato
}
void loop()
{
if (micros() - t_bobine >= 2200) // se passati 2200 uS
{
digitalWrite(bob1, HIGH); // disattivo bobine
digitalWrite(bob2, HIGH);
}
if (micros() - t_impulso >= 1000) // se passati 1000 uS
{
digitalWrite(imp, LOW); // disattivo impulso per giri
}
if (giri >= 15 && rele_off == false)
{ // se supreo 15 giri motore e se non già fatto
digitalWrite(rele, LOW); // disattivo il relè
rele_off = true; // flag per non rifare
}
}
//**************************************************************************************
//********************** funzione per interrupt da sensore 1 ***************************
void sens1() //Funzione che viene eseguita dall'interrupt
{
if (digitalRead(hall1) == LOW && rele_off == false); // se hall1 basso
{ // e se non ho finito il tempo di avvio
digitalWrite(bob1, LOW); // attivo la bobina
giri++; // incremento variabile giri
t_bobine = micros(); // azzero tempo
}
digitalWrite(imp, HIGH); // impulso per giri
t_impulso = micros(); // azzero tempo
}
//**************************************************************************************
//********************** funzione per interrupt da sensore 2 ***************************
void sens2() //Funzione che viene eseguita dall'interrupt
{
if (digitalRead(hall2) == LOW && rele_off == false); // se hall2 basso
{ // e se non ho finito il tempo di avvio
digitalWrite(bob2, LOW); // attivo la bobina
t_bobine = micros(); // azzero tempo
}
digitalWrite(imp, HIGH); // impulso per giri
t_impulso = micros(); // azzero tempo
}
//**************************************************************************************
millis() non incrementa nella ISR, ma micros() dovrebbe incrementare, cosa che comunque non dovrebbe essere rilevante per come ho fatto il programma, appena rientro nel loop dopo la ISR dovrei iniziare a contare il tempo, come mai quindi non è sempre lo stesso come dovrebbe essere regolato dall'if nel loop?
dopo ore che controllo il programma, non mi ero accorto del punto e virgola… Grazie, è proprio vero che certe cose non si notano nemmeno se sono evidenti
Questi sensori mi lavorano a una frequenza di circa 70 Hz, per entrambi, quindi circa 35 Hz per un solo sensore (lavorano in sequenza). Al massimo però possono arrivare a 250 Hz, sempre per entrambi, quindi 125 Hz per singolo sensore.
Per Salvorhardin, sì, è un comando accensione per motore otto, ma solo ad anticipo fisso, il tempo di 2200 uS è per caricare la bobina
Idealmente bisognerebbe anche avere delle sezioni critiche nel loop in cui si duplicano le variabili volatili usate nelle interruzioni, per evitare accessi concorrenti se un’interruzione avviene mentre si sta elaborando la variabile nel loop.
Se si usassero anche dei bool nei vari if, si eviterebbe di reimpostare continuamente i pin al loro valore predefinito quando il tempo è scaduto
(Da dichiarare anche come volatile e da gestire nella sezione critica)
ho sistemato un po’ il programma, avevo già in mente l’inserimento dei flag per non reimpostare continuamente i pin uscita; però il problema del cambio casuale del tempo di on dell’uscita impulsi resta, ecco il codice aggiornato:
#define hall1 2 // pin ingresso sensore hall 1
#define hall2 3 // pin ingresso sensore hall 2
#define bob1 6 // pin uscita bobina 1
#define bob2 7 // pin uscita bobina 2
#define imp 9 // pin uscita impulsi
#define rele 11 // pin uscita relè
volatile byte giri = 0; // var incrementata da impulsi interrupt
volatile unsigned long t_bobine = 0;
volatile unsigned long t_impulso = 0;
volatile bool rele_off = false; // per sapere se staccare il relè
volatile bool bob_off = false; // per sapere se già fatto
volatile bool imp_off = false; // per sapere se già fatto
void setup()
{
pinMode(hall1, INPUT); // imposta il pin come ingresso
pinMode(hall2, INPUT);
pinMode(bob1, OUTPUT); // imposta il pin come uscita
pinMode(bob2, OUTPUT);
pinMode(imp, OUTPUT);
pinMode(rele, OUTPUT);
digitalWrite(bob1, HIGH); // a riposo, alto perchè c'è tr
digitalWrite(bob2, HIGH); // a riposo
digitalWrite(imp, LOW); // porto basso l'impulso
digitalWrite(rele, HIGH); // eccito il relè
attachInterrupt(0, sens1, CHANGE); //int pin 2, quando cambia stato
attachInterrupt(1, sens2, CHANGE); //int pin 3, quando cambia stato
}
void loop()
{
if (micros() - t_bobine >= 2200 && bob_off == false)
{ // se passati 2200 uS e se non già fatto
digitalWrite(bob1, HIGH); // disattivo bobine
digitalWrite(bob2, HIGH);
bob_off = true; // flag per non rifare
}
if (micros() - t_impulso >= 1000 && imp_off == false)
{ // se passati 1000 uS e se non già fatto
digitalWrite(imp, LOW); // disattivo impulso per giri
imp_off = true; // flag per non rifare
}
if (giri >= 15 && rele_off == false)
{ // se supreo 15 giri motore e se non già fatto
digitalWrite(rele, LOW); // disattivo il relè
rele_off = true; // flag per non rifare
}
}
//**************************************************************************************
//********************** funzione per interrupt da sensore 1 ***************************
void sens1() //Funzione che viene eseguita dall'interrupt
{
if (digitalRead(hall1) == LOW && rele_off == false) // se hall1 basso
{ // e se non ho finito il tempo di avvio
giri++; // incremento variabile giri
bob_off = false; // flag per if nel loop
digitalWrite(bob1, LOW); // attivo la bobina
t_bobine = micros(); // azzero tempo
}
digitalWrite(imp, HIGH); // impulso per giri
imp_off = false; // flag per if nel loop
t_impulso = micros(); // azzero tempo
}
//**************************************************************************************
//********************** funzione per interrupt da sensore 2 ***************************
void sens2() //Funzione che viene eseguita dall'interrupt
{
if (digitalRead(hall2) == LOW && rele_off == false) // se hall2 basso
{ // e se non ho finito il tempo di avvio
bob_off = false; // flag per if nel loop
digitalWrite(bob2, LOW); // attivo la bobina
t_bobine = micros(); // azzero tempo
}
digitalWrite(imp, HIGH); // impulso per giri
imp_off = false; // flag per if nel loop
t_impulso = micros(); // azzero tempo
}
//**************************************************************************************
Il discorso del probabile intervento della ISR mentre nel loop sto lavorando una variabile, dovrebbe essere improbabile per questi tempi, nel caso dovrei disattivare l'interrupt mentre eseguo la parte che interessa le variabili?
Ecco un codice modificato a partire dal vostro. L'ho scritto direttamente qui, quindi non è testato — va verificato che faccia esattamente la stessa cosa.
PS:
Usare un tipo formale invece di un #define è generalmente meglio oggigiorno. Le macro si tengono soprattutto per la compilazione condizionale, se possibile.
Non era necessario prendessi l’impegno di scrivere il codice, ho capito cos’hai voluto fare… Purtroppo però il comportamento è il solito, ora voglio vedere se riesco a capire qualcosa con l’oscilloscopio, se c’è qualche correlazione con i tempi…
Non ho invece capito cosa vuoi dire con l’ultima frase provo a fare una ricerca in rete per capire cosa intendi
Dico “voi” in francese perché è la forma di cortesia, e appartengo a una generazione in cui era naturale farlo. Cerco di scrivere in italiano, ma sto ancora imparando, quindi passo poi le mie frasi in un correttore.
Cercherò di passare a “lei”, non ci vedete alcuna adesione agli anni ’30… (Mi sono informato, non conoscevo questo aspetto).
constexpr è meglio di #define perché è una costante tipizzata, verificata a compilazione, con rispetto della portata, il che migliora sicurezza e debug. È un po’ come la differenza tra “voi” e “lei”, #define è roba dell’ultimo millennio. (Si usava questo in C quando i compilatori non erano così avanzati come oggi.)