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);
}
}