Interrupt

Salve a tutti.

Ho un quesito da porre per chi avrà voglia di rispondermi.

Ho costruito con arduino una semplice lampada strobo per verificare la fasatura di un motore da modellismo che fa uso di una accensione CDI. In pratica prendo il segnale dal sensore di hall sul volano e tramite interrupt sul pin 2 faccio accendere una serie di led collegati al pin 13 a mezzo mosfet.

const byte ledPin = 13;
volatile int b=0;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
 // Serial.begin(9600);
}

void loop() {
  
  digitalWrite(ledPin, HIGH);
  //flash = analogRead(sensorPin);
//  flash = map(flash, 0, 1023, 0, 255);
 // Serial.println(flash);
}

void blink() {
  
for ( b = 0; b <= 50; b++) {
digitalWrite(ledPin, LOW);

  }
for ( b = 0; b <= 100; b++) {
  
digitalWrite(ledPin,HIGH);
 
  }

la lampada funziona bene, direi, con un bel flash deciso, ma purtroppo l'interrupt scatta anche per interferenze elettromagnetiche.

La cosa strana è che anche ponticellando il pin 2 ( interrupt) con la terra GND il flash scatta lo stesso.

come è possibile tutto questo?

Saluti
Luca

Non usare assolutamente la resistenza di PULL_UP interna.
Mettine una esterna da 10K.

steve-cr:
Non usare assolutamente la resistenza di PULL_UP interna.
Mettine una esterna da 10K.

Questo che dici vale sempre o solo in questo caso?

steve-cr:
Non usare assolutamente la resistenza di PULL_UP interna.
Mettine una esterna da 10K.

Come mai? Non è la stessa cosa?

anch'io sono curioso del perché.
Ciao Uwe

Ciao uwe

È possibile, secondo te, che dalla scheda entrino dei picchi di tensione che vanno ad interessare l'interrupt anche se il pin è forzato a terra?

...... anche se il pin è forzato a terra?

Ma se hai abilitato il PullUp ?

uwefed:
anch'io sono curioso del perché.
Ciao Uwe

Perché ho fatto delle prove in ambienti "rumorosi" e con le resistenze esterne ho meno problemi.
Il perché non me lo sono nemmeno andato a cercare...

steve-cr:
Perché ho fatto delle prove in ambienti "rumorosi" e con le resistenze esterne ho meno problemi.

... perché, probabilmente, hanno un valore più basso di quelle interne e quindi aumentano l'immunità al rumore.

Da datasheet, il valore delle pull-up interne Rpu va da circa 20KΩ fino anche a 50KΩ ... usare estrenamente un valore più basso sicuramente aiuta.

Guglielmo

rullo:
la lampada funziona bene, direi, con un bel flash deciso, ma purtroppo l'interrupt scatta anche per interferenze elettromagnetiche.
La cosa strana è che anche ponticellando il pin 2 ( interrupt) con la terra GND il flash scatta lo stesso.

Nel listato che hai postato manca qualcosa, penso una graffa, comunque sia anche mettendola non capisco bene cosa vuoi fare.

Tu nella ISR fai due cicli for() nel primo per 51 cicli spegni il led facendo digitalWrite() a LOW , nel secondo per 101 cicli lo metti HIGH.

Prima domanda, ma il led lo controlli con logica invertita? Penso sia così (ma non lo hai specificato..) perché altrimenti ovviamente dopo un primo flash resta sempre acceso. Tant'è che dentro alla loop() hai messo proprio una "digitalWrite(ledPin, HIGH);"... Però se il led è a logica inversa (ma lo è veramente?), a questo punto perché nella setup() non lo hai messo subito HIGH?

Seconda domanda: immagino che tu abbia usato i for() per non usare i delay() (ma anche questo non lo hai detto...), vero?

Terza domanda: vedo che hai fatto "esperimenti" con variabili inutilizzate come "volatile byte state = LOW;" che forse impostavi nella ISR, c'è un motivo per cui hai rinunciato a questa soluzione?

Intendo una cosa tipo (oltre ad altre cosette secondarie, come le #define che le preferisco alle const):

// Definizione pin
#define PIN_FLASH 13
#define PIN_SENSOR 2
// Parametri del sistema
#defile ON_DUR 5
#define OFF_DUR 10
// Flag
volatile bool isBlink = false;

void setup() {
  pinMode(PIN_FLASH, OUTPUT);
  digitalWrite(PIN_FLASH, HIGH);
  
  pinMode(PIN_SENSOR, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_SENSOR), blink, FALLING);
}

void loop() {
  if (isBlink) {
	isBlink = false;
    digitalWrite(PIN_FLASH, LOW);
    delay(FLASH_DUR);
    digitalWrite(PIN_FLASH,HIGH); 
    delay(OFF_DUR);
  }
}

void blink() {
  isBlink = true;
}

Primo, grazie delle risposte.
Secondo sono un cogl***e, perchè ho postato un codice sbagliato, nel senso che in preda ai vari tentativi di far funzionare la lampada a dovere ho invertito gli " HIGH " con i "LOW" e fra l'altro non so nemmeno il perchè....

il circuito funziona con logica diretta ed il codice giusto è il seguente:

const byte ledPin = 13;

const byte interruptPin = 2;


void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);

}

