I see the blocking code in here now... but it's such a common problem that it should be easy to fix. Forget about multitasking this or that... it's just about converting the delay() to millis().
// BV signal detection rev 5 April 2020
// Rev 4 includes flashing yellow, current sample averaging and added delays for green and red LEDs
// Rev 5 This version works. Cleaned up code and documentation
// ACS712 wiring pins connection to Arduino
// VCC pin to 5V
// GND pin to GND
// Out pin to A0
//Initialize variables
const int Csensor1 = A0; //Current sensor set on pin A0
int Green1 = 2; //Green signal 1 is set to digital pin 2
int Yellow1 = 3; //Yellow signal 1 is set to digital pin 3
int Red1 = 4; //Red signal 1 is set to digital pin 4
// Black signal wire goes to Arduino GND pin
int prevState = 0; // Set previous state to 0 for unoccupide
int sensitivity = 185; // Because ACS712 is 5A version
int adcValue = 0;
int offsetVoltage = 2497;
double adcVoltage = 0;
double currentValue = 0;
int currentSample = 0; // variable that returns current read
double sumCurrent = 0; // current accumulator
double avgCurrent = 0; // average current over sample
// Variables that can be tweaked
double sensorThreshold = .03354; // .0335 for Livermore front
int currentSampleSize = 15000; //Sets number of samples of current to average out
double blinkDelay = 1000; // sets delay between yellow blinks
int yellowBlinkNum = 15; // number of times the yellow LED blinks
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// Establish all of our pins as inputs or outputs
pinMode(Green1,OUTPUT);
pinMode(Yellow1,OUTPUT);
pinMode(Red1,OUTPUT);
// set initial state of LEDs to Green on and rest off
digitalWrite(Green1,HIGH); // Green signal on
digitalWrite(Yellow1,LOW); // Yellow signal off
digitalWrite(Red1,LOW); //Red signal off
}
void loop() {
// put your main code here, to run repeatedly:
// Read and compute track block current
// Sample current and average results
sumCurrent = 0;
for (int i = 0; i <= currentSampleSize; i++)
{ currentSample = analogRead(Csensor1);
// Compute voltage and current
adcVoltage = (currentSample / 1024.0) * 5000;
currentValue = ((adcVoltage - offsetVoltage) / sensitivity);
if (currentValue < 0) {currentValue = currentValue * -1;}
sumCurrent = sumCurrent + currentValue;}
avgCurrent = sumCurrent / currentSampleSize;
// Test for Occupany
if (avgCurrent > sensorThreshold ) {
// Block occupied
digitalWrite(Green1,LOW); // Green signal off
digitalWrite(Yellow1,LOW); // Yellow signal off
digitalWrite(Red1,HIGH); //Red signal on
prevState = 1; // Set occupancy to occupied
}
// Block not occupied right now
else if ( prevState == 1)
{
digitalWrite(Green1,LOW); // Turn off Green signal
digitalWrite(Red1,LOW); // Turn off Red signal
digitalWrite(Yellow1,HIGH);
// flash Yellow for X seconds
for (int j = 0; j <= yellowBlinkNum; j++)
{
digitalWrite(Yellow1,LOW); //Turn on Yellow
delay (blinkDelay);
digitalWrite(Yellow1,HIGH);
delay (blinkDelay);
}
prevState = 0; // Set occupancy to unoccupied
}
else
{// Block was not occupied before
digitalWrite(Green1,HIGH); // Turn on Green signal
digitalWrite(Yellow1,LOW); // Turn off Yellow signal
digitalWrite(Red1,LOW); // Turn off Red signal
prevState = 0; // Set occupancy to unoccupied
delay (5000);
}
}
I suggest you start using an enum for your state machine so the states can have meaningful names.
It looks to me (although I haven't dug deeply yet) that you could use the state machine itself to control timing. Right now it's underutilized. But I don't think you've explained, inside or outside the code, how it operates. Does it go through a timed sequence of signal aspects after occupancy is released? If so, you can just define states DANGER, APPROACH, CLEAR for which you have appropriate LED sequence handlers. I'm also not sure what signal system you are using but a flashing yellow is usually an ADVANCE and if you watched the signal after a train passes you would see the sequence DANGER, APPROACH, ADVANCE, CLEAR.
I have both proprietary and non-proprietary code for signals. The former is so because of the restrictive licensing agreement of the IDE I'm using (not Arduino). The Arduino implementation will be public some day, but it's just not ready for prime time. It's fully cooperative multitasking and features software LED brightness adjustment, LED gamma correction, tungsten filament lag simulation as well as searchlight filter servo simulation.
I've decided to hack this code for you. Look for an update later. Meanwhile, it would be great if you could give a very simple flowchart/pseudocode explanation of the desired behaviour.