Non-blocking code help - timeline is attached

Hi,
I have a project involving 9 solenoids. I open this topic in General electronics to get help for the solenoids driver circuit.

This topic I'm writing here is not about the electronics of the project in which the other topic was for. This topic is for help with the code for the project.

I want the code to be as much modular as possible - meaning - easy to make a change in the timing of each solenoid.

my idea of sequence is as following:

how can I do my above idea?

Thanks for any help!

Hello hk_jh
Post your current sketch, well formated, with comments and in so called code tags "</>" and a schematic, not a Fritzy diagram, to see how we can help.
Have a nice day and enjoy coding in C++.
Дайте миру шанс

What do you mean by "one pulse between every 7-9 seconds" ?

I was going to suggest you look into arrays, but then realised I might be misunderstanding what you mean by "between every x-y seconds" here: seems to me that it's variable, random? Does it mean that that led comes on somewhere between 7 and 9 seconds after it went off? Where does that choice come from (if I'm right in my understanding)? Or, if I'm wrong in my understanding can you explain it please?

image

edit: I see I'm not the only one who doesn't understand that :wink:

I see that's your go-to response, and maybe it's appropriate in the Programming Questions board. But this is Project Guidance and the OP's looking for exactly that: guidance on how to go about this.

looking at solenoid 2 for example:
"1:30: solenoid2 is joining - one pulse between every 9 - 25 seconds"
"20:00: solenoid 2 is turning off"

What I mean is that one pulse (ON state for 30ms than OFF) will be generated randomly between 9 - 25 seconds so if 1:30 minute has elapsed a random number will be generated - assuming number 10 - so at 1:40 one pulse of solenoid2 is generated. after that pulse is happen another random number will be generated (between 9-25 seconds). assuming the number 15 - at 1:55 another one pulse of that solenoid 2 will be generated and so on so on until the time 20:00 minute that this solenoid will stop completly.

is that more understoodable?

I would suggest a structure to represent each of the solenoids, then create an array of these.

struct Solenoid
{
  unsigned long startTime;       // The time this solenoid is first active
  unsigned long stopTime;        // The time this solenoid becomes inactive
  unsigned long minPulse;        // The minimum time the next pulse is generated
  unsigned long maxPulse;        // The maximum time the next pulse is generated
  unsigned long nextPulseStart;  // The time of the next pulse starts 
  unsigned long nextPulseStop;   // The time of the next pulse  stops
};

Solenoid mySolenoids[9]= { 50000,  600000, 5000, 10000, 0, 0,
                           90000, 1200000, 9000, 25000, 0, 0};

Then something like this... (untested)

void loop()
{
  startSequence();
}


void startSequence()
{
  unsigned long currentMillis = millis();
  
  for(uint8_t x = 0; x < 9; x++)
  {
    // Is this solenoid active
    if (mySolenoids[x].startTime < currentMillis && mySolenoids[x].stopTime > currentMillis)
    {
      // Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        // Turn off solenoid
        // Calculate nextPulseStart & nextPulseStop
      }

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
         // Turn on solenoid           
      }
    }
  }
}

where/how you determine the solenoids pins?

something like that?


//button pin to start/stop sequence
#define BTN_PIN 10 

//total num of solenoids
#define NUM_SOLENOIDS 9

//solenoids pin numbers
const uint8_t SOLENOID_PIN[NUM_SOLENOIDS] = { 2,3,4,5,6,7,8,9 };

void setup() {
  pinMode( BTN_PIN, INPUT_PULLUP );
  for (uint8_t i=0; i < NUM_SOLENOIDS; i++)
  { 
    pinMode(SOLENOID_PIN[i],OUTPUT);

  }
}

Just add to the struct, and define when you define each solenoid.

struct Solenoid
{
  unsigned long startTime;       // The time this solenoid is first active
  unsigned long stopTime;        // The time this solenoid becomes inactive
  unsigned long minPulse;        // The minimum time the next pulse is generated
  unsigned long maxPulse;        // The maximum time the next pulse is generated
  unsigned long nextPulseStart;  // The time of the next pulse starts 
  unsigned long nextPulseStop;   // The time of the next pulse  stops
  int pin;                       // The pin of the solenoid.
};

Indood. And seems @red_car has you covered so I'll keep out of the way.

I have never used struct before. how do you define the pin in the void setup(){} function?

  for (uint8_t i=0; i < NUM_SOLENOIDS; i++)
  { 
    pinMode(mySolenoids.pin[i],OUTPUT);

  }

I'm getting the following error:

my_solenoid:23:25: error: request for member 'pin' in 'mySolenoids', which is of non-class type 'Solenoid [9]'
pinMode(mySolenoids.pin[i],OUTPUT);
^~~
exit status 1
request for member 'pin' in 'mySolenoids', which is of non-class type 'Solenoid [9]'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

here is the code:

#define NUM_SOLENOIDS 9

struct Solenoid
{
  unsigned long startTime;       // The time this solenoid is first active
  unsigned long stopTime;        // The time this solenoid becomes inactive
  unsigned long minPulse;        // The minimum time the next pulse is generated
  unsigned long maxPulse;        // The maximum time the next pulse is generated
  unsigned long nextPulseStart;  // The time of the next pulse starts 
  unsigned long nextPulseStop;   // The time of the next pulse  stops
  uint8_t pin;
};

Solenoid mySolenoids[9]= { 50000,  600000, 5000, 10000, 0, 0,
                           90000, 1200000, 9000, 25000, 0, 0};



void setup()
{
   for (uint8_t i=0; i < NUM_SOLENOIDS; i++)
  { 
    pinMode(mySolenoids.pin[i],OUTPUT);

  }
  
}

void loop()
{
  startSequence();
}


void startSequence()
{
  unsigned long currentMillis = millis();
  
  for(uint8_t x = 0; x < 9; x++)
  {
    // Is this solenoid active
    if (mySolenoids[x].startTime < currentMillis && mySolenoids[x].stopTime > currentMillis)
    {
      // Do we need to calculate a next pulse time?
      if (mySolenoids[x].nextPulseStop < currentMillis)
      {
        // Turn off solenoid
        // Calculate nextPulseStart & nextPulseStop
      }

      // Are we currently in the middle of a pulse?
      if (mySolenoids[x].nextPulseStart < currentMillis && 
          mySolenoids[x].nextPulseStop  > currentMillis)
      {
         // Turn on solenoid           
      }
    }
  }
}

Sorry typo...

pinMode(mySolenoids[i].pin,OUTPUT);

Thanks. it compile now.

What does this array mean?

Solenoid mySolenoids[9]= { 50000,  600000, 5000, 10000, 0, 0,
                           90000, 1200000, 9000, 25000, 0, 0};

each index is correspond to the struct index?

solenoid number 9: start at 5 second, stop at minute 6, first pules after 5 sencond minimum and after 10 second maximum?
0 - don't start a new pulse? second 0 means?

Each row relates to 1 solenoid... remember you need to add the pin at the end now.

So row 2 relates to the example you gave:

On at 1:30 (90000 ms)
Off at 20min(120000ms)
Minimum next pulse 9 seconds(9000 ms)
Maximum next pulse 25 seconds (25000ms)
Next 2 variables get set in program // Calculate nextPulseStart & nextPulseStop
and then you need to add the pin number.

the "9" is the total number of solenoids. You need to fill all 9 rows.

Where the length of the pulse is determined? the solenoid should have a pulse of around 30ms (due to change) at is onTime (transient from off to on for 30ms to off)
can I try it with few solenoids (lets say 2) - so can I not fill all the 9 rows?

Is the pulse always the same for all solenoids? If it is then just create a global constant. It will be used when calculating nextPulseStart and nextPulseStop. If the pulse length is different for each solenoid then add another variable to the struct and initialise when you initialise the array.

Yes you can start with 2 solenoids... just use NUM_SOLENOIDS instead of hard coding "9".

Yes, The pulse should be the same for all solenoids.

uint8_t const PULSE_LENGTH = 30;

You need this when you calculate nextPulseStop.