Cycle between High and LOW signal every milliseconds for 6 seconds

I am trying to pulse a stepper motor driver between HIGH and LOW signals every millisecond for 6 seconds, and am having trouble accomplishing this. I tried the blink without delay sketch and i got the stepper motor to move but too slow for what i need. I have also tried AnalogWrite() on the PWM pins, this gets the stepper motor to move but too slowly even at max hertz.

Hoping i can get some input here:

const int solenoid = 10; //Output to solenoid relay
const int Step = 9; //Stepper motor driver pulse signal
const int step_dir = 8; //Low=CW High=CCW direction output to step driver
const int button = 7; //start button and Cylinder switch
const int cylswitch = 6; //cylinder switch
const int stepdirection = 5; //input for direction of stepper motor

int cylstate;
int buttonstate; //state of button high/low input from start button
int dirstate;  //state of stepper direction high/low input from directional switch
int stepstate; //state of stepper motor pulse
int solstate; //state of solenoid high/low 

long previousmillis = 0;
long interval = 1;

void setup() {
pinMode(button, INPUT_PULLUP);
pinMode(stepdirection, INPUT_PULLUP);
pinMode(cylswitch, INPUT_PULLUP);
pinMode(solenoid,OUTPUT);
pinMode(step_dir,OUTPUT);
pinMode(Step,OUTPUT);
digitalWrite(step_dir,LOW);
digitalWrite(Step,LOW);
}

void loop() {

stepstate=digitalRead(stepdirection);
buttonstate=digitalRead(button);
cylstate=digitalRead(cylswitch);

if (stepstate==HIGH){
  dirstate=HIGH;} //when switch is on direction is CCW
 else{
  dirstate=LOW;} //when switch is off direction is CW

if (buttonstate==HIGH){
  solstate=HIGH;}//start button is pressed strobe is clamped activating cylswitch input
 else{
  solstate=LOW;} //start button is not pressed strobe is released

//Having trouble here

if((buttonstate==HIGH) && (cylstate==LOW)){
  unsigned long currentmillis=millis();
  if (currentmillis-previousmillis>interval){ //when air cylinder switch and start buttons are active turn on stepper motor for 6 seconds.
    previousmillis=currentmillis;
    if (stepstate == LOW) {
      stepstate = HIGH;} 
    else {
      stepstate = LOW;}
  digitalWrite(Step,stepstate);}
  }
 digitalWrite(solenoid,solstate);
 digitalWrite(step_dir,dirstate);
 }

analogWrite() is the wrong thing to use.

If you want to time things to millisecond accuracy, use microseconds. There's 1000 microseconds in a millisecond.

You don't need to be using balanced on- and off-times for the stepper. Most stepper drivers only require the pulse to be on for 1 microsecond. So switch it on, delayMicroseconds(1) and then turn it off right away.

i get it to work using that technique (see code), but how do i time it so it only runs for 6 seconds?

const int solenoid = 10; //Output to solenoid relay
const int Step = 9; //Stepper motor driver pulse signal
const int step_dir = 8; //Low=CW High=CCW direction output to step driver
const int button = 7; //start button and Cylinder switch
const int cylswitch = 6; //cylinder switch
const int stepdirection = 5; //input for direction of stepper motor

int cylstate;
int buttonstate; //state of button high/low input from start button
int dirstate;  //state of stepper direction high/low input from directional switch
int stepstate; //state of stepper motor pulse
int solstate; //state of solenoid high/low 

long previousmillis = 0;
long interval = 6000;

void setup() {
pinMode(button, INPUT_PULLUP);
pinMode(stepdirection, INPUT_PULLUP);
pinMode(cylswitch, INPUT_PULLUP);
pinMode(solenoid,OUTPUT);
pinMode(step_dir,OUTPUT);
pinMode(Step,OUTPUT);
digitalWrite(step_dir,LOW);
digitalWrite(Step,LOW);
}

