interrupt pins

My assembly is one single stepper motor two limit switches a stepper driver and arduino uno. I want to have the stepper motor drive a stage x steps. The limit switches will act as safety cutt off switches that will stop the stage from running off the rails.

I am brand new to arduino, and I am looking for help with this project.

Do not try to write the code in one go. What have you tried so far ? Can you make a stepper motor move in either direction ? What action will start the motor moving ? Do you know how to read a switch input and determine whether it is HIGH or LOW ? How will the limit switches be wired ?

Note that it is extremely unlikely that you will need to use interrupts to do what you want.

You'll have much time between single steps of the motor, where you can check for the limit switches (best before each step). Consider how far the stage will move when stopped at full speed, you may need a stop sequence to run for a controlled stop. After such a stop you have to decide how to continue, mostly different depending on whether the limit was reached intentionally (calibration phase) or erroneously (emergency stop and shut down).

UKHeliBob: Note that it is extremely unlikely that you will need to use interrupts to do what you want.

Unbelievably unlikely in fact.

A query entitled "interrupt pins" for a situation where interrupt pins are completely and absolutely irrelevant. :astonished:

OK, so this always catches my attention, which is why I wrote this more-or-less generic explanation.

You may find some useful stuff in stepper motor basics

I agree with @UKHeliBob - develop the project in small pieces. Get each piece working separately before you try to joint them together. Have a look at planning and implementing a program

...R

samjacmon: Any advice?

There are 4 replies with advice so far.... did you read any of the links?

I did a quick and dirty test of an Uno running through loop() a while ago. Admittedly an (edit: almost) empty loop(), doing edit literally nothing very little, but if my memory serves me it ran through there some 150k times a second. So there's plenty of time to check your switches without using interrupts.

edit: my memory didn't serve me well at all: 1500x a second..... but still enough to service a couple of switches.

If you are literally brand new to Arduino, you should start here.

edit.... grrrr you removed your post of 907 so now my reply looks dumb.

JimboZA: I did a quick and dirty test of an Uno running through loop() a while ago. Admittedly an empty loop(), doing literally nothing, but if my memory serves me it ran through there some 150k times a second.

If it was an empty loop, how did you count how many times it ran?

JimboZA: edit.... grrrr you removed your post of 907 so now my reply looks dumb.

Par for the course I fancy.

"Hit and run" merchants. We get 'em.

Paul__B: If it was an empty loop, how did you count how many times it ran?

Voodoo....

edit... in fact looking at the code which clearly wasn't empty so it could count, I also had a bunch of analogRead()s in there to give a little work to do..

//speed test

long startTime;
long runTime;
long counter=0;
int analogReading;

void setup()
{
  startTime = millis();
  Serial.begin(9600);
  Serial.print("Start ");
  Serial.println(millis());
}

void loop()
{
  runTime = millis()- startTime;
  counter++;
  analogReading= analogRead(0);
  analogReading= analogRead(1);
  analogReading= analogRead(2);
  analogReading= analogRead(3);
  analogReading= analogRead(4);
  analogReading= analogRead(5);

  if (runTime >= 1000)
  {
    Serial.print("Looped ");
    Serial.print(counter);
    Serial.print(" times in ");
    Serial.print(runTime);
    while(1){
    };
  }

}

Also seems my memory was really bad on the performance: just ran that and it's 1500 times a second.

But analogRead() is a really slow operation (even if you do not allow for settling), so that is hardly surprising.

Paul__B: But analogRead() is a really slow operation (even if you do not allow for settling), so that is hardly surprising.

Ah ok, I'm not totally losing it: I remmed the analogRead()s out, and it's 150k loop()s in a second. That's what I was thinking about with the (more-or-less) empty loop().

UKHeliBob:
Do not try to write the code in one go. What have you tried so far ? Can you make a stepper motor move in either direction ? What action will start the motor moving ?

#include <TimerOne.h> 
String portString="";
volatile long tickCount=1L;
const int pinPowerRef = 8;
const int pinStep = 9;

const int pinDirLo = 10;
const int pinDir = 11;

const int pinENLo = 12;
const int pinENHi = 13;


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

  pinMode(pinPowerRef, OUTPUT);
  pinMode(pinStep, OUTPUT);
  pinMode(pinDirLo, OUTPUT);
  pinMode(pinDir, OUTPUT);
  pinMode(pinENLo, OUTPUT);
  pinMode(pinENHi, OUTPUT);
  
  digitalWrite(pinPowerRef, LOW);
  digitalWrite(pinStep, LOW);
  digitalWrite(pinDirLo, LOW);
  digitalWrite(pinDir, LOW);
  digitalWrite(pinENLo, LOW);
  digitalWrite(pinENHi, LOW);

  Timer1.initialize(2500);
  Timer1.attachInterrupt(timerTick);
  Timer1.pwm(pinStep,255); 
}

void loop()
{
}

// --------------------------
// Timer1 Routine
// --------------------------

void timerTick()
{
  if (tickCount > 0L)
  {
    tickCount --;
  }
  else
  {
    Timer1.stop();
    digitalWrite(pinPowerRef, HIGH);
    Serial.print("Done\n");
  }
}

// --------------------------
// Serial information
// --------------------------

void serialEvent(){

  while(Serial.available()){
    char inChar = (char)Serial.read(); 
    if (inChar == '\n') {
      processSerialCommand();
      break;
    } 
    else {
      portString += inChar;
    }
  }
}

void processSerialCommand(){
  char cmdHead = portString.charAt(0);
  
  switch (cmdHead){
    case 'X':
      Timer1.stop();
      digitalWrite(pinENHi, LOW);
      Serial.print("X\n");
      break;
    case 'O':
      digitalWrite(pinENHi, HIGH);
      Timer1.resume();
      Serial.print("O\n");
      break;
    case 'F':
      // FORWARD MODE
      digitalWrite(pinDir, HIGH);
      if (portString.length() > 1)
      {
        String tmpTicks = portString.substring(1);
        Serial.print(String(tmpTicks+"F\n"));
        tickCount = tmpTicks.toInt();
        digitalWrite(pinPowerRef, LOW);
        Timer1.resume();
      }
      break;  
    case 'R':
      // REVERSE MODE
      digitalWrite(pinDir, LOW);
      if (portString.length() > 1)      
      {
          String tmpTicks = portString.substring(1);
          Serial.print(String(tmpTicks+"R\n"));
          tickCount = tmpTicks.toInt();
          digitalWrite(pinPowerRef, LOW);
          Timer1.resume();
      }
      break;    
    case 'P':
      // CHANGE PERIOD
      if (portString.length() > 1)      
        {
          String tmpPer = portString.substring(1);
          Serial.print(String(tmpPer+"P\n"));
          Timer1.setPeriod(tmpPer.toInt());
        }
        break;
    case 'Q':
        Serial.print(tickCount);
        Serial.print("\n");      
        break;
    default:
      break;
  }
  
  portString="";
}

I apologize for the late response.

I am able to get the stage to move in both directions, and I have been able to adjust the speed as well. I am using motorized linear slide assembly. What I am trying to accomplish is utilizing the limit switches that are fixed to both ends of the slide.

To my current knowledge, I believe that the interrupt pins will pause a command and allow a new command to be performed first correct?

Also I have been told that by implementing interrupt pins in the code it will tidy up the code as well as free up processing time?

samjacmon: To my current knowledge, I believe that the interrupt pins will pause a command and allow a new command to be performed first correct?

Not really.

The purpose of an interrupt is to take notice of something shortlived and make a note that it has happened - perhaps by incrementing a count variable. The code in an Interrupt Service Routine (ISR) should be as short as possible - ideally taking less than 100 microsecs. When the ISR completes the Arduino keeps going where it left off.

You could, of course, use the code in an ISR to set a flag which the main program interprets as an indicator to do something else.

For the purpose of limit switches an ISR would just record the fact that the switch has been triggered. Wht to do in response to that should be decided in the main body of code.

However if you are moving a table with a stepper motor the simplest code would not need interrupts. It would be something like this pseudo code

void loop() {
   if (it is time for a step) {
       moveOneStep();
       checkLimitSwitches();
   }
   if (limitSwitch was pressed) {
      // do whatever
   }
 }

...R

Also I have been told that by implementing interrupt pins in the code it will tidy up the code as well as free up processing time?

Get friends who know what they are talking about.

