Software for the scintillators detectors counters

                     Previous                   Next

 

               The software used to control the scintillator detectors is a two layers system: the firmware inside the Arduino 2560 controls the hardware and reads the data; the user interface in the PC let the user interact with the hardware with a set of commands sent to the microcontroller. It is written in VBA  for Excel, it sends the commands to Arduino and read the results via Strokereader, an activeX module whose reference is given below. I'm using Excel because it is easy to develop this kind of instrument software, it is also very flexible for modifications and access to the results. Moreover, radioactivity measurement is not a fast process ( at least with my samples) so there is few activity on the transfer line and a slow baud rate can even be used.  Strokereader is a low cost program easy to use.

https://strokescribe.com/en/serial-port-download.html

      Details of the Excel commands panel. The different buttons restart the interface, send the commands to the Arduino and start or Stop the measurement. If needed, the data are printed directly into the sheet (see below). The small table on the top of the figure describes the parameters (in black), the parameters values (in blue) and the Arduino response to confirm the reception (in green). The description of the commands is displayed on the figure below.
 

Various commands sent to the Arduino by the Excel program
or the Arduino serial monitor for testing purposes.


Stop_Time: parameter = value: set the time limit for counting, example Stop_Time:3600:
Discri_1: parameter = voltage1: set the reference voltage of discriminator 1, example Discri_1:0.3:
Discri_2: parameter = voltage2: set the reference voltage of discriminator 2, example Discri_2:1:
File_Name: parameter = FileName: set the filename for SD card, example File_Name:  sample1:
Titre: parameter = samplename: set the sample name, example Titre:  pechblende:
SD_Card: parameter = ON: or OFF: use SD card for printout or not
Printer: parameter = ON: or OFF: use Excel or serial monitor for printout or not
Counter: parameter = Plastic: NaI: CdWO4: LYSO: Two Detectors: set the type of detector. Used to format printout.
Start: no parameter
Stop: no parameter
Reset: no parameter

 

          Above is the data table (left part of the Excel sheet) for the radioactivity results. It can easily be copied elsewhere for storage and further calculations.

          I have reproduced below the Strokereader routines for illustration only. See the strokereader web site for reference.

     

Public Function Send_Command_Parameter(Parametre) As Boolean
StrokeReader1.Send Parametre + ":"
If StrokeReader1.Error Then
MsgBox StrokeReader1.ErrorDescription
Send_Command_Parameter = False
Else
Send_Command_Parameter = True
End If
End Function


Public Function Read_Parameter(Temps) As String
Dim Response
Response = ""
Intervalle = 2
Temps = Temps / Intervalle
For i = 1 To Temps
Sleep Intervalle
Response = Response + StrokeReader1.Read(Text)
If Right(Response, 1) = Chr(10) Then
Exit For
End If
Next i
Intervalle = Intervalle * (i - 1)
Range("Read_Time").Value = Intervalle
Response = Replace(Response, Chr(13), "") 'Arduino sends <CR><LF>. Remove <CR> if present
Response = Replace(Response, Chr(10), "")
Read_Parameter = Response
End Function

Public Function Send_Command_Wait_Response(Commande As String, HandShake As Boolean) As String
Dim Response
Response = ""
Intervalle = 2
Send_Command = ""
StrokeReader1.Send Commande
If StrokeReader1.Error Then
MsgBox StrokeReader1.ErrorDescription
Exit Function
End If
For i = 1 To 1000
Sleep Intervalle
Response = Response + StrokeReader1.Read(Text)
If Right(Response, 1) = Chr(10) Then
Exit For
End If
Next i
Intervalle = Intervalle * (i - 1)
Range("Read_Time").Value = Intervalle
Response = Replace(Response, Chr(13), "") 'Arduino sends <CR><LF>. Remove <CR> if present
Response = Replace(Response, Chr(10), "")
Range("Commande").Value = Response
Commande = Replace(Commande, ":", "")
If Response <> Commande Then
MsgBox "Erreur Commande"
Else
Send_Command = Response
End If
If HandShake Then
StrokeReader1.Send "Xoff:" + Chr(13) + Chr(10)
End If
End Function

Private Sub StrokeReader1_CommEvent(ByVal Evt As StrokeReaderLib.Event, ByVal data As Variant)
Dim Reponse As String
Dim Fields, i As Integer, Nb_Fields As Integer
If Counter_Started And Range("Print").Value = "ON" And EVT_DATA Then
Reponse = Read_Parameter(1000)
If Reponse = "Counter_Stopped" Then
StrokeReader1.Connected = False
Range("Status").Value = "Instrument Closed"
Range(Range("Param_Begin"), Range("Param_End")).ClearContents
Counter_Started = False
Exit Sub
End If
Fields = Split(Reponse, ";")
Nb_Fields = UBound(Fields)
If Nb_Fields > 8 Then
Nb_Fields = 8
End If

For i = 1 To Nb_Fields
Range("Buffer").Cells(ICount, i).Value = Fields(i - 1)
If i = 1 Then
Range("Time").Value = Range("Buffer").Cells(ICount, i).Value
End If
Next i
ICount = ICount + 1
Application.ScreenUpdating = True
End If
End Sub

 Example of the LCD display.
       

           Program of the Arduino microcontroller reproduced for illustration only. The loop routine is reading the serial interface to see if a command is ready. When the counter is activated, the program send data to LCD, to SD Card and Excel.

 

 
// Micro SD card interface
#include <SPI.h>
#include <SD.h>

#define SD_CS 53
String FileName = ""; // Chip select for micro SD card
File myFile;

//------------------------------------------------------------------------------------------------------------------

// Display interface
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------

//Dac interface
#include <Adafruit_MCP4725.h>

Adafruit_MCP4725 Discriminator_1;
Adafruit_MCP4725 Discriminator_2;
int Dac_Value;
float Dac_Voltage;
float Discri_1_Max = 4.938;
float Discri_2_Max = 4.896;

//------------------------------------------------------------------------------------------------------------------

int Secondes; // Time in seconds for scaler
boolean Read_Gamma_Detector = false; // test if counter is started
boolean Printer_Status = true;  // Set ON or OFF the printout on serial monitor or Excel program
boolean SD_Card = false; // test if SD card is to be used for printout
String Ligne = ""; // The result line to be printed
int Scaler ; // delay between successive printout
int Scaler_Count = 0; // used to start a printout
String Titre = "Gamma FtLab counter file."; // Sample name
boolean Time_Flag = false; // Flag if stop time parameter is set
int Stop_Time; // counter to test if Stop Time is reached
volatile long interrupt_Counter; // variable incremented by the first interrupt, used by the analog pulses output
long Pulse_Counter; // Store the pulses to be printed after Scaler time
long Pulse_Rate; // interrupt_Counter is loaded into this variable after 60 seconds
volatile long interrupt_Counter_2;  // same three variable for interrupts 2 and 3
long Pulse_Counter_2;
long Pulse_Rate_2;
volatile long interrupt_Counter_3;
long Pulse_Counter_3;
long Pulse_Rate_3;
byte interrupt_Pin = 3; // define the 3 interrupts pins
byte interrupt_Pin_2 = 19;
byte interrupt_Pin_3 = 18;
String Counter_Type = "Plastic"; // counter type to be used, default is plastic
unsigned long milli_Begin; // Start and stop timer variables
unsigned long milli_End;
String Discri1 = ""; //Discriminator voltage for printout
String Discri2 = "";
//------------------------------------------------------------------------------------------------------------------

void software_Reset()
{
  asm volatile ("  jmp 0"); 
}

void setup()
{
   //Arduino Initialize
   Serial.begin(9600);  
   Serial.print("SD card ");
   if (!SD.begin(SD_CS))  //Test the presence of SD card
   {
     Serial.println("initialization failed!");
   }
   else
   {
      Serial.println("initialization OK.");
   }
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);
   Scaler = 5;
   
   lcd.init();                      // initialize the lcd 
   lcd.backlight();
   lcd.noAutoscroll();
   lcd.setCursor(0,0);
   lcd.print("Gamma counter");
   pinMode(interrupt_Pin,INPUT); // Set interrupts pins
   pinMode(interrupt_Pin_2,INPUT);
   pinMode(interrupt_Pin_3,INPUT);
   Discriminator_1.begin(0x60);   // Set reference voltage to the discriminators
   Discriminator_1.setVoltage(0, false);
   Discriminator_2.begin(0x61);
   Discriminator_2.setVoltage(0, false);  
}

// 3 interrupt routines for the output counters
void Pulse_Detected()
{
  interrupt_Counter ++;
}

void Pulse_Detected_2()
{
  interrupt_Counter_2 ++;
}

void Pulse_Detected_3()
{
  interrupt_Counter_3 ++;
}

void loop()
{
  String Command = "";
  boolean wait_read;
  String parameter;
  
  Serial.flush();
  if (Serial.available() > 0)
  {
    Command = Serial.readStringUntil(':');  // Use of colon (:) as a separator to indicate an end of string

    if (Command == "Start")  // Start all counters
    {
        Scaler_Count = 0;
        Secondes = 0;
        Pulse_Rate = 0;
        Pulse_Rate_2 = 0;
        Pulse_Rate_3 = 0;
        interrupt_Counter = 0;
        interrupt_Counter_2 = 0;
        Pulse_Counter = 0;
        Pulse_Counter_2 = 0;
        Pulse_Counter_3 = 0;
                   
        lcd.setCursor(0,0);
        lcd.print("                   ");
        lcd.setCursor(0,0);
        lcd.print("  Time: ");
        lcd.setCursor(0,1);
        lcd.print("                   ");                         
        lcd.setCursor(0,1);
        lcd.print("Discri 1  Discri 2");
        lcd.setCursor(0,2);
        lcd.print("                   ");  
        lcd.setCursor(0,3);
        lcd.print("                   ");  
       if (SD_Card)
      {
         if (FileName == "")
         {
           Serial.println("No file Name!");
           SD_Card = false;         
                         
         }
         else
         {         
           if ( SD.exists(FileName)) 
           {
               Serial.println("File exist!");
               SD_Card = false;
           }
           else
           {
             // open the file. note that only one file can be open at a time,
             // so you have to close this one before opening another.
               myFile = SD.open(FileName, FILE_WRITE);
              if (myFile)
              {
             
                 myFile.print("Sample: "+Titre + "; Stop Time = ");
                 myFile.print(Stop_Time);
                 myFile.println(";Discri1 = " + Discri1 +";Discri2 = "+Discri2);
                 myFile.println("Time(secondes) ;Discrim. Low;Discrim. High;Scaler count"); 
              }  
            }
          }
       }           
       if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
       { 
           attachInterrupt(digitalPinToInterrupt(interrupt_Pin), Pulse_Detected, RISING);
           attachInterrupt(digitalPinToInterrupt(interrupt_Pin_2), Pulse_Detected_2, FALLING);
       }
       if ( Counter_Type == "CdWO4" )
       {           
           attachInterrupt(digitalPinToInterrupt(interrupt_Pin_3), Pulse_Detected_3, FALLING);
       }
       if ( Counter_Type == "Two Detectors")
       { 
          attachInterrupt(digitalPinToInterrupt(interrupt_Pin), Pulse_Detected, RISING);
          attachInterrupt(digitalPinToInterrupt(interrupt_Pin_2), Pulse_Detected_2, FALLING);
          attachInterrupt(digitalPinToInterrupt(interrupt_Pin_3), Pulse_Detected_3, FALLING);
       }
       interrupt_Counter_2 = 0;
       interrupt_Counter = 0;
       interrupt_Counter_3 = 0;
       milli_Begin = millis();          
       Secondes = 0;
       Read_Gamma_Detector = true;
       Serial.println("Counter Started");
       delay(500);
       if ( Printer_Status )
       {
       Serial.print(Titre);
       Serial.println(";");
       delay(500);
                
       if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
                 Serial.println("Time(Seconds);Discrim. Low;Discrim. High;");
                     
      if ( Counter_Type == "CdWO4" )
                  Serial.println("Time(Seconds);Discrim.CdWO4;");
                     
      if ( Counter_Type == "Two Detectors") 
                  Serial.println("Time(Seconds);Discrim. Low;Discrim. High;Discrim.CdWO4;");          
      }
    }  

    if (Command == "Stop")  // Manual stop of all counters
    {
      Read_Gamma_Detector = false;
      // close the file:
      myFile.println("Manual stop");
      myFile.close();
      detachInterrupt(digitalPinToInterrupt(interrupt_Pin));
      detachInterrupt(digitalPinToInterrupt(interrupt_Pin_2));
      detachInterrupt(digitalPinToInterrupt(interrupt_Pin_3));
      Serial.println("File closed. Gamma Counter Stopped.");
      //Serial.println("OK");
    }

    if (Command == "Reset")  // reset microcontroller
    {
      software_Reset();
        
    } 

   if (Command == "Scaler") // set delay time between each printout
    {
      wait_read = true;
      while (wait_read)
     {       
       if (Serial.available() >0)
          {  
             wait_read = false;       
             parameter = Serial.readStringUntil(':'); 
             //Serial.println(parameter);            
             if (parameter.toInt() > 0)
             {
               Scaler = parameter.toInt();
               Serial.print("Scaler = ");  
               Serial.println(Scaler);
             }
             else
             {
               Serial.println("Parameter Error!");
             }
          }
     }       
    }
   
if (Command == "Counter") // Define the counter type used
    {
      wait_read = true;
      while (wait_read)
     {       
       if (Serial.available() >0)
          {  
             wait_read = false;       
             parameter = Serial.readStringUntil(':'); 
             //Serial.println(parameter);            
             if (parameter == "Plastic" || parameter == "NaI" || parameter == "CdWO4" || parameter == "LYSO"|| parameter == "Two Detectors")
             {
               Counter_Type = parameter;
               Serial.print("Detector = ");  
               Serial.println(Counter_Type);
             }
             else
             {
               Serial.println("Parameter Error!");
             }
          }
     }       
    }

    if (Command == "Stop_Time") // Total counting time 
    {
      wait_read = true;
      while (wait_read)
           { 
            if (Serial.available() >0)
            {                      
             parameter = Serial.readStringUntil(':');
             wait_read = false;                                      
             if (parameter.toInt() > 0)
             {
               Stop_Time =  parameter.toInt();
               Time_Flag = true;
               lcd.setCursor(0,0);
               lcd.print("                    ");
               lcd.setCursor(0,0);
               lcd.print("Max Time: ");
               lcd.setCursor(11,0);
               lcd.print(Stop_Time);  
               Serial.print("Stop Time = ");
               Serial.println(Stop_Time);
             }
             else
             {
               Serial.println("Parameter Error!");
             }
           } 
          }   
    }

    if (Command == "Discri_1")  // Set discriminator 1 Voltage
    {
      wait_read = true;
      while (wait_read)
           { 
            if (Serial.available() >0)
            {                      
             parameter = Serial.readStringUntil(':');
             Discri1 = parameter;
             wait_read = false; 
             Dac_Voltage =  parameter.toFloat();                                     
             if ((Dac_Voltage >= 0) && (Dac_Voltage < Discri_1_Max))
             {
               Serial.print("Discri 1 voltage = ");
               Serial.println(Dac_Voltage,3);
               Dac_Voltage = Dac_Voltage / Discri_1_Max * 4095 ;
               Dac_Value = (int) Dac_Voltage;
               Discriminator_1.setVoltage(Dac_Value, false);                          
             }
             else
             {
               Serial.println("Parameter Error!");
             }
           } 
          }   
    }

    if (Command == "Discri_2")  // Set discriminator 2 Voltage
    {
      wait_read = true;
      while (wait_read)
           { 
            if (Serial.available() >0)
            {                      
             parameter = Serial.readStringUntil(':');
             Discri2 = parameter;
             wait_read = false; 
             Dac_Voltage =  parameter.toFloat();                                     
             if ((Dac_Voltage >= 0) && (Dac_Voltage < Discri_2_Max))
             {
               Serial.print("Discri 2 voltage = ");
               Serial.println(Dac_Voltage,3);
               Dac_Voltage = Dac_Voltage / Discri_2_Max * 4095 ;
               Dac_Value = (int) Dac_Voltage;
               Discriminator_2.setVoltage(Dac_Value, false);                          
             }
             else
             {
               Serial.println("Parameter Error!");
             }
           } 
          }   
    }

   if (Command == "File_Name")  // Set filename for SD card
    {
       wait_read = true;
       //Serial.println(Command); 
       while (wait_read)
       {
          if (Serial.available() >0)
          {           
             FileName = Serial.readStringUntil(':');
             FileName = FileName + ".csv";
             wait_read = false;  
             if ( SD.exists(FileName) )
             {
                Serial.println("File exist!");
             }
             else
               Serial.println("File Name " + FileName + " OK");
          }
       }               
    }

   if (Command == "Titre")  // General purpose info, most of the time used for the rock or mineral name.
    {
       wait_read = true;
       //Serial.println(Command); 
       while (wait_read)
       {
          if (Serial.available() >0)
          {           
             Titre = Serial.readStringUntil(':');
             wait_read = false; 
             myFile.println(Titre);
             lcd.setCursor(0,0);
             lcd.print("                    ");
             lcd.setCursor(0,0);
             lcd.print(Titre.substring(0, 19));
             Serial.print("Titre = "); 
             Serial.println(Titre);
          }
       }               
    }

    if (Command == "Printer")  // Set printout ON or OFF
    {
       wait_read = true;
       //Serial.println(Command); 
       while (wait_read)
       {
          if (Serial.available() >0)
          {           
             parameter = Serial.readStringUntil(':');             
             wait_read = false;  
             if ( parameter == "ON" )
             {
                Serial.println("Printer ON");
                Printer_Status = true;
             }
             else
             {
               Serial.println("Printer Off");
               Printer_Status = false;
               //Serial.println("OK");
             }
          }
       }               
    }
  }

  if (Command == "SD_Card")  // Set SD card ON or OFF
    {
       wait_read = true;
       while (wait_read)
       {
          if (Serial.available() >0)
          {           
             parameter = Serial.readStringUntil(':');             
             wait_read = false;  
             if ( parameter == "ON" )
             {
                Serial.println("SD_Card ON");
                SD_Card = true;
             }
             else
             {
               Serial.println("SD_Card Off");
               SD_Card = false;
               //Serial.println("OK");
             }
          }
       }               
    }
  
 // Executed after command "Start" has been sent, read the data from all counters and send results to Excel or SD card.
  if (Read_Gamma_Detector)
  {
    milli_End = millis();  
    if ((milli_End - milli_Begin) >= Scaler * 1000)  // Generate the results after the Scaler time
    {
       // Gestion pulse counter
        milli_Begin = milli_End; 
        Pulse_Rate = interrupt_Counter;
        Pulse_Rate_2 = interrupt_Counter_2;
        Pulse_Rate_3 = interrupt_Counter_3;
        interrupt_Counter =0;
        interrupt_Counter_2 =0;
        interrupt_Counter_3 =0;
        Pulse_Counter = Pulse_Counter + Pulse_Rate;
        Pulse_Counter_2 = Pulse_Counter_2 + Pulse_Rate_2; 
        Pulse_Counter_3 = Pulse_Counter_3 + Pulse_Rate_3; 
        Secondes = Secondes + Scaler;

        // Data sent to small LCD display
        lcd.setCursor(8,0);
        lcd.print("           ");
        lcd.setCursor(8,0);
        lcd.print(Secondes);
       
        lcd.setCursor(0,2);
        lcd.print("        ");
        lcd.setCursor(0,2);
        lcd.print(Pulse_Rate); 

        if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
        {
           lcd.setCursor(10,2);
           lcd.print("        ");
           lcd.setCursor(10,2);
           lcd.print(Pulse_Rate_2);
        }
        if ( Counter_Type == "Two Detectors" || Counter_Type == "CdWO4"  ) 
        {
           lcd.setCursor(10,2);
           lcd.print("        ");
           lcd.setCursor(10,2);
           lcd.print(Pulse_Rate_3); 
        }
         
        lcd.setCursor(0,3);
        lcd.print("        ");
        lcd.setCursor(0,3);
        lcd.print(Pulse_Counter); 

        if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
        {
           lcd.setCursor(10,3);
           lcd.print("        ");
           lcd.setCursor(10,3);
           lcd.print(Pulse_Counter_2);
        }   

         if ( Counter_Type == "Two Detectors" || Counter_Type == "CdWO4"  ) 
        {
           lcd.setCursor(10,3);
           lcd.print("        ");
           lcd.setCursor(10,3);
           lcd.print(Pulse_Counter_3);
        }

        // Print to PC, Excel or Arduino monitor
        if ( Printer_Status )
        {
          Serial.print(Secondes);
          Serial.print(" ; ");
         
          if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
          {
               Serial.print(Pulse_Rate);
               Serial.print(" ; ");
               Serial.print(Pulse_Rate_2);
               Serial.println(" ; ");
          }    
          if ( Counter_Type == "CdWO4"  ) 
          {
               Serial.print(Pulse_Rate_3);
               Serial.println(" ; ");
          }     
          if ( Counter_Type == "Two Detectors"  )     
          {
               Serial.print(Pulse_Rate);
               Serial.print(" ; ");
               Serial.print(Pulse_Rate_2);
               Serial.print(" ; ");
               Serial.print(Pulse_Rate_3);
               Serial.println(" ; ");
          }          
        }              

        // Data sent to SD card if activated            
        if (SD_Card)
        {
           if ( Counter_Type == "Plastic" || Counter_Type == "NaI" || Counter_Type == "LYSO")
                Ligne =  String(Secondes)+ " ; " + String(Pulse_Rate)+ " ; " + String(Pulse_Rate_2);
           if ( Counter_Type == "CdWO4"  )
                Ligne =  String(Secondes)+ " ;  " + String(Pulse_Rate_3);
           if ( Counter_Type == "Two Detectors"  )
                Ligne =  String(Secondes)+ " ; " + String(Pulse_Rate)+ " ; " + String(Pulse_Rate_2) + " ; " + String(Pulse_Rate_3);
        
           if (myFile)
           {
               myFile.println(Ligne);
               myFile.flush(); 
           }          
        }   

         // Stops all counters after "Sop_Time"  
         if (Secondes >=  Stop_Time)
         {
              detachInterrupt(digitalPinToInterrupt(interrupt_Pin));
              detachInterrupt(digitalPinToInterrupt(interrupt_Pin_2));
              detachInterrupt(digitalPinToInterrupt(interrupt_Pin_3));
              Read_Gamma_Detector = false;
              // close the file:
              myFile.close();
              delay(500);
              Serial.println("Counter_Stopped");
              lcd.setCursor(0,0);
              lcd.print("                    ");
              lcd.setCursor(0,0);
              lcd.print("Counter Stopped");
         }
     }                                                      
  }   
}

Previous                   Next