Stepper motor interruption issue during LCD Countdown

Hi

I have a stepper that runs when a toggle button is pressed. On the LCD I have a countdown using millis() subtracting seconds from the total runtime.

The problem is that every time the LCD updates (every second) the motor has an interrupt, it stutters every millis interval().

How do I update the LCD every second without interrupting the stepper?

Please post your code as decribed in the how to get the best from the forum post.

A wiring diagram would probably be helpful, too.

I am using nema 34 stepper motor 12 Nm torque with 5.2A and Stepper motor driver 2D68MH, LCD Display 20*4 with I2C module, 4 Push buttons, 2 limiting switches,
Here is below Arduino code:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define BUZZER_PIN 7 // Define the buzzer pin
#define BUZZ_DURATION_SHORT 65 // Define duration for short buzz
#define BUZZ_DURATION_LONG 2000 // Define duration for long buzz
#define BUZZ_DURATION_INITIAL 1500 // Define duration for initial buzz
#define BUZZ_DURATION_COMPLETE 3000 // Define duration for complete buzz
#define DEBOUNCE_DELAY 200

LiquidCrystal_I2C lcd(0x27, 20, 4); // Set the LCD address to 0x27 for a 20 chars and 4 line display
const int clockwiseLimitPin = 6; // Change to your clockwise limit switch pin
const int counterclockwiseLimitPin = 5; // Change to your counterclockwise limit switch pin

bool clockwiseLimitReached = true;
bool counterclockwiseLimitReached = false;


const int modeButtonPin = 8;
const int increaseButtonPin = 10;
const int decreaseButtonPin = 9;
const int toggleButtonPin = 11;

unsigned long previousMillis = 0;
const long interval = 1000; // Update interval (1 second)

enum TimerState { HH, MM, SECONDS_STATE, FLEX_DELAY, EXT_DELAY, COUNTDOWN, PAUSED }; // Changed SS to SECONDS_STATE
TimerState currentState = HH;

int hours = 0;
int minutes = 0;
int seconds = 0;
int flexDelay = 0; // Flexion delay in seconds
int extDelay = 0; // Extension delay in seconds

bool startTimer = false;
bool togglePressed = false; // Added a togglePressed variable to track button state
bool displayNeedsUpdate = true; // Flag to track if display needs update

bool cursorOn = false; // Flag to track cursor position
int cursorPosition = 0; // Track cursor position (0 for HH, 1 for MM, 2 for SECONDS_STATE, 3 for FLEX_DELAY, 4 for EXT_DELAY)

// Stepper motor pins
const int dirPin = 3;
const int stepPin = 2;
const int enablePin = 4;

void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(modeButtonPin, INPUT_PULLUP);
  pinMode(increaseButtonPin, INPUT_PULLUP);
  pinMode(decreaseButtonPin, INPUT_PULLUP);
  pinMode(toggleButtonPin, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT); // Initialize buzzer pin as output
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(enablePin, OUTPUT);
  buzz(BUZZ_DURATION_INITIAL);

   // Other setup code...

  pinMode(clockwiseLimitPin, INPUT_PULLUP);
  pinMode(counterclockwiseLimitPin, INPUT_PULLUP);
}

bool countdownEnded = false; // Flag to track if the countdown has ended

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (startTimer && currentState == COUNTDOWN) {
      if (hours == 0 && minutes == 0 && seconds == 0) {
        startTimer = false;
        currentState = HH;
        displayNeedsUpdate = true;
        countdownEnded = true; // Set the flag to true when countdown ends
      } else {
        updateTimer();
        displayNeedsUpdate = true;
      }
    }
  }
  
  // Perform stepper motor steps if the timer is running
  if (startTimer && currentState == COUNTDOWN) {
    motorStep(2000); // Adjust the step count as needed
  }

  if (digitalRead(modeButtonPin) == LOW) {
    debounce();
    switchMode();
    displayNeedsUpdate = true;
    buzz(BUZZ_DURATION_SHORT); // Short buzz when mode button is pressed
  }

  if (digitalRead(increaseButtonPin) == LOW) {
    debounce();
    increaseValue();
    displayNeedsUpdate = true;
  }

  if (digitalRead(decreaseButtonPin) == LOW) {
    debounce();
    decreaseValue();
    displayNeedsUpdate = true;
  }

  if (digitalRead(toggleButtonPin) == LOW && !togglePressed) {
    debounce();
    togglePressed = true;
    toggleCountdown();
    displayNeedsUpdate = true;
  } else if (digitalRead(toggleButtonPin) == HIGH && togglePressed) {
    debounce();
    togglePressed = false;
  }

  // Check if limit switches are triggered
  if (digitalRead(clockwiseLimitPin) == LOW) {
    stopMotorAndApplyDelay(extDelay); // Apply EXT delay
    reverseMotorDirection(clockwiseLimitPin);
    delay(100); // Add a small delay for stability
  }

  if (digitalRead(counterclockwiseLimitPin) == LOW) {
    stopMotorAndApplyDelay(flexDelay); // Apply FLX delay
    reverseMotorDirection(counterclockwiseLimitPin);
    delay(100); // Add a small delay for stability
  }

  if (displayNeedsUpdate) {
    if (countdownEnded) {
      lcd.setCursor(0, 0);
      lcd.print("   CPM stopped   ");
    } else {
      displayTimer();
    }
    displayNeedsUpdate = false;
  }
}