Any code you write will have to check the flag from the interrupt routine and that will take just as long as checking the real input, and you have all that interrupt code to deal with. So more code and longer between reacting to a change.

Robin2: I agree with @UKHeliBob - develop the project in small pieces. Get each piece working separately before you try to joint them together. Have a look at planning and implementing a program

...R

Thank you Robin2.

After reading other posts from those new to the Arduino coding, I have decided to write out what I want the process to look like in order to communicate what I am attempting to accomplish. It goes as follows:

Start Check limit switches Reverse direction of the stage until it presses limit switch "A" Stop Wait for user input (Or existing code giving the desired stage positions/delays)

I am not sure if I am over complicating the code, but this is what I have come up with so far in terms of the limit switches...

//--------for the stage

const int stepMin=0;
const int stepMax=11540;
int stagePosition=stepMin;

//---------for the limit switches
const byte limitApin=2;
const byte limitBpin=3;
byte limitAstate;
byte limitBstate;

void setup() {
myStage.attach(stagePin);
myStage.write(stagePosition);

pinMode(limitApin, INPUT_PULLUP);
pinMode(limitBpin, INPUT_PULLUP);

delay(5000);

void setAutoPositioning(){
 if (limitAstate == LOW && limitBstate == LOW){
  return
 }
 if (limitAstate --LOW){
   // reverse direction 
 } 
 else {
   //wait for user input
 }
}
void loop() {

CheckLimitA();
CheckLimitB();

AskForUserInput();
GetUserResponce();

SetStageDelay();
SetStagePosition();
MoveStage();
}
void CheckLimitA(){
  limitAstate=digitalRead(limitApin);
}
void CheckLimitB(){
  limitBstate=digitalRead(limitBpin);
}
void AskForUserInput(){
}
void GetUserResponce(){
}
void SetStageDelay(){
/*the stage needs to stay in a possition for a 
alotted time then move to next possition*/
}
void SetStagePosition(){
}
void MoveStage(){
  myStage.write(stagePosition);
}

Is this portion of the coding written correctly?

if (limitAstate --LOW){What is this line supposed to do ?

Start Check limit switches Reverse direction of the stage until it presses limit switch "A" Stop

It's called HOMING . (ie: HOME the stage)

UKHeliBob: if (limitAstate --LOW){

What is this line supposed to do ?

if (limitAstate --LOW){
 // reverse direction 
}

It is meant to have the stage come towards limit switch A. Please keep in mind that I am not at all 100% positive that I am writing the code correctly.

There is a standard convention for homing stepper driven x-y stages.

First, there needs to be opto interupters at both ends (HOME & END) Second , both ends of the stage need to have Home Flags (metal piece mounted to stage that passes through the opto sensor. It is a small metal piece. Third, the software should ALWAYS home toward the HOME. Yes, Home is a place , and there is only one. On power-up the stage should check both sensors to see if the stage is at either end. Fourth, the stage starts moving a slow (homing) speed, toward HOME (AWAY from END) Fifth, when the HOME sensor detects interuption the speed drops down to a very slow crawl until the flag has passed completely THROUGH the HOME sensor Sixth, the motor then REVERSES direction and very slowly BACKS OUT of the HOME sensor until it completely clears it. Seventh, the motor AGAIN REVERSES direction and moves, one step at a time , very slowly TOWARD the HOME sensor and as soon as the sensor detects the flag the motor STOPS, with the sensor interrupted.

The stage is now homed.

raschemmel:
There is a standard convention for homing stepper driven x-y stages.

Thanks, this is exactly how I want the code to start.

But this is just the beginning of what I want the code to accomplish. The original code that I posted moves the motor forwards/backwards/and changes speed.

Below is the code for the stepper motor and driver board (I have not written this code myself but have verified that it does work.

#include <TimerOne.h> 
String portString="";
volatile long tickCount=1L;
const int pinPowerRef = 8;
const int pinStep = 9;

const int pinDirLo = 10;
const int pinDir = 11;

const int pinENLo = 12;
const int pinENHi = 13;


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

  pinMode(pinPowerRef, OUTPUT);
  pinMode(pinStep, OUTPUT);
  pinMode(pinDirLo, OUTPUT);
  pinMode(pinDir, OUTPUT);
  pinMode(pinENLo, OUTPUT);
  pinMode(pinENHi, OUTPUT);
  
  digitalWrite(pinPowerRef, LOW);
  digitalWrite(pinStep, LOW);
  digitalWrite(pinDirLo, LOW);
  digitalWrite(pinDir, LOW);
  digitalWrite(pinENLo, LOW);
  digitalWrite(pinENHi, LOW);

  Timer1.initialize(2500);
  Timer1.attachInterrupt(timerTick);
  Timer1.pwm(pinStep,255); 
}

void loop()
{
}

// --------------------------
// Timer1 Routine
// --------------------------

void timerTick()
{
  if (tickCount > 0L)
  {
    tickCount --;
  }
  else
  {
    Timer1.stop();
    digitalWrite(pinPowerRef, HIGH);
    Serial.print("Done\n");
  }
}

// --------------------------
// Serial information
// --------------------------

void serialEvent(){

  while(Serial.available()){
    char inChar = (char)Serial.read(); 
    if (inChar == '\n') {
      processSerialCommand();
      break;
    } 
    else {
      portString += inChar;
    }
  }
}

void processSerialCommand(){
  char cmdHead = portString.charAt(0);
  
  switch (cmdHead){
    case 'X':
      Timer1.stop();
      digitalWrite(pinENHi, LOW);
      Serial.print("X\n");
      break;
    case 'O':
      digitalWrite(pinENHi, HIGH);
      Timer1.resume();
      Serial.print("O\n");
      break;
    case 'F':
      // FORWARD MODE
      digitalWrite(pinDir, HIGH);
      if (portString.length() > 1)
      {
        String tmpTicks = portString.substring(1);
        Serial.print(String(tmpTicks+"F\n"));
        tickCount = tmpTicks.toInt();
        digitalWrite(pinPowerRef, LOW);
        Timer1.resume();
      }
      break;  
    case 'R':
      // REVERSE MODE
      digitalWrite(pinDir, LOW);
      if (portString.length() > 1)      
      {
          String tmpTicks = portString.substring(1);
          Serial.print(String(tmpTicks+"R\n"));
          tickCount = tmpTicks.toInt();
          digitalWrite(pinPowerRef, LOW);
          Timer1.resume();
      }
      break;    
    case 'P':
      // CHANGE PERIOD
      if (portString.length() > 1)      
        {
          String tmpPer = portString.substring(1);
          Serial.print(String(tmpPer+"P\n"));
          Timer1.setPeriod(tmpPer.toInt());
        }
        break;
    case 'Q':
        Serial.print(tickCount);
        Serial.print("\n");      
        break;
    default:
      break;
  }
  
  portString="";
}

Below is the code I tried to write for the limit switches

//--------for the stage

const int stepMin=0;
const int stepMax=11540;
int stagePosition=stepMin;

//---------for the limit switches
const byte limitApin=2;
const byte limitBpin=3;
byte limitAstate;
byte limitBstate;

void setup() {
myStage.attach(stagePin);
myStage.write(stagePosition);

pinMode(limitApin, INPUT_PULLUP);
pinMode(limitBpin, INPUT_PULLUP);

delay(5000);

void setAutoPositioning(){
 if (limitAstate == LOW && limitBstate == LOW){
  return
 }
 if (limitAstate --LOW){
   // reverse direction 
 } 
 else {
   //wait for user input
 }
}
void loop() {

CheckLimitA();
CheckLimitB();

AskForUserInput();
GetUserResponce();

SetStageDelay();
SetStagePosition();
MoveStage();
}
void CheckLimitA(){
  limitAstate=digitalRead(limitApin);
}
void CheckLimitB(){
  limitBstate=digitalRead(limitBpin);
}
void AskForUserInput(){
}
void GetUserResponce(){
}
void SetStageDelay(){
/*the stage needs to stay in a possition for a 
alotted time then move to next possition*/
}
void SetStagePosition(){
}
void MoveStage(){
  myStage.write(stagePosition);
}

I need to tie that code in with the “HOMING” code as well as the if/else statements that implement the limit switches to work as emergency stop switches in case something happens with the positioning of the stage after HOMING has been established.

I have been slowly figuring out the way to do this with ROBIN2’s planning and implimenting a program However, I am confused how to do this. Any suggestions?