Stranezza dell'interrupt su Attiny85

Ciao a tutti.

Tempo fa progettai un contatore Geiger, hardware e software, con un ATmega328p, con un LCD e svariati menu. Adesso ne sto realizzando uno molto più piccolo, che deve solo fare tic-tic. Ho impiegato un Attiny85 sia per controllare lo stato dell’elemento ai polimeri di litio all’accensione, con un LED che emette da 1 a 5 lampi secondo lo stato di carica, sia per emettere un brevissimo bip (in pratica un tic) per ogni particella rilevata. Quando viene rilevata, un transistor chiude a massa l’int0 (pin7, I/O2, B2).

Ecco il problema: se metto nella routine di interrupt “particella()”

void particella()
  {
  tone(3,1000,5); // Fa TIC nell'auricolare.
  PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
  delay(10); // Il LED rimane acceso 10mS.
  PORTB&=0b11111110; //  Spegne il LED su I/O0 = PB0
  }

quando il transistor chiude a massa il LED si accende, ma non si spegne più.
Mettendo, invece, nell’interrupt solo l’assegnazione di un valore a una variabile e leggendolo, poi, nel loop, funziona:

/* Per ATTINY85:
1: I/O5 PB5 A0 RS 
2: I/O3 PB3 A3
3: I/O4 PB4 A2          - Uscita per auricolare per Geiger
4: GND
5: I/O0 PB0    MOSI SDA - Uscita per LED provapila/Geiger
6: I/O1 PB1    MISO     
7: I/O2 PB2 A1 SCLK SCL INT0 - Ingresso per sonda Geiger
8: Vcc
*/

#include<avr/sleep.h>
byte state;
volatile byte P;

void particella() {P=1;}
// ISR(INT0_vect){}

void setup()
{
pinMode(0, OUTPUT);
pinMode(2, INPUT);
pinMode(2, INPUT_PULLUP); // Pull-up per il collettore del transistor.
pinMode(4, OUTPUT);

PORTB|=0b00000001;
delay(1000);
PORTB&=0b11111110;
delay(1000);
readVcc();

for(byte n=1; n<=state; n++)
  {
  PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
  delay(50);
  PORTB&=0b11111110; //  Spegne il LED su I/O0 = PB0
  delay(250);
  }

attachInterrupt(0, particella, FALLING);
// GIMSK |= _BV(INT0);
}


void loop()
{
if(P)
  {
  P=0;
  tone(3,1000,5); // Fa TIC nell'auricolare.
  PORTB|=0b00000001; // Accende il LED su I/O0 = PB0
  delay(10); // Il LED rimane acceso 10mS.
  PORTB&=0b11111110; //  Spegne il LED su I/O0 = PB0
  }
}

Qualcuno mi può spiegare perché?
Che cosa succede nell’interrupt? Il delay() fa danni?..

Grazie
Gianluca

When writing an Interrupt Service Routine (ISR):

Keep it short
Don't use delay()
Don't do serial prints
Make variables shared with the main code volatile
Variables shared with main code may need to be protected by "critical sections" (see below)
Don't try to turn interrupts off or on

... puoi leggere di più QUI.

Guglielmo

Grazie, Guglielmo! :slight_smile:

Gianluca

Io il delay lo abolirei per legge...
Cioè, non ha senso, creiamo macchine sempre più veloci per fare calcoli sempre più rapidi e poi... gli diciamo di fermarsi un attimo!
:o

steve-cr:
. gli diciamo di fermarsi un attimo!
:o

per darci il tempo di scappare