How can I code using TTL signal (+5V) to control stepper motor direction?

I am new to coding in general, and I am mainly self taught. I am using a bipolar stepper motor, with two limit switches and an external device (analytical instrument) that provides TTL outputs. Originally, I had working code where when a limit switch was activated, it could change the direction of the stepper motor. I quickly learned that the stepper motor rate isn’t precise enough to stay in time with the analytical instrument. I’m trying to have the two devices communicate (the analytical instrument has strict software), so the analytical instrument can keep time and tell the stepper motor when to change direction. The instrument can only provide TTL ouput, so I have wired a pin that can receive the signal. The signal from the instrument is normal edge, so it’s constant +5V and sends a 0v signal.

When I use an if loop based on whether the limit switches are active, this controls the direction of the stepper motor very well. Now, I’m trying to adapt the code so the limit switches are for safety, so they can stop the motor from turning if either one is activated, and instead use the TTL 0v from the instrument to control the stepper motor direction. The code compiles. It’s only when I uploaded the code below, the stepper motor doesn’t respond or turn at all. The code has been able to control the stepper motor before, it’s only when I added the bolded section that the stepper ceased to respond to the stop/start commands.

Any feedback is greatly appreciated!

//MOTOR SETUP
const int MotorSpeedFW = 14; // for control over injecting speed
const int MotorSpeedRW = 1; // for control over sampling speed
int speedFW = 2000;
int speedRW = 2000;
int MotorStartStop = 0;
int direction_set; // no initial value for motor direction FW=1 RW=0

//PIN SETUP
const int dirPin1 = 4;  //DIG PIN 4
const int stepperPin1 = 5; //DIG PIN 5
const int dirPin2 = 7; //DIG PIN 7
const int stepperPin2 = 6; //DIG PIN 6
const int LimitSwitchTOP = 2;   // neg. direction sensor limit pin
const int LimitSwitchBOTTOM = 3;  // pos. direction sensor limit pin 
const int TTLin = 8; // DIG PIN 8 for TTLout-TTLin on IC


// BLINK SETUP - Millis value when the data was last sent. 
long LastSent;
long LastBlink = 0; // Time we last blinked the LED
int OnTime = 10; // Amount of time the LED remains on [milliseconds]
int OffTime = 100; // Amount of time the LED remains off [milliseconds]
const int LEDPin = 13; // Pin the LED is attached to 

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Blink 2.0"));
  Serial.println(F("=========="));

  //BLINK SETUP
  LastSent = millis();

 
  //MOTOR SETUP  
  pinMode(dirPin1, OUTPUT);
  pinMode(stepperPin1, OUTPUT);
  pinMode(dirPin2, OUTPUT);
  pinMode(stepperPin2, OUTPUT);
  
  pinMode(TTLin, INPUT);
  pinMode(LimitSwitchTOP, INPUT);
  pinMode(LimitSwitchBOTTOM, INPUT);
  
  pinMode(relay1_pin, OUTPUT);
  pinMode(relay2_pin, OUTPUT);
  
}//END OF SETUP


//MOTOR FUNCTION

void stepFW () //STEP FW Function
{
  if (direction_set == 1 ) {
    
  digitalWrite(dirPin2,LOW);
  digitalWrite(dirPin1,LOW);
  
  for(int j=0;j<=MotorSpeedFW;j++){
    digitalWrite(stepperPin1,LOW);
    digitalWrite(stepperPin2,LOW);
    delayMicroseconds(speedFW);
    digitalWrite(stepperPin1,HIGH);
    digitalWrite(stepperPin2,HIGH);
    //delay(1);
    }
   }
}

void stepRW () //STEP RW Function
{
  if (direction_set == 0 ) {
  
  digitalWrite(dirPin2,HIGH);
  digitalWrite(dirPin1,HIGH);
  
  for(int j=0;j<=MotorSpeedRW;j++){
    digitalWrite(stepperPin1,LOW);
    digitalWrite(stepperPin2,LOW);
    delayMicroseconds(speedRW);
    digitalWrite(stepperPin1,HIGH);
    digitalWrite(stepperPin2,HIGH);
    delay(50);
    }
   }
}

void loop() 
{
  SerialCommandHandler.Process();
  
  //SETUP MOTOR SPEED AND LIMIT SWITCHES
  speedFW = (2000 - (2000*MotorSpeedFW/100)); //for control over sampling speed
  speedRW = (2000 - (2000*MotorSpeedRW/100)); //for control over injecting speed
  
  int toplimitSwitch = digitalRead(LimitSwitchTOP);
  int bottomlimitSwitch = digitalRead(LimitSwitchBOTTOM);
  int IC_signal = digitalRead(TTLin);
  

 [b][b] if (toplimitSwitch == HIGH && bottomlimitSwitch == HIGH){
    MotorStartStop = 0;
  }
  else {
    Panel.SetText("lst1", "OFF");
    Panel.SetText("lsd1", "OFF");
  }
  
  if (IC_signal == LOW){
    switch (direction_set){
      case 0:
      direction_set = 1;
      break;
      case 1:
      direction_set = 0;
      break;
    }
  }
[/b]
  //SETUP MOTOR
  if ( MotorStartStop == 1 ) {
    if (direction_set == 0 ) {
      Panel.SetText("direction_set", "0");
      Panel.SetText("direction_read", "Collecting Sample");
      stepRW();
    } else if (direction_set == 1 ) 
    {
      Panel.SetText("direction_set", "1");
      Panel.SetText("direction_read", "Injecting Sample");
      stepFW();
    }
  else {
    Panel.SetText("direction_read", "Motor Stopped");  
    delayMicroseconds(1);
  }
  }

}//END OF PROGRAM

