#include <LiquidCrystal.h>
// Pins for the LCD
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Pins for stepper driver
const int stepPin = 3;
const int dirPin = 4;
// Variables for RPM and timer
int rpm = 60; // Default RPM
int hours = 0; // Timer hours
int minutes = 1; // Timer minutes
int stepsPerRevolution = 200; // Adjust based on your motor
unsigned long startTime;
unsigned long totalTimerMillis = 0; // Timer in milliseconds
bool motorRunning = false;
// Acceleration and Deceleration
int currentRPM = 0; // Start from 0 RPM
int maxRPM = 60; // Maximum RPM
int accelerationStep = 5; // RPM increment per step
int decelerationStep = 5; // RPM decrement per step
unsigned long rampDelay = 100; // Delay for acceleration ramp (ms)
// Pins for buttons
const int upButton = 5;
const int downButton = 6;
const int modeButton = 2; // Toggle between hours/minutes adjustment
const int startButton = 13; // Start motor
// Modes for timer adjustment
enum Mode { ADJUST_HOURS, ADJUST_MINUTES };
Mode currentMode = ADJUST_HOURS;
// Setup
void setup() {
// Initialize LCD
lcd.begin(16, 2);
lcd.print("RPM: ");
lcd.print(rpm);
// Set stepper driver pins
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
// Set button pins
pinMode(upButton, INPUT_PULLUP);
pinMode(downButton, INPUT_PULLUP);
pinMode(modeButton, INPUT_PULLUP);
pinMode(startButton, INPUT_PULLUP);
}
// Function to calculate delay between steps based on RPM
int calculateStepDelay(int rpm) {
return 60000000L / (stepsPerRevolution * rpm);
}
// Ramp function for acceleration
void rampUp(int targetRPM) {
while (currentRPM < targetRPM) {
currentRPM += accelerationStep;
if (currentRPM > targetRPM) currentRPM = targetRPM; // Ensure it doesn't exceed the target RPM
int stepDelay = calculateStepDelay(currentRPM);
for (int i = 0; i < stepsPerRevolution / 10; i++) { // Perform steps at the current RPM
digitalWrite(stepPin, HIGH);
delayMicroseconds(stepDelay / 2);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepDelay / 2);
}
delay(rampDelay);
}
}
// Ramp function for deceleration
void rampDown() {
while (currentRPM > 0) {
currentRPM -= decelerationStep;
if (currentRPM < 0) currentRPM = 0; // Ensure it doesn't go below 0 RPM
int stepDelay = calculateStepDelay(currentRPM);
for (int i = 0; i < stepsPerRevolution / 10; i++) { // Perform steps at the current RPM
digitalWrite(stepPin, HIGH);
delayMicroseconds(stepDelay / 2);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepDelay / 2);
}
delay(rampDelay);
}
}
// Loop
void loop() {
// Adjust RPM
if (digitalRead(upButton) == LOW) {
rpm += 10;
delay(200); // Debounce delay
}
if (digitalRead(downButton) == LOW && rpm > 10) {
rpm -= 10;
delay(200); // Debounce delay
}
// Adjust timer based on current mode
if (digitalRead(modeButton) == LOW) {
currentMode = (currentMode == ADJUST_HOURS) ? ADJUST_MINUTES : ADJUST_HOURS;
delay(200); // Debounce delay
}
if (digitalRead(upButton) == LOW) {
if (currentMode == ADJUST_HOURS && hours < 23) {
hours++;
} else if (currentMode == ADJUST_MINUTES && minutes < 59) {
minutes++;
}
delay(200); // Debounce delay
}
if (digitalRead(downButton) == LOW) {
if (currentMode == ADJUST_HOURS && hours > 0) {
hours--;
} else if (currentMode == ADJUST_MINUTES && minutes > 0) {
minutes--;
}
delay(200); // Debounce delay
}
// Check start button
if (digitalRead(startButton) == LOW) {
motorRunning = true;
totalTimerMillis = (hours * 3600000L) + (minutes * 60000L); // Convert to milliseconds
startTime = millis(); // Record start time
lcd.clear();
lcd.print("Running...");
rampUp(maxRPM); // Accelerate to max RPM
}
// Update LCD display
if (!motorRunning) {
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print(rpm);
lcd.print(" "); // Clear trailing characters
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(hours);
lcd.print("h ");
lcd.print(minutes);
lcd.print("m ");
}
// Run motor if motorRunning is true
if (motorRunning) {
unsigned long elapsedTime = millis() - startTime; // Elapsed time in milliseconds
if (elapsedTime < totalTimerMillis) {
int stepDelay = calculateStepDelay(maxRPM);
digitalWrite(dirPin, HIGH); // Clockwise direction
digitalWrite(stepPin, HIGH);
delayMicroseconds(stepDelay / 2);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepDelay / 2);
} else {
motorRunning = false; // Stop motor after timer ends
rampDown(); // Decelerate to stop
lcd.clear();
lcd.print("Done");
delay(2000); // Show "Done" message for 2 seconds
lcd.clear();
}
}
}