Contatore geiger con interrupt

Ho un paio di contatori geiger realizzati con circuiti diversi che permettono di contare gli impulsi prodotti tramite un PC. Adesso sto costruendo un data-logger per poter fare conteggi su tempi lunghi senza tenere il PC collegato.
Sto usando Arduino UNO con il data-logger shield della Adafruit.
Per contare gli impulsi che escono dai circuiti TTL dei contatori geiger uso un Digital input di Arduino "collegato" alla funzione attachInterrupt(...). Il programma è listato qui sotto. Il conteggio non avviene però nello stesso modo per i due geiger, infatti quello dei due che emette un impulso di durata 100 microsec. (misurata con un'oscilloscopio) produce un conteggio sempre superiore alla realtà. Il secondo geiger, con un impulso di durata 1500 microsec. invece produce un conteggio giusto. A questo punto mi sono chiesto se può dipendere dal fatto che l'impulso è troppo breve e crea qualche casino nella gestione dell'interrupt, anche se la frequenza degli impulsi è bassa. Ma il problema potrebbe essere anche altrove. Qualcuno che ha usato gli interrupt potrebbe aiutarmi?

grazie

int pin = 13;
volatile int state = LOW;
int conta=0;
float intervallo=60000;
float time=0;
float time0=0;
float diff=0;

void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);

Serial.begin(9600);
}

void loop()
{
digitalWrite(pin, state);
time=millis();
diff=time-time0;
if(diff > intervallo){
Serial.print(" ");
Serial.println(conta);
conta=0;
time0=millis();
}
}

void blink()
{
if(state == HIGH){
Serial.print("X ");
conta=conta+1;
}
state = !state;
}

Ciao :slight_smile:
Io ne ho costruiti due e vanno bene :slight_smile: il fatto è che non ne ho uno professionale quindi avendo solo questi vanno bene :stuck_out_tongue:
parti da questo codice è già fatto e tutto:
https://sites.google.com/site/diygeigercounter/software
Trovi anche il codice e lo schema del mio tra le prime sezioni....

Passa da queste parti è un pò che sono assente ma presto tornerò con importanti news :):):slight_smile:
http://radioactivity.forumcommunity.net/

Grazie ratto,
faro' un giro su quel forum!

Figurati :slight_smile:
Ce gente molto molto moooolto più preparata di me li :):slight_smile:
Ciao...

togli la Serial.print("X "); dall'interrupt e riprova.

In effetti potrebbe essere la seriale a dare fastidio, provero'.
Grazie

ciao paolometeo
vedo 2 problemi:
Tu triggheri l' interrupt sia sul fianco salente che discendente del segnale per poi controllare nella funzione di interrupt se il segnale é high. È uno preco di tempo.

Meglio
attachInterrupt(0, blink, RISING);
...
void blink()
{
conta++;
}

Il secondo problema é l' elettronica.
Se un impulso é lugo 1,5msec vuol dire che al massimo puó leggere un attivitá radioattiva di ca 600 colpi al secondo (cps) che sono 40000 colpi al minuto (cpm). Non sono tanti. Sopra questa soglia legge molto di meno. Valori normali senza materiale radioattivao sono da 50 a 100 cpm.

Ciao Uwe

Ok, ho provato con raising ma non cambia niente. Se non e' l'impulso troppo corto, allora potrebbero essere impulsi spuri che si presentano subito dopo quello vero. Mi chiedo appunto se i 100 microsec dell'impulso di uno dei due geiger non sia troppo breve per l'interrupt. Anche se in questo caso dovrebbe contarne di meno e non di piu'.

Da che geiger prelevi gli impulsi ?

paolometeo:
Ok, ho provato con raising ma non cambia niente. Se non e' l'impulso troppo corto, allora potrebbero essere impulsi spuri che si presentano subito dopo quello vero. Mi chiedo appunto se i 100 microsec dell'impulso di uno dei due geiger non sia troppo breve per l'interrupt. Anche se in questo caso dovrebbe contarne di meno e non di piu'.

se non hai un oscilloscopio, puoi provare a mettere una pull-down sull'entrata, in modo da evitare l'effetto antenna del cavo... ma di quanti ohm devi ricavartelo dal sensore.

paolometeo:
Ok, ho provato con raising ma non cambia niente. Se non e' l'impulso troppo corto, allora potrebbero essere impulsi spuri che si presentano subito dopo quello vero. Mi chiedo appunto se i 100 microsec dell'impulso di uno dei due geiger non sia troppo breve per l'interrupt. Anche se in questo caso dovrebbe contarne di meno e non di piu'.

No , 100µsec non é troppo breve. Non ho trovato informazioni nel datasheet ma direi che la durata minima del interrupt é nella grandezza di qualche ciclo di clock, percui sotto il µsecondo.
Ciao Uwe

sicuramente con la Serial supera i 100microsec.

il problema di una lettura troppo alta o dipende dalla cattura di segnali "spuri", un'errore di "montaggio" del circuito, o il sensore non è calibrato.

Secondo me la seriale ti rallenta tutto.
Tu scrivi dalla routine di interrupt il carattere "X" sulla seriale, quindi quando ti arriva un segnale il micro dà riscontro di ciò sulla seriale.
Però la scrittura sulla seriale ti porta via del tempo. E se durante la scrittura ti arriva un altro segnale, che succede? Il micro sta già eseguendo la routine blink, questa dovrebbe essere chiamata un'altra volta. Secondo me si incasina proprio qui.

Prova a togliere la stampa seriale dalla blink, lasciando solo l'aggiornamento del contatore.

Ciao,

da cosa viene generato l'impulso del primo contatore che ti da gli errori?
Potrebbe essere un problema di piu' impulsi generati ad esempio da un rele', uno switch reed, ecc (bounce in inglese).

Se e' cosi' puoi mettere nella funzione ISR dell'interrupt un meccanismo di debounce, in pratica se arriva altro impulso al pin nterrupt sotto n millesecondi, allora non avanza il contatore.

Qualcosa del genere

...

// Intervallo di tempo di debounce degli impulsi del contatore
#define DEBOUNCE_TIME 500 // valore in millesondi

volatile unsigned long interrupt_time = 0 ; // interrupt debounce
volatile unsigned long last_interrupt_time = 0 ; // interrupt debounce

// le variabili nelle funzioni di interrupt modificate devono essere "volatile"
volatile unsigned long count_meter ; // variabile conteggio inpulsi ingresso digitale contatore

....

void mio_interrupt_handler()
{

interrupt_time = millis();

// Se l'interrupt arriva piu' velocemente del DEBOUNCE_TIME si presume data da disturbo elettrico da chiusura contatto, viene quindi ignorato.
if (interrupt_time - last_interrupt_time > DEBOUNCE_TIME)
{
count_meter++ ; // incrementa il contatore degli impulsi

last_interrupt_time = interrupt_time;

}

}

Ciao,
Marco.

@Marco Benini
Non era che il millis() non viene aggiornate durante l' interrupt??
Non puoi fare un debounce via software del interrupt, perché ogni impulso richiama di nuovo la funzione di interrupt se non blocchi gli interrupt. Se blocchi l' interrupt puoi perdere degli impulsi.

Ti consiglio di leggerti una spiegazione di come funzione un contatore geiger. Non ha parti meccanici.

@leo72
Avevo capito che aveva seguito i miei consigli e percui tolto la parte di spedizioni seriali.

Ciao Uwe

uwefed:
Non era che il millis() non viene aggiornate durante l' interrupt??

Sì, millis resta ferma all'interno di un interrupt.
Però mi pare che il codice di Marco non controlli l'aggiornamento di millis ma ne legga solo il valore e lo confronti con quello precedentemente memorizzato. Quindi può funzionare.

Non puoi fare un debounce via software del interrupt, perché ogni impulso richiama di nuovo la funzione di interrupt se non blocchi gli interrupt. Se blocchi l' interrupt puoi perdere degli impulsi.

Giusto, non puoi chiamare un interrupt mentre ne stai eseguendo un altro.

Ti consiglio di leggerti una spiegazione di come funzione un contatore geiger. Non ha parti meccanici.

Era il commento che mi aveva fatto un po' pensare, infatti, anche a me:

si presume data da disturbo elettrico da chiusura contatto

@leo72
Avevo capito che aveva seguito i miei consigli e percui tolto la parte di spedizioni seriali.

Sì, però non sappiamo cos'ha fatto perché da ieri non ci fa più sapere nulla :smiley:
Aspettiamo.

uwefed:
@Marco Benini
Non era che il millis() non viene aggiornate durante l' interrupt??
Non puoi fare un debounce via software del interrupt, perché ogni impulso richiama di nuovo la funzione di interrupt se non blocchi gli interrupt. Se blocchi l' interrupt puoi perdere degli impulsi.

Ti consiglio di leggerti una spiegazione di come funzione un contatore geiger. Non ha parti meccanici.

per le parti meccaniche non so, ma per come usa la millis va benissimo, ottiene il tempo di entrata nella interrupt, e non è loccante (è senza delay o accrocchi simili)

Scusatemi tutti se non mi sono fatto sentire, ma sono stato abbastanza impegnato con il lavoro " vero". Ho letto i vostri consigli ma non ho potuto fare prove. Cerco di ricapitolare un po' le cose in modo da proporre un elenco di prove da fare appena posso. Dunque l'impulso da 100 microsec viene prelevato dall'uscita del tubo G.tramite un condensatore, quindi e' possibile che sia sporco e la sua durata non sia costante. Al contrario l'altro circuito geiger produce un impulso pulito tramite un ne555. Giustamente pero' un geiger con impulso troppo lungo, 1.5 ms, rischia di non contare elevati livelli di radioattivita' (speriamo non ce ne sia mai bisogno!!). Quindi una prima prova potrebbe consistere nel far arrivare l'impulso da 100 micro ad un trigger ne555 che me lo pulisca e lo porti ad una lunghezza di 150 - 200 micro prima di mandarlo ad arduino.
Cmq posso fare la prova togliendo la scrittura sulla seriale che se fosse effettivamente quello non servirebbe il lavoro di prima.
Vi terro' informati, intanto grazie.
Paolometeo

è un semplice tubo G.M. oppure una camera a scintillazione ?
a che tensione funziona ?
usa questo :


funziona di certo poi.. ti da un onda quadra quasi perfetta....
Devi usare solo la parte in basso dove ci son le porte logiche...

Ciao,

No , 100µsec non é troppo breve. Non ho trovato informazioni nel datasheet ma direi che la durata minima del interrupt é nella grandezza di qualche ciclo di clock, percui sotto il µsecondo.

Per entrare nella routine di interrupt ci vogliono come minimo 4 cicli di clock (per lo sleep aggiungerne altre quattro), per uscirne almeno altri 4. Si trova nella sezione 6.7.1 Interrupt Response Time della versione del datasheet, almeno di quello che ho io dell'Atmega328.

Ma nella realta', a seconda dei compilatori ci vuole piu' tempo, una ventina di cicli di clock.
Per 16 MHz circa 1.25 us.

Per maggiori informazioni potete vedere questa discussione.

Comunque siamo nell'ordine di qualche us per entrare ed uscire dalla routine ISR, a cui vanno aggiunti quelli del codice che uno scrive, per cui meno codice c'e', meno cicli di clock sono necessari, meglio e'.

Per quanto riguarda il mio codice di debounce funziona bene nella maggior parte dei casi in cui sia prevedibile l'intervallo minimo fra interrupt successivi (o nel caso non si vogliano contari interrupt troppo ravvicinati, come nel caso di reed bounce dei contatori d'acqua, gas, ecc.).

Se invece si vigliono contare impulsi che arrivano in un intervallo di tempo inferione al tempo per entrare ed uscire dall'ISR, allora non va bene.

Segnali spuri elettrici, con i voltaggi in gioco per un tubo geiger, potrebbero esserci comunque.

Dunque l'impulso da 100 microsec viene prelevato dall'uscita del tubo G.tramite un condensatore, quindi e' possibile che sia sporco e la sua durata non sia costante.

Dato che ha l'oscilloscopio, potrebbe vedere cosa succede all'uscita del condensatore.

Ciao,
Marco.