void loop() {
  
  digitalWrite(ledPin, LOW);
 
}

void blink() {
  
for ( b = 0; b <= 50; b++) {
digitalWrite(ledPin, HIGH);

  }
for ( b = 0; b <= 100; b++) {
  
digitalWrite(ledPin,LOW);
 
  }  

  }

ho usato 50 cicli di for per tenere acceso il led per un tempo minimo ed altri 100 come anti rimbalzo .

Il problema è che dalla centralina CDI escono dei disturbi che mi fanno scattare il flash anche se metto a massa il pin 2 ( quello che pilota l'interrupt impostato su " FALLING ").

Come è possibile ciò?

Caro Docdoc

nel codice che tu proponi esegui il flash nel "loop" con l'utilizzo dei delay ma in questo caso, se ho dei rimbalzi o dei disturbi, l'interrupt mi scatta più volte non credi? Ossia il mio codice (per quando veramente banale) mi sembrerebbe più immune perchè dopo il flash devo forzatamente aspettare altri 100 cicli di for a led spento. Sbaglio?

Saluti

Luca

Intanto, nella routine dell'interrupt, mettici il meno possibile in assoluto (nel tuo caso una semplice flag che alzi) ... poi, ALL'ESTERNO della ISR, nel loop, controlli la flag con un semplice if, e se e' ad uno, la rimetti a zero e fai il flash ...

EDIT: buttato giu al volo sul notepad lasciando i tuoi pin, controllalo prima, ma una cosa del genere dovrebbe bastare ... se il flash e' troppo breve, modifica il delayMicroseconds ...

const byte ledPin = 13;
digitalWrite(ledPin, LOW);
const byte interruptPin = 2;
volatile byte flag1 = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
}

void loop()
{
  if(flag1)
  {
    flag1 = 0;
    digitalWrite(ledPin, HIGH);
    delayMicroseconds(200)
    digitalWrite(ledPin, LOW);
  } 
}

void blink()
{
  flag1 = 1;
}

Poi considera che il flash, piu e' breve e meglio e', per cui nell'if puoi semplicemente richiamare una funzione che fa: "accendi led -> aspetta tot microsecondi (si, anche con delay, a quel punto) - >spegni led" e basta, non serve altro ...

Per i disturbi devi vedere tu cosa esce dalla tua centralina, ma se colleghi direttamente il pin a GND, a parte il flash che DEVE fare nel momento in cui lo colleghi (il "falling" della ISR), altri flash non te ne dovrebbe fare a meno che tu non abbia problemi hardware da qualche altra parte ...