Also cross posted on ASE https://arduino.stackexchange.com/questions/53459/how-can-i-use-a-ttl-signal-to-control-the-movement-of-a-stepper-motor

If you're going to sprinkle the same question all over the internet, at least be considerate enough to link them so nobody wastes their time giving you answers you already have.

Nowhere in your code MotorStartStop is set to 1.

Hi,
What are you using to control the stepper motor?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

Thank you, Delta_G, for your do diligence. I've linked the other post to this as well.

I'm also using MegunoLink to interact with Arduino, so setting the MotorStartStop to 0 or 1 is done through that interface.

I'm using a Stepper Motor Shield which is wired exactly like Stepper_Motor_Shield_For_Arduino_DRV8825__SKU_DRI0023-DFRobot

I have been able to code the limit switches to stop the motor, using simple switch...case code. All the code works (if the IC_signal, here IC = Ion Chromatograph, is commented out). It's only when I try to code in when Arduino receives a TTL signal from the Ion Chromatograph, it changes direction. I realize this must be a basic coding question. :confused:

Even if the chromatograph sends a very short pulse, the Arduino works so fast that it may see that input is LOW many times around the loop. So it switches direction many times.

Look at the example sketch used to detect when an input changes.

If the LOW pulse truly is short (microseconds) then you may not detect it at all this way and may need to use an interrupt.

I'm also using MegunoLink to interact with Arduino, so setting the MotorStartStop to 0 or 1 is done through that interface.

That is nowhere in your code except for the undefined SerialCommandHandler. Can you show us a link to this library?

What type of IC? Just for curiosity, thats one of the instruments I build for a living. It’s not from Dionex is it?

Thank you, both! I figured out the problem with the pin number I was using. Pin 8 was manageable as an output pin, but for INPUT - the stepper motor would not work when there was 5+V running through it. In the Datasheet, this pin also had some other functions that deal with the rotation resolution. When I switched to pin 13, then the TTL signal was able to be recognized. A simple if (IC_signal == HIGH && direction_set == ) loop does the trick.

Yes! It is a Dionex system. Do you build the internal hardware as well?? I've heard stories of the old PeakNet software where you could control the TTL inputs more easily, but I had to work around that by making the Arduino the slave to the ICS-2000. Which ones do you build?

AHrdina:
Thank you, both! I figured out the problem with the pin number I was using. Pin 8 was manageable as an output pin, but for INPUT - the stepper motor would not work when there was 5+V running through it. In the Datasheet, this pin also had some other functions that deal with the rotation resolution. When I switched to pin 13, then the TTL signal was able to be recognized. A simple if (IC_signal == HIGH && direction_set == ) loop does the trick.

Yes! It is a Dionex system. Do you build the internal hardware as well?? I've heard stories of the old PeakNet software where you could control the TTL inputs more easily, but I had to work around that by making the Arduino the slave to the ICS-2000. Which ones do you build?

I sent you a PM. I can help.

pinMode(TTLin, INPUT);
  pinMode(LimitSwitchTOP, INPUT);
  pinMode(LimitSwitchBOTTOM, INPUT);

You're not using the internal pullup resistors for the switches. Do you have external resistors? The TTL won't need them, but the limit switches will float without and that can cause spurious readings.

  if ( MotorStartStop == 1 ) {
    if (direction_set == 0 ) {
      Panel.SetText("direction_set", "0");
      Panel.SetText("direction_read", "Collecting Sample");
      stepRW();
    } else if (direction_set == 1 ) 
    {
      Panel.SetText("direction_set", "1");
      Panel.SetText("direction_read", "Injecting Sample");
      stepFW();
    }
  else {
    Panel.SetText("direction_read", "Motor Stopped");  
    delayMicroseconds(1);
  }
  }

}//END OF PROGRAM

I think I see what's going on. I think you want that last else to go with the first if. But right now it goes with the else if. I think this is the logic you actually want:

if ( MotorStartStop == 1 ) {
    if (direction_set == 0 ) {
      Panel.SetText("direction_set", "0");
      Panel.SetText("direction_read", "Collecting Sample");
      stepRW();
    } else if (direction_set == 1 ) 
    {
      Panel.SetText("direction_set", "1");
      Panel.SetText("direction_read", "Injecting Sample");
      stepFW();
    }
}
else {
    Panel.SetText("direction_read", "Motor Stopped");  
    delayMicroseconds(1);
  }
  

}//END OF PROGRAM