void stopMotorAndApplyDelay(int delayTime) {
  digitalWrite(enablePin, HIGH); // Disable the motor
  delay(delayTime * 1000); // Apply delay in milliseconds
}

void reverseMotorDirection(int limitSwitchPin) {
  // Determine which limit switch has been triggered and reverse motor direction accordingly
  if (limitSwitchPin == clockwiseLimitPin) {
    // Reverse motor direction for clockwise limit switch
    digitalWrite(enablePin, LOW); // Enable the motor
    digitalWrite(dirPin, LOW); // Set the direction of rotation
  } else if (limitSwitchPin == counterclockwiseLimitPin) {
    // Reverse motor direction for counterclockwise limit switch
    digitalWrite(enablePin, LOW); // Enable the motor
    digitalWrite(dirPin, HIGH); // Set the direction of rotation
  }
}

void debounce() {
  delay(DEBOUNCE_DELAY);
}

void switchMode() {
  cursorOn = true; // Turn on cursor
  cursorPosition = (cursorPosition + 1) % 5; // Cycle through cursor positions (0, 1, 2, 3, 4)
  currentState = static_cast<TimerState>(cursorPosition); // Update timer state based on cursor position
}

void increaseValue() {
  switch (currentState) {
    case HH:
      hours = (hours + 1) % 24;
      break;
    case MM:
      minutes = (minutes + 1) % 60;
      break;
    case SECONDS_STATE:
      seconds = (seconds + 1) % 60;
      break;
    case FLEX_DELAY:
      flexDelay = (flexDelay + 1) % 11; // Flex delay from 0 to 10 seconds
      break;
    case EXT_DELAY:
            extDelay = (extDelay + 1) % 11; // Extension delay from 0 to 10 seconds
      break;
    default:
      break;
  }
}

void decreaseValue() {
  switch (currentState) {
    case HH:
      hours = (hours - 1 + 24) % 24;
      break;
    case MM:
      minutes = (minutes - 1 + 60) % 60;
      break;
    case SECONDS_STATE:
      seconds = (seconds - 1 + 60) % 60;
      break;
    case FLEX_DELAY:
      flexDelay = (flexDelay - 1 + 11) % 11; // Flex delay from 0 to 10 seconds
      break;
    case EXT_DELAY:
      extDelay = (extDelay - 1 + 11) % 11; // Extension delay from 0 to 10 seconds
            break;
    default:
      break;
  }
}

void toggleCountdown() {
  if (currentState == COUNTDOWN) {
    startTimer = !startTimer; // Toggle startTimer value
    if (!startTimer) {
      currentState = PAUSED;
      buzz(BUZZ_DURATION_LONG);
    }
  } else {
    currentState = COUNTDOWN;
    startTimer = true;
    if (countdownEnded) {
      countdownEnded = false; // Reset countdownEnded flag
      displayNeedsUpdate = true; // Trigger display update to show the main screen
      cursorOn = false; // Turn off cursor
      currentState = HH; // Reset timer state to HH
      hours = 0; // Reset hours
      minutes = 0; // Reset minutes
      seconds = 0; // Reset seconds
      flexDelay = 0; // Reset flex delay
      extDelay = 0; // Reset extension delay
    }
  }
}

void updateTimer() {
  if (seconds > 0) {
    seconds--;
  } else {
    if (minutes > 0) {
      minutes--;
      seconds = 59;
    } else {
      if (hours > 0) {
        hours--;
        minutes = 59;
        seconds = 59;
      }
    }
  }
}

void displayTimer() {
  lcd.clear();
  if (currentState == COUNTDOWN && hours == 0 && minutes == 0 && seconds == 0) {
    lcd.setCursor(0, 0);
    lcd.print("   CPM stopped   ");
    return;
  }

  lcd.setCursor(0, 0);
  lcd.print("Timer = HH:MM:SS");
  lcd.setCursor(0, 2);
  lcd.print("FLX Delay = ");
  lcd.print(flexDelay);
  lcd.print("s"); // Add "s" after flex delay value
  lcd.setCursor(0, 3);
  lcd.print("EXT Delay = ");
  lcd.print(extDelay);
  lcd.print("s"); // Add "s" after extension delay value

  lcd.setCursor(8, 1);
  if (cursorOn && currentState != COUNTDOWN && currentState != PAUSED) {
    switch (cursorPosition) {
      case 0:
        lcd.print(">");
        lcd.print(hours < 10 ? "0" : "");
        lcd.print(hours);
        lcd.print(":");
        lcd.print(minutes < 10 ? "0" : "");
        lcd.print(minutes);
        lcd.print(":");
        lcd.print(seconds < 10 ? "0" : "");
        lcd.print(seconds);
        break;
      case 1:
        lcd.print(hours < 10 ? "0" : "");
        lcd.print(hours);
        lcd.print(":>");
        lcd.print(minutes < 10 ? "0" : "");
        lcd.print(minutes);
        lcd.print(":");
        lcd.print(seconds < 10 ? "0" : "");
        lcd.print(seconds);
        break;
      case 2:
        lcd.print(hours < 10 ? "0" : "");
        lcd.print(hours);
        lcd.print(":");
        lcd.print(minutes < 10 ? "0" : "");
        lcd.print(minutes);
        lcd.print(":>");
        lcd.print(seconds < 10 ? "0" : "");
        lcd.print(seconds);
        break;
      case 3:
        lcd.print(hours < 10 ? "0" : "");
        lcd.print(hours);
        lcd.print(":");
        lcd.print(minutes < 10 ? "0" : "");
        lcd.print(minutes);
        lcd.print(":");
        lcd.print(seconds < 10 ? "0" : "");
        lcd.print(seconds);
        lcd.setCursor(12, 2); // Set cursor position for flex delay
        lcd.print(">");
        lcd.print(flexDelay);
        lcd.print("s"); // Add "s" after flex delay value
        break;
      case 4:
        lcd.print(hours < 10 ? "0" : "");
        lcd.print(hours);
        lcd.print(":");
        lcd.print(minutes < 10 ? "0" : "");
        lcd.print(minutes);
        lcd.print(":");
        lcd.print(seconds < 10 ? "0" : "");
        lcd.print(seconds);
        lcd.setCursor(12, 3); // Set cursor position for extension delay
        lcd.print(">");
        lcd.print(extDelay);
        lcd.print("s"); // Add "s" after extension delay value
        break;
    }
  } else {
    lcd.print(hours < 10 ? "0" : "");
    lcd.print(hours);
    lcd.print(":");
    lcd.print(minutes < 10 ? "0" : "");
    lcd.print(minutes);
    lcd.print(":");
    lcd.print(seconds < 10 ? "0" : "");
    lcd.print(seconds);
  }

  lcd.setCursor(0, 0);
  if (currentState == COUNTDOWN) {
    lcd.print("    CPM started  ");
  } else if (currentState == PAUSED) {
    lcd.print("    CPM paused  ");
  }
}

void buzz(int duration) {
  digitalWrite(BUZZER_PIN, HIGH); // Turn on buzzer
  delay(duration); // Wait for the specified duration
  digitalWrite(BUZZER_PIN, LOW); // Turn off buzzer
}

// Function to control stepper motor
void motorStep( int steps){
   for(int i = 0; i < steps; i++) {
        digitalWrite(stepPin,HIGH);
        delayMicroseconds(200);
        digitalWrite(stepPin,LOW);
        delayMicroseconds(200);
      }
}

Can anyone help me instantly to solve this issue?

Updating the LCD takes time, so your

cannot be called continously. ( Apart from that it is a blocking call )
Your debouncing is a little bit weired too :wink:

Which board are you using? If it is supported by the MobaTools library you could use it for step creating and switch debouncing. Tis library creates the step via timer ISR. So steps are even created while the LCD is updated.

I think your sketch needs to be changed significantly to solve your problem.

1 Like

I am using arduino uno and breadboard

So you can give MobaTools a try. I'm pretty shure it can solve your problem :wink:

Yes I tried mobatools but code could not execute
I am facing this issue,
exit status 1

Compilation error: 'MobaStepper' does not name a type; did you mean 'MoToStepper'?

The compiler obviously tells you what is wrong. Did you read the documentation and have a look at the examples?

Without seeing the code, no advice is possible.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.