void loop() {

stepstate=digitalRead(stepdirection);
buttonstate=digitalRead(button);
cylstate=digitalRead(cylswitch);

if (stepstate==HIGH){
  dirstate=HIGH;} //when switch is on direction is CCW
 else{
  dirstate=LOW;} //when switch is off direction is CW

if (buttonstate==HIGH){
  solstate=HIGH;}//start button is pressed strobe is clamped activating cylswitch input
 else{
  solstate=LOW;} //start button is not pressed strobe is released



if((buttonstate==HIGH) && (cylstate==LOW)){
      digitalWrite(Step,HIGH);;
      delayMicroseconds(1);
      digitalWrite(Step,LOW);;
      delayMicroseconds(1);}


 digitalWrite(solenoid,solstate);
 digitalWrite(step_dir,dirstate);
 }

but how do i time it so it only runs for 6 seconds?

using millis() for non blocking timing as in Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

tried adjusting the code following those samples you provided and still nothing happens. Not sure the issue.

const int solenoid = 10; //Output to solenoid relay
const int Step = 9; //Stepper motor driver pulse signal
const int step_dir = 8; //Low=CW High=CCW direction output to step driver
const int button = 7; //start button and Cylinder switch
const int cylswitch = 6; //cylinder switch
const int stepdirection = 5; //input for direction of stepper motor

int cylstate;
int buttonstate; //state of button high/low input from start button
int dirstate;  //state of stepper direction high/low input from directional switch
int stepstate; //state of stepper motor pulse
int solstate; //state of solenoid high/low 

long previousmillis = 0;
long interval = 6000;

void setup() {
pinMode(button, INPUT_PULLUP);
pinMode(stepdirection, INPUT_PULLUP);
pinMode(cylswitch, INPUT_PULLUP);
pinMode(solenoid,OUTPUT);
pinMode(step_dir,OUTPUT);
pinMode(Step,OUTPUT);
digitalWrite(step_dir,LOW);
digitalWrite(Step,LOW);
}

void loop() {

stepstate=digitalRead(stepdirection);
buttonstate=digitalRead(button);
cylstate=digitalRead(cylswitch);

if (stepstate==HIGH){
  dirstate=HIGH;} //when switch is on direction is CCW
 else{
  dirstate=LOW;} //when switch is off direction is CW

if (buttonstate==HIGH){
  solstate=HIGH;}//start button is pressed strobe is clamped activating cylswitch input
 else{
  solstate=LOW;} //start button is not pressed strobe is released

if((buttonstate==HIGH) && (cylstate==LOW)){
  unsigned long currentmillis=millis();
  if (currentmillis-previousmillis>interval){ //when air cylinder switch and start buttons are active turn on stepper motor for 6 seconds.
    previousmillis=currentmillis;
    if (digitalRead(Step)==LOW){
      digitalWrite(Step,HIGH);;
      delayMicroseconds(1);
      digitalWrite(Step,LOW);;
      delayMicroseconds(1);}}}


 digitalWrite(solenoid,solstate);
 digitalWrite(step_dir,dirstate);
 }

Your code is hard to read with multiple } on some lines. Run the auto-format tool in Arduino to fix that.

The second delayMicroseconds() is not necessary.

Your timing is still using milliseconds, so you can't step any faster than one step per millisecond.

Normally you want a stepper motor to run to a certain position. To do that, you count the number of steps and stop when the required distance has been completed. If it has to run for a period of time, then you need an additional "interval" to keep track of that. The way it's written now ,it will only take one step each 6 seconds.

It looks like you're using buttons or switches to set the direction and start/stop. Think about the states the system can be in - waiting for a start, running forwards, etc. What happens if the direction switch is switched during the 6 seconds? Does it run the remaining time in reverse or should it remember the direction it was originally commanded and keep moving in that direction? Does it start a new 6 seconds?

I'm very much a noob, but I had a similar challenge.

Perhaps someone can verify this but i might try reading the micros() at the point you want the 6 seconds to start then let 6 seconds elapse.

currentmicros = micros(); //record current time as currentmicors
delaytime = currentmicros + 6000 ;//add 6 seconds to the currentmicros and call it delaytime

when micros and delaytime are equal 6 seconds have passed.

Everyone has been helpful with my challenges, so I hope I have helped with yours.

Suggestions to make things clearer.

Put the code that is to be executed repeatedly in a function.
Create a boolean variable initially set to false and call the action function only when the boolean is true
Set the boolean to true when the start conditions become true not when they are true
Save the start time for the 6 second period at that time
Each time through loop() if the boolean is true and the 6 second period has not elapsed call the action function
When the period has elapsed or some exit condition()s become true set the boolean to false to stop the action

ultratec:
I'm very much a noob, but I had a similar challenge.

Perhaps someone can verify this but i might try reading the micros() at the point you want the 6 seconds to start then let 6 seconds elapse.

currentmicros = micros(); //record current time as currentmicors
delaytime = currentmicros + 6000 ;//add 6 seconds to the currentmicros and call it delaytime

when micros and delaytime are equal 6 seconds have passed.

Everyone has been helpful with my challenges, so I hope I have helped with yours.

There are one million microseconds in a second, not one thousand.

ultratec:
currentmicros = micros(); //record current time as currentmicors
delaytime = currentmicros + 6000 ;//add 6 (milli)seconds to the currentmicros and call it delaytime

Do not add to milli/microseconds in Arduino. Only subtract. See Nick
Gammon's page on overflows.

Nice thanks for the feedback. I got my code to work by setting a Boolean variable in a timer loop which is pretty effective. However, this only works the first time the start button is pressed. When the start button is pressed a second time nothing happens. If i reset the board twice it works again for the first button press. Is there any way to adjust the code so the last two if loops are activated every time the start button is pressed?

const int solenoid = 10; //Output to solenoid relay
const int Step = 9; //output Stepper motor driver pulse signal
const int step_dir = 8; //output Low=CW High=CCW direction output to step driver
const int button = 7; //input for start button
const int cylswitch = 6; //input cylinder switch
const int stepdirection = 5; //input for direction of stepper motor

int cylstate; //state of solenoid and cylinders it actuates
int buttonstate; //7 state of button high/low input from start button
int dirstate;  //5 state of stepper direction high/low input from directional switch
int stepstate; //state of stepper motor pulse
int solstate; //6 state of solenoid high/low

unsigned long overallstarttime;
unsigned long previousmicros; //time tracking variable
unsigned long Timeinterval = 6000000; //overall time interval to run step motor
unsigned long stepinterval = 1; //time per step om motor
unsigned long currenttime;
boolean stepping = true; //statement to control overall time of step motor running

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(stepdirection, INPUT_PULLUP);
  pinMode(cylswitch, INPUT_PULLUP);
  pinMode(solenoid, OUTPUT);
  pinMode(step_dir, OUTPUT);
  pinMode(Step, OUTPUT);
  digitalWrite(step_dir, LOW);
  digitalWrite(Step, LOW);
  overallstarttime = micros();
  previousmicros = overallstarttime;
}

void loop() {

  //Read states of inputs
  dirstate = digitalRead(stepdirection);
  buttonstate = digitalRead(button);
  cylstate = digitalRead(cylswitch);

  //start button is pressed strobe is clamped activating cylswitch input to LOW
  if (buttonstate == HIGH) {
    solstate = HIGH;
  }//start button is not pressed strobe is released
  else {
    solstate = LOW;
  }

  //when air cylinder switch and start buttons are active turn on stepper motor with 1 microsencond step time
  if ((buttonstate == HIGH) && (cylstate == LOW)) {
    currenttime = micros();
    if (currenttime - previousmicros > stepinterval && stepping) {
      digitalWrite(Step, !digitalRead(Step));
      previousmicros = previousmicros + stepinterval;
    }
    //track 6s time interval for stepper motor to run
    if (currenttime - overallstarttime >= Timeinterval && stepping) {
      stepping = false;
    }
  }
  
  //write output states
  digitalWrite(Step, stepstate);
  digitalWrite(solenoid, solstate);
  digitalWrite(step_dir, dirstate);
}

These links may help
Stepper Motor Basics
Simple Stepper Code

...R

However, this only works the first time the start button is pressed. When the start button is pressed a second time nothing happens.

That's because you never set stepping back to true again to allow another timing cycle to start

i added this bit of code after the 6s tracking loop, but then nothing happens when i press the start button.

  if (buttonstate == LOW && stepping == false) {
    stepping = true;
  }

Please post the whole program as it is now

Here is something that you might find useful

const byte outPin = 3;
unsigned long currentTime;
unsigned long longPeriodStart;
unsigned long shortPeriodStart;
unsigned long longPeriod = 6000000;   //6 seconds in microseconds
unsigned long shortPeriod = 1000;     //1 millisecond in microseconds
boolean pulsing = true;

void setup()
{
  Serial.begin(115200);
  pinMode(outPin, OUTPUT);
  currentTime = micros();
  longPeriodStart = currentTime;
  shortPeriodStart = currentTime;
}

void loop()
{
  currentTime = micros();
  if (currentTime - longPeriodStart >= longPeriod)
  {
    Serial.println("toggle");
    pulsing = !pulsing;
    longPeriodStart = currentTime;
    shortPeriodStart = currentTime;
  }
  if (pulsing)
  {
    output();
  }
}

void output()
{
  if (currentTime - shortPeriodStart >= shortPeriod)
  {
    digitalWrite(outPin, !digitalRead(outPin));
    shortPeriodStart = currentTime;
  }
}

As written the code toggles between producing pulses for 6 seconds and not producing pulses for 6 seconds. To start producing pulses set the pulsing boolean to true for the required period, perhaps as a result of user input.

here it is.

const int solenoid = 10; //Output to solenoid relay
const int Step = 9; //output Stepper motor driver pulse signal
const int step_dir = 8; //output Low=CW High=CCW direction output to step driver
const int button = 7; //input for start button
const int cylswitch = 6; //input cylinder switch
const int stepdirection = 5; //input for direction of stepper motor

int cylstate; //state of solenoid and cylinders it actuates
int buttonstate; //7 state of button high/low input from start button
int dirstate;  //5 state of stepper direction high/low input from directional switch
int stepstate; //state of stepper motor pulse
int solstate; //6 state of solenoid high/low

unsigned long overallstarttime;
unsigned long previousmicros; //time tracking variable
unsigned long Timeinterval = 6000000; //overall time interval to run step motor
unsigned long stepinterval = 1; //time per step om motor
unsigned long currenttime;
boolean stepping = true; //statement to control overall time of step motor running

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(stepdirection, INPUT_PULLUP);
  pinMode(cylswitch, INPUT_PULLUP);
  pinMode(solenoid, OUTPUT);
  pinMode(step_dir, OUTPUT);
  pinMode(Step, OUTPUT);
  digitalWrite(step_dir, LOW);
  digitalWrite(Step, LOW);
  overallstarttime = micros();
  previousmicros = overallstarttime;
}

void loop() {

  //Read states of inputs
  dirstate = digitalRead(stepdirection);
  buttonstate = digitalRead(button);
  cylstate = digitalRead(cylswitch);

  //start button is pressed strobe is clamped activating cylswitch input to LOW
  if (buttonstate == HIGH) {
    solstate = HIGH;
  }//start button is not pressed strobe is released
  else {
    solstate = LOW;
  }

  //when air cylinder switch and start buttons are active turn on stepper motor with 1 microsencond step time
  if ((buttonstate == HIGH) && (cylstate == LOW)) {
    currenttime = micros();
    if (currenttime - previousmicros > stepinterval && stepping) {
      digitalWrite(Step, !digitalRead(Step));
      previousmicros = previousmicros + stepinterval;
    }
    //track 6s time interval for stepper motor to run
    if (currenttime - overallstarttime >= Timeinterval && stepping) {
      stepping = false;
    }
  }
  //change state of stepping when start button is released after 6 second cycle completed
  if (buttonstate == LOW && stepping == false) {
    stepping = true;
  }

  //write output states
  digitalWrite(Step, stepstate);
  digitalWrite(solenoid, solstate);
  digitalWrite(step_dir, dirstate);
}

You don't seem to be updating the value of overallstarttime anywhere so this test

    //track 6s time interval for stepper motor to run
    if (currenttime - overallstarttime >= Timeinterval && stepping)
    {
      stepping = false;
    }

will return true every time and stepping will be set to false every time.

J_Dub98375:
here it is.

And what exactly happens when you run that code?

What do you want it to do that is different?

Have you looked at any of the code suggestions you have been given?

...R