Provato a controllare se ci sono impulsi di disturbo sull'alimentazione, con un'oscilloscopio ? ... provato ad usare un debounce hardware "veloce" ? (tipo, R di pull-up da 1K fra pin e VCC, R da 10 ohm fra pin e segnale, C da 10n fra pin e GND, o valori simili) ... inoltre che tipo di segnale ti esce dalla centralina, quanti volt ?

RIEDIT: ... il flash DEVE essere breve per uno stroboscopio, quindi se la luminosita' e' troppo poca, si aumenta la corrente ai led ... quali led esattamente stai usando ? ... perche' secondo il tipo di led, per funzionamento impulsivo possono sopportare anche correnti piu elevate del massimo (se gli impulsi di accensione sono abbastanza brevi), per cui si puo compensare la riduzione della luminosita' anche di parecchio ... ma dipende dal tipo di led ...

Etemenanki:
Intanto, nella routine dell'interrupt, mettici il meno possibile in assoluto (nel tuo caso una semplice flag che alzi) ... poi, ALL'ESTERNO della ISR, nel loop, controlli la flag con un semplice if, e se e' ad uno, la rimetti a zero e fai il flash ...

Ehm, scusa Etem, ma è esattamente quello che avevo infatti già proposto io nel post #9...:wink: Se ci sovrapponiamo così rischiamo di fargli confusione, meglio proseguire un discorso già iniziato.

rullo:
nel codice che tu proponi esegui il flash nel "loop" con l'utilizzo dei delay ma in questo caso, se ho dei rimbalzi o dei disturbi, l'interrupt mi scatta più volte non credi?

Non sbagli, ma (fermo restando che è molto strano che tu riceva "FALLING" anche quando metti a massa il pin...) intanto in genere eventuali rimbalzi si correggono via hardware (R-C) non via software, tanto più se hai necessità di precisione.
Comunque se vuoi evitare gli interrupt durante il flash ti basta disabilitarli:

// Definizione pin
#define PIN_FLASH 13
#define PIN_SENSOR 2
// Parametri del sistema
#defile ON_DUR 5
#define OFF_DUR 10
// Flag
volatile bool isBlink = false;

void setup() {
  pinMode(PIN_FLASH, OUTPUT);
  digitalWrite(PIN_FLASH, HIGH);
  
  pinMode(PIN_SENSOR, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_SENSOR), blink, FALLING);
}

void loop() {
  if (isBlink) {
    // Disattivo temporaneamente gli interrupt per evitare rimbalzi
    noInterrupts();
    // Emetto il flash
    isBlink = false;
    digitalWrite(PIN_FLASH, LOW);
    delay(FLASH_DUR);
    digitalWrite(PIN_FLASH,HIGH); 
    delay(OFF_DUR);
    // Riattivo gli interrupt
    interrupts();
  }
}

void blink() {
  isBlink = true;
}

docdoc: ... emmm ... come pensi di poter far funzionare la delay(), che usa millis(), che usa gli interrupts se ... disabiliti gli interrupts ? ? ? :smiling_imp:

MAI disablitare gli interrupts, varie cose sono ad essi collegate, volendo, la cosa corretta è fare il detach di quell'interrupt e rifare l'attach dopo.

Guglielmo

gpb01:
MAI disablitare gli interrupts, varie cose sono ad essi collegate, volendo, la cosa corretta è fare il detach di quell'interrupt e rifare l'attach dopo.

Si, hai ragione, volevo dire proprio quello poi ho scritto interrupt()/nointerrupt() invece di attachInterrupt()/detachInterrupt().
Il senso comunque è quello, e comunque eventuali rimbalzi li deve gestire via hardware (e capire la stranezza del FALLING anche quando il pin è sempre a massa, cosa che mi fa pensare ad altri disturbi ben più gravi...).

docdoc:
... e capire la stranezza del FALLING anche quando il pin è sempre a massa, cosa che mi fa pensare ad altri disturbi ben più gravi ...

... e più che evidente che entrino disturbi da altre parti, un pin a GND NON potrà mai generare transazioni ed attivare l'interrupt ... magari gli entra porcheria dall'alimentazione o da qualche cavo ::slight_smile:

Guglielmo

docdoc: quello che non ho capito del tuo programma e' perche' usi un delay "off-dur" ... non serve a nulla avere un delay "spento", perche deve comunque rimanere spento per tutto il tempo fra i due impulsi (meno ovviamente la durata del flash), ed il trigger lo prende dal motore ... l'unico delay che ti serve e' quello di "acceso" , che se vuoi puoi anche far cambiare con un potenziometro, ma non e' che serva a molto, deve essere il piu breve possibile per uno stroboscopio (una volta trovato il valore migliore, non lo cambi piu) :wink:

EDIT: la durata dei lampi per gli strobo "industriali" va in genere da 20 a 200 microsecondi, lampade speciali a bassa intensita' xenon per fasature (che possono funzionare fino a 400Hz, contro i 10/15 di quelle "da discoteca" ad alta potenza, arrivano ad emettere impulsi anche di soli 10 microsecondi, ma ovviamente non possono dare la stessa luminosita' ... per un motore direi di partire da 50 microsecondi e vedere se gli vanno bene (sempre sapendo il tipo di led usati)

Salve a tutti

grazie delle risposte.

Per quanto riguarda la parte Hardware ho montato un led da faretto a 12 volts che se alimentato in continua fa luce a tutto il circondario....... diciamo che con 50 colpi di ciclo for blocco un riferimento su un volano a 15000 giri quindi, per adesso, ho già trovato un buon compromesso fra luminosità e rapidità del flash....grazie comunque dei suggerimenti.

La parte rognosa è che di riferimenti ( segni dipinti sul volano) ne compaiono più di uno.... ossia, uno fisso nella posizione di " FALLING " del sensore di hall 3144 e uno ( o più) in altra posizione variabile con il numero di giri.

La cosa buffa è che il tutto succede sia che il pin2 sia collegato al sensore (e alla sua terra ovviamente) sia che il cavetto sia in aria e.....udite udite..... sia che il pin2 sia ponticellato a massa.Ho provato anche ad avvolgere tutto il circuito nella stagnola ma non ho visto variazioni di fatto.

Allora mi domando io.......se il pin 2 è forzato a "low" il mio disturbo deve lavorare a livello di pista di rame sulla basetta provocando una DDP fra ponticello e processore.....possibile?

Adesso, facendo tesoro delle vostre risposte provo a modificare il software e ad introdurre filtri Hardware ma non ho capito bene dove metterli e di che valore, qualcuno può darmi qualche indicazione più precisa?

Saluti
Luca

rullo:
Allora mi domando io.......se il pin 2 è forzato a "low" il mio disturbo deve lavorare a livello di pista di rame sulla basetta provocando una DDP fra ponticello e processore.....possibile?

Il disturbo può benissimo essere un disturbo elettromagnetico o un distubo sull'alimentazione ed entrare da qualsiasi punto ... dalle piste, da un componente, dall'alimentazione, ecc. ecc.

Sono le cose più "bastarde" da individuare e da eliminare ... ::slight_smile:

Guglielmo

Mi viene un dubbio, a questo punto (piu di uno, in effetti :P)

Prima di tutto, come alimenti tutto il sistema ? ... posta un circuito e magari anche una foto chiara di tutti i collegamenti ... che forse si vede qualcosa che dal post non appare ...

Secondo, presumo tu intenda un led di questi o simili ... lo stai usando direttamente, senza il suo circuito di alimentazione a corrente costante, solo con una resistenza in serie, giusto ?

Terzo, se ti compaiono piu segni di marker, e' ovvio che c'e' qualcosa che non va, non importa se "sembra" funzionare bene ... non usare cicli for per fare temporizzazioni, usa millis, oppure in questo caso delayMicroseconds(), dato che ti servono intervalli di accensione minori di un millisecondo ...

Quarto, se come sospetto stai alimentando tutto dalla stessa fonte di alimentazione, hai messo disaccoppiamenti e filtri sull'alimentazione che va al micro ?

EDIT: Guglielmo, ci siamo sovrapposti :smiley: