Turning off a solenoid after time using Millis ()

I have a model of a 2 stroke engine to show my students how it works.
I have a solenoid which operates a valve at a certain degree of the crankshaft rotation.
If the engine stops with the solenoid HIGH it over heats and melts the plastic.
I have an Absolute Rotary Encoder telling the Mega where the crank is, and over 100 Neopixels flashing at certain positions, so I can't use delay()
I've chopped out most of the code with the Neopixels (over 5100 lines of code)
I can use the "blink without delay" but that just "blinks" the solenoid when it is HIGH.

const int PIN_DATA = 10; 
const int PIN_CS = 9;    
const int PIN_CLOCK = 8; 

// The Time the Solenoid will stay on if the engine stops when Solenoid HIGH
// This will overheat the Solenoid and melt the plastic
//int SolenoidState = LOW;
const int Solenoid = 7; // Solenoid Pin

int SolenoidState = LOW;
long interval = 1000; // 1 second
long unsigned lastTime = 0;        // will store last time Solenoid was updated  
int Timing = 0; // variable to store the 'fine tuning' of the NeoPixels
                // or you could just turn the encoder / crankshaft pulley

#define TIMING_PIN   A1 //  POT for adjusting NeoPixels timing
#define SPEEDPIN     A5 //  POT for adjusting Motor Speed

// These pins are hardwired in the motor shield
const int MotorDir = 12;      //  output pin for the Motor Direction
const int MotorSpeed = 3;     //  output pin for the Motor Speed 

int MotorPot = 0;       //  variable to store the value coming from the Motor POT
int TimingPot = 0;      //  variable to store the value coming from the Timing POT

void setup() 
{
  Serial.begin(9600);

  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_DATA, INPUT);

  pinMode (MotorDir, OUTPUT);
  pinMode (TimingPot, INPUT);
  pinMode (MotorPot, INPUT);

  pinMode (Solenoid, OUTPUT);

  digitalWrite(PIN_CLOCK, HIGH);
  digitalWrite(PIN_CS, LOW);

}
void loop() 
{
  // This bit for the speed control for the Electric Motor

  digitalWrite(MotorDir, HIGH); // Motor direction
  int SpeedPin = analogRead(SPEEDPIN);
  int Speed = map(SpeedPin,0,1024,0,255);
  analogWrite (MotorSpeed, Speed);

  // This bit is for the Absolute Rotary Encoder

  digitalWrite(PIN_CS, HIGH);
  digitalWrite(PIN_CS, LOW);
  int pos = 0;
  for (int i=0; i<10; i++) 
  {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);

    byte b = digitalRead(PIN_DATA) == HIGH ? 1 : 0;
    pos += b * pow(2, 10-(i+1));
  }
  for (int i=0; i<6; i++) 
  {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
  }
  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);

  int EncoderAngle = map(pos,0,1024, 0, 360);

  // This bit is to adjust the timing and 
  // keep the angle less than 360 degrees

  int AdjAngle = analogRead(TIMING_PIN);
  AdjAngle = map(AdjAngle, 0, 1024, 0, 360);

  int Angle = (AdjAngle + EncoderAngle);

  if (Angle >= 360) {
    (Angle -= 360);
  }

  //Serial.print("  Adjustment Angle  "); 
  //Serial.print(AdjAngle);
  //Serial.print(" Encoder Angle  "); 
  //Serial.print(EncoderAngle);
  


  // This bit for the solenoid on the Vacuum Port Cylinder
    if (Angle >160 && Angle <= 280)  
  {
    digitalWrite (Solenoid, HIGH);
    
     if(millis()- lastTime >= interval)
      {
        lastTime = millis();
        if (Solenoid == HIGH)
        SolenoidState = LOW;
      
       else
        SolenoidState = LOW;
       digitalWrite(Solenoid, SolenoidState);
      } 
  }   
    else 
    (digitalWrite (Solenoid, LOW));  
 
/*    if (Angle >160 && Angle <= 280)  
  {
   if(currentMillis + interval > millis())
      {
        if (Solenoid == HIGH)
        SolenoidState = LOW;
      
       else
        SolenoidState = LOW;
       digitalWrite(Solenoid, SolenoidState);
      } 
  }
  */
  Serial.print(" Angle  "); 
  Serial.print(Angle);
  Serial.print("  Millis  ");
  Serial.print(millis());
  Serial.print("   Last Time  ");
  Serial.print (lastTime); 
  //Serial.print("   previousMillis  ");
  //Serial.print (previousMillis);
  Serial.print( "   Solenoid  " );
  Serial.println (digitalRead (Solenoid));    

}

The bit I'm having trouble with is while the code is in the first "if statemsnt"

  // This bit for the solenoid on the Vacuum Port Cylinder
    if (Angle >160 && Angle <= 280)  
  {
    digitalWrite (Solenoid, HIGH);
    
     if(millis()- lastTime >= interval)
      {
        lastTime = millis();
        if (Solenoid == HIGH)
        SolenoidState = LOW;
      
       else
        SolenoidState = LOW;
       digitalWrite(Solenoid, SolenoidState);
      } 
  }   
    else 
    (digitalWrite (Solenoid, LOW));  
 
/*    if (Angle >160 && Angle <= 280)  
  {
   if(currentMillis + interval > millis())
      {
        if (Solenoid == HIGH)
        SolenoidState = LOW;
      
       else
        SolenoidState = LOW;
       digitalWrite(Solenoid, SolenoidState);
      } 
  }
  */

I've tried all sorts of various codes and even a separate "void", but I'm still at a loss.

Thanks in advance
Gerry

const int Solenoid = 7;

if (Solenoid == HIGH) is the same as saying if (7 == HIGH);

You need to do a digitalRead on Solenoid to see if it is high or low. digitalRead() - Arduino Reference

Also, in the following code even if the "if" statement worked (it doesn't), you are setting SolinenoidState LOW in every case and writing the solenoid to a LOW in every case.

if(millis()- lastTime >= interval)
      {
        lastTime = millis();
        if (Solenoid == HIGH)
        SolenoidState = LOW;
     
       else
        SolenoidState = LOW;
       digitalWrite(Solenoid, SolenoidState);
      }

Yes were are right.
I tried that before along with many many variations.
The problem is (I think) with updating the lastTime.
I've put lastTime = millis(); in the second if statement and still the same.
The Solenoid is HIGH between 160 and 280 degrees, but switches LOW for a blink
and goes HIGH again for a second

if (Angle >160 && Angle <= 280)
{
digitalWrite (Solenoid, HIGH);

if(millis() - lastTime >= interval)
{
lastTime = millis();
if (digitalRead (Solenoid == HIGH))
digitalWrite(Solenoid, LOW);
}
}
else
(digitalWrite (Solenoid, LOW));

Perhaps you can work it into a simple state machine:

#define TOUT_SOLENOID       1000ul

#define SOL_ANGLE_LOW       160
#define SOL_ANGLE_HIGH      280

void setup() 
{
    .
    .
    .

}

void loop() 
{
    .
    .
    .
    DoSolenoid( Angle );
    .
    .
    .

}

//Solenoid control state names
#define ST_OFF          0
#define ST_ON           1
#define ST_RESET        2
//
void DoSolenoid( int Angle )
{
    unsigned long
        timeNow;
    static unsigned long
        timeSolenoid;
    static byte
        stateSolenoid = ST_OFF;

    timeNow = millis();
    switch( stateSolenoid )
    {
        case    ST_OFF:
            //solenoid is off now. Is the angle correct to turn it on?
            if( Angle > SOL_ANGLE_LOW && Angle <= SOL_ANGLE_HIGH ) 
            {
                //yes; set pin high
                digitalWrite( Solenoid, HIGH );        
                //grab millis count now
                timeSolenoid = timeNow;
                //and move to on state
                stateSolenoid = ST_ON;
                
            }//if
            
        break;

        case    ST_ON:
            //is on now; has it been on too long?
            if( timeNow - timeSolenoid >= TOUT_SOLENOID )
            {
                //yes, shut it off and move to reset state
                digitalWrite( Solenoid, LOW );
                stateSolenoid = ST_RESET;                                        
            }//if
            //not on too long yet; still within valid angle?
            else if( Angle <= SOL_ANGLE_LOW || Angle > SOL_ANGLE_HIGH ) 
            {
                //no; turn it off and return to off state
                digitalWrite( Solenoid, LOW );
                stateSolenoid = ST_OFF;                                        
                                
            }//else
        
        break;

        case    ST_RESET:
            //solenoid was on too long. Wait until angle reading shows "off" before
            //returning to top of state machine
            if( Angle <= SOL_ANGLE_LOW || Angle > SOL_ANGLE_HIGH ) 
                stateSolenoid = ST_OFF;                                        
                
        break;
        
    }//switch
    
}//DoSolenoid

Thank you, Thank you
Yes it works.
Been on this problem for weeks
Again a big Thank you.
I've nearly finished and will put it up on Thingiverse.com
and the code on GitHub if that is OK with you.
Gerry

Hi,
This site also has in the forum a Exhibition/Gallery section you might like to place it in too.

Or Arduino project Hub.
https://create.arduino.cc/projecthub?f=1

Sounds like an interesting project.

Tom... :slight_smile: