Laser Controller Project

The project consists of using arduino uno used to switch between 4 states of a Pre-Amp based on the number of input pulses received from a laser. A block diagram of my project is shown below:

Laser (Input) ----> Arduino Uno (Controller) ------> Pre-Amp (Output)

I don’t have a laser so i am using a waveform generator to mimic a laser, the waveform settings are :
Type: Pulse, Freq:20Hz (50ms), Amp:3.0 Vpp, Offset:0V, Width = 5ms

I am trying to add the following things to my project to optimize it, however so far i have been unsuccessful:

  1. Initialize all the 4 state machine states into an array so user can define as many states as they want.

  2. ADD a digital de-bounce to the input pin LASER_PIN.

  3. ADD a reset to the system which moves it back to STATE_00 from whatever it is doing.

  4. Wait to receive pulses from Laser before going to the state machine.

my code so far is shown below:

//Objectives: Use input from laser to control pre-amp on adc. Multiplex the inputs on Pre-Amp
//Date:10/21/2019
//Type: Pulse, Freq:20Hz (50ms), Amp:3.0 to 5.0 Vpp, Offset:0V, Width = 5ms 


//Declare Laser Input Pin
#define LASER_PIN 2

//Declare Reset Pin
#define RESET_PIN 3

//Define the states of the machine
#define STATE_00 0
#define STATE_01 1
#define STATE_10 2
#define STATE_11 3

//Bootup State
uint8_t fsm_state = STATE_00;

//Declare variables
int PulseCount = 0;
int LASER_READING = 0;
int Output = 0;//Switch state on the Pre-Amp
int N = 20;//no. of pulses to count before switching states
volatile int IRQcount = 0;
int pin_irq = 0; //External Interrupt0 Request on pin 2
boolean reset = 0;


void setup()
{

  Serial.begin(115200);
  pinMode(LASER_PIN, INPUT);
  pinMode(RESET_PIN, INPUT);
  attachInterrupt(pin_irq, IRQcounter, FALLING);
}


void loop()
{
  delay(5);//wait for laser to startup, replace with better code.
  
    switch(fsm_state)
    {
      
      case STATE_00:
        //Boot Up State
          Serial.println("The state is 00");
          CountPulses();
          Serial.println("");
          Output = 0;
          if(PulseCount == N)
          {
            PulseCount = 0;//Reset Pulse Count
            fsm_state = STATE_01;//switch to next state
            
          }
          break;

          
      case STATE_01:
        //Second State
        Serial.println("The state is 01");
        CountPulses();
        Serial.println("");
        Output = 2;
        if(PulseCount == N)
          {
            PulseCount = 0;//Reset Pulse COunt
            fsm_state = STATE_10;//switch to next state
            
          }
          break;


        case STATE_10:
        //Third State
        Serial.println("The state is 10");
        CountPulses();
        Serial.println("");
        Output = 3;
        if(PulseCount == N)
          {
            PulseCount = 0;//Reset Pulse COunt
            fsm_state = STATE_11;//switch to next state
            
          }
          break;

        case STATE_11:
        //Fourth State
        Serial.println("The state is 11");
        CountPulses();
        Serial.println("");
        Output = 4;
        if(PulseCount == N)
          {
            PulseCount = 0;//Reset Pulse COunt
            fsm_state = STATE_00;//switch to next state
            
          }
          break; 

         default:
            fsm_state = STATE_00;
         break;
    }
  
  
 
}

void IRQcounter() 
{
  IRQcount++;
}

void CountPulses()
{
  IRQcount = 0;
  
  sei();//enable interrupts
  delay(1000);//20 Pulses per 1000 ms 
  
  PulseCount = IRQcount;//Count Interrupts fired due to Falling Edge
  
  Serial.print(F("Pulse Count is = "));
  Serial.println(PulseCount);
  
  cli();//disable interrupts
}

The results from the serial monitor are shown in the image Results.PNG . The program works but i am unable to add the stuff above without changing the functionality of the code. Any help or suggestions would be greatly appreciated.

ADD a reset to the system which moves it back to STATE_00 from whatever it is doing.

That is going to be impossible while you have a 1 second delay() in the CountPulses() function. Use a non-blocking millis() timer for that so that the code can be responsive.

Non-blocking timing tutorials: Several things at a time. Beginner's guide to millis(). Blink without delay().

1) Define the states in an enum, the related code in a switch statement. 2) If a laser beam requires debouncing then something is broken.

groundFungus:
That is going to be impossible while you have a 1 second delay() in the CountPulses() function. Use a non-blocking millis() timer for that so that the code can be responsive.

Non-blocking timing tutorials:
Several things at a time.
Beginner’s guide to millis().
Blink without delay().

Amazing Stuff, i am trying to add the millis() that to the CountPulses() ISR, however it seems without the delay, the pulse counts are not being stored and interrupts are happening way too fast so i am seeing only 0s on the serial monitor. Below is what i put in the ISR:

void CountPulses()
{

IRQcount = 0;
sei();//enable interrupts
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
sei();//enable interrupts
PulseCount = IRQcount;//Count Interrupts fired due to Falling Edge
Serial.print(F("Pulse Count is = "));
Serial.println(PulseCount);

startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
}
cli();//disable interrupts
}

I believe the above should work in principle but i do not get the pulse count , am i missing something ?

CountPulses() is not an ISR. It is a function.

void CountPulses()
{
   
        IRQcount = 0;
        sei();//enable interrupts
        if (currentMillis - startMillis >= period)  //test whether the period has elapsed
        {
            sei();//enable interrupts
            PulseCount = IRQcount;//Count Interrupts fired due to Falling Edge

It lloks to me that PulseCount will always be 0 as you set IRQcount is set to 0 at the beginning of the function. Reset IRQcount after you read it.

Why are you enabling and disabling interrupts in that function? It seems backwards. Usually you disable interrupts so that the IRQcount variable cannot change while you read it and enable interrupts afterward. Since you disable interrupts at the end of the function, how do external interrupts happen?