Selbstbau eines multi-channel-analyzers (MCA) mit Arduino

Begonnen von stoppi, 12. November 2019, 16:07

⏪ vorheriges - nächstes ⏩

stoppi

Hallo!

Vor einiger Zeit habe ich mich mit dem Bau eines Multichannel-Analyzers zur Erstellung von Gammaspektren beschäftigt. Ich versuchte möglichst einfache Hilfsmittel wie etwa einen Arduino zu verwenden.

Die Messschleife ist einfach:

1.) Eingangsschalter öffnen
2.) Speicherkondensator entleeren
3.) Eingangsschalter schließen
4.) Auf Puls des Monoflops warten
5.) Spannungswert einlesen und Histogramm aktualisieren
6.) Beginne wieder mit 1.)

Damit erziele ich eigentlich sehr brauchbare Ergebnisse (siehe Spektrum mit Cäsium-137)

Der Auslesevorgang ist auch schnell genug. Dies habe ich überprüft, indem ich zum Test nach dem Monofloppuls eine Zeitverzögerung aktivierte und dann erst einen kurzen 5V-Puls ausgegeben habe. Zeichnete ich sowohl die Spannung am Kondensator als auch diesen Ausgabepuls auf, so stellte ich fest, dass bei keiner Verzögerung der Kondensator noch nahezu vollständig geladen war...


#include <U8glib.h>

U8GLIB_ST7920_128X64 u8g(13, 11, 12, U8G_PIN_NONE);

// Einstellungs-Tabelle für die Erhöhung der Taktfrequenz
// ======================================================

//  ADPS2     ADPS1    ADPS0     Division factor
//    0         0        0              2
//    0         0        1              2
//    0         1        0              4
//    0         1        1              8
//    1         0        0             16
//    1         0        1             32
//    1         1        0             64
//    1         1        1            128   (Standard)

#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


// Variablendeklaration
// ====================

const int analogInPin = A0;       // Analog input pin für die Pulshöhe
const int pin_verzoegerung = A1;  // Analog input pin für die über ein Poti einstellbare variable Verzögerung
const int pin_entleeren = 3;      // Digital output pin für das Entleeren des Speicherkondensators
const int pin_treffer = 4;        // Digital input pin für vom Monoflop kommenden treffer
const int pin_switch = 5;         // Digital output pin für switch
const int pin_test = 7;           // Digital output pin um zu überprüfen, in welcher Phase der Entladekurve von C die Spannungsmessung erfolgt
const int pin_reset = 8;          // Digital input pin für das Leeren des Pulshöhenarrays um eine neue Messung zu starten


int U_puls = 0;              // aktuelle gemessene Pulshöhe
float Spannung;              // aktuelle gemessene Pulsspannung
int Index = 0;               // Index der gemessenen Pulshöhe im Intervall [0,127]
float Faktor = 1;            // Vergrößerungs- bzw. Verkleinerungsfaktor
int Pulshoehen[128];         // array mit der Anzahl der jeweils 128 verschiedenen Pulshöhen
int reset_time;              // Zeitdauer in ms der U-Max-Speicherentleerung
int j;                       // Zählvariable als Maß für die Schnelligkeit der Pulsabfrage

int time_alt, time_neu;      // Variablen zur Ermittlung der Schleifendauer
int Verzoegerung;            // Verzögerungszeit in µs


// ===========================
// ========== SETUP ==========
// ===========================

void setup(void)
   {
    Serial.begin(9600);
   
    pinMode(pin_entleeren, OUTPUT);      // U-Speicher-Entleer-pin als output deklariert
    pinMode(pin_switch, OUTPUT);         // switch-pin als output deklariert
    pinMode(pin_test, OUTPUT);           // test-pin als output deklariert
       
    pinMode(pin_treffer, INPUT);         // treffer-pin als input deklariert
    pinMode(pin_reset, INPUT);           // reset-pin für die Anzeige als input deklariert
   
   
    digitalWrite(pin_entleeren, HIGH);   // U_max-Speicher entleeren
    digitalWrite(pin_switch, HIGH);      // Schalter für U-Zuleitung
    digitalWrite(pin_test, LOW);         // Test-pin auf 0 setzen
   
   
    for (int i = 0; i < 128; i++)
       {
        Pulshoehen[i] = 0;           // alle Pulshöhentreffer auf 0 setzen
       }
       
    Faktor = 1;         // Startvergrößerung für die graphische Darstellung
   
    reset_time = 5;     // Zeitdauer in ms der U-Max-Speicherentleerung
   
   
   
    #if FASTADC
   
    // set prescale to 16
   
    sbi(ADCSRA,ADPS2) ;      // ADPS2  auf  1  gesetzt
    cbi(ADCSRA,ADPS1) ;      // ADPS1  auf  0  gesetzt
    cbi(ADCSRA,ADPS0) ;      // ADPS0  auf  0  gesetzt
   
    // cbi = 0; sbi = 1
   
    #endif
   
   
    // Zeichnen der Achsen
    // ===================
   
    u8g.firstPage();
     
    do
       {
        u8g.drawLine(0, 63, 127, 63);
        u8g.drawLine(0, 0, 0, 63);         
       }
    while( u8g.nextPage() );
           
   }
   
   
   

// ===================================
// ========== HAUPTSCHLEIFE ==========
// ===================================

void loop(void)
   {
     /*
     Verzoegerung = analogRead(pin_verzoegerung);
     
     Verzoegerung = Verzoegerung * 10;   // Verzögerungsintervall 0 bis 1023 * 10 µs
     
     Serial.print("Verzoegerung im µs = ");
     Serial.println(Verzoegerung);
     */
           
     digitalWrite(pin_entleeren, HIGH);    // U_max-Speicher gelöscht
     delay(reset_time);                    // reset_time ms Wartezeit zum ausreichenden Löschen des U_max-Speichers
     digitalWrite(pin_entleeren, LOW);     // U_max-Speicher bereit
     
     digitalWrite(pin_switch, HIGH);       // Schalter für U-Zuleitung geschlossen; Messung startet... eigentlich unnötig, da ja eh der Kondensator gelöscht wird und auf den ersten Puls gewartet wird
         
     
     // Warte bis ein vom Monoflop verlängerter Puls über DIGITAL-IN registriert wird!
     // ==============================================================================
         
     while(digitalRead(pin_treffer) == LOW)
        {
        }
     
     
     
     //delayMicroseconds(Verzoegerung);    // übers Poti variable Verzögerung, damit der Zuleitungsschalter nicht schon schließt obwohl der Spannungspuls noch nicht sein Maximum erreicht hat!
     delayMicroseconds(5);                 // fixe Verzögerung, damit der Zuleitungsschalter nicht zu früh schließt und der Spannungspuls auch zu seinem Maximum anwachsen kann!
     
     digitalWrite(pin_switch, LOW);      // Puls wurde registriert --> Schalter für U-Zuleitung offen; Messung gestoppt
         
     
     // Pulshöhe wird eingelesen
     // ========================     
     
     U_puls = analogRead(analogInPin);             // Einlesen der Pulshöhe 0-5V
     
     
     
     // digitale Ausgabe über den Test-Pin unmittelbar nach Einlesen der Spannung um festzustellen, "wo" in der Entladekurve die Spannung gemessen wird. Soll ja genau im Maximum erfolgen!
     // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     /*
     digitalWrite(pin_test, HIGH);      // Test-pin auf 1 setzen
     delay(5);                          // Verzögerung
     digitalWrite(pin_test, LOW);       // Test-pin auf 0 setzen     
     */
     
       
     
     // graphische und Speicher-Verarbeitung der registrierten Pulshöhe
     // ---------------------------------------------------------------
     
     if(U_puls > 130)     // Vermeidung von der Anzeige dominierender peaks mit geringer Amplitude
        {
         Index = map(U_puls, 0, 1023, 0, 127);         // Index der aktuell gemessenen Pulshöhe im Intervall [0,127]
     
         Pulshoehen[Index] = Pulshoehen[Index] + 1;    // aktuelle Pulshöhe erhält einen Treffer

         //Spannung = U_puls * 5.0 / 1023;
         //Serial.print("Pulshoehe = ");                 // serielle Ausgabe der aktuellen Pulshöhe 0-5V
         //Serial.println(Spannung,2);     
        }



     // ==============================================
     // ============ graphische Ausgabe ==============
     // ==============================================
     
     u8g.firstPage();
     
     if (int(Faktor * Pulshoehen[Index]) > 63)    // Zuviele Treffer für die ausreichende y-Darstellung --->  Stauchung um Faktor 2
        {
         Faktor = Faktor / 2;
        }
   
     do
        {
         u8g.drawLine(0, 63, 127, 63);
         u8g.drawLine(0, 0, 0, 63);
       
         for (int i = 0; i < 128; i++)
            {
             u8g.drawLine(0+i, 63, 0+i, 63 - int(Faktor * Pulshoehen[i]));     // zeichnen aller Treffer
            }       
        }
     while( u8g.nextPage() );
     
     
         
     // Abfrage, ob der Reset-Knopf betätigt wurde
     // ------------------------------------------
     
     if (digitalRead(pin_reset) == HIGH)
        {
         // Spektrum an den Computer senden
         // ===============================
         
         for (int i = 0; i < 128; i++)
            {
             Serial.println(Pulshoehen[i]);
            }

       
         // Spektrum löschen
         // ================
         
         for (int i = 0; i < 128; i++)
            {
             Pulshoehen[i] = 0;           // alle Pulshöhentreffer auf 0 setzen
            }
       
         Faktor = 1;         // Startvergrößerung für die graphische Darstellung
        }
     
   
   
   //delay(2);   // optionale Zeitverzögerung
     
   }



Vielleicht mag ja der eine oder andere diesen MCA nachbauen  ;)

Hier das Video: