#include <LiquidCrystal_I2C.h>
#define DIR1_PIN 4
#define STEP1_PIN 5
#define POT1_PIN A0
#define DIR2_PIN 2
#define STEP2_PIN 3
#define POT2_PIN A1
#define EN1_PIN 7
#define EN2_PIN 6
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
enum stepperDirections : bool {
CCW,
CW
};
typedef struct {
// Output
uint8_t dirPin;
uint8_t stepPin;
// Input
uint8_t enPin;
uint8_t potPin;
bool enable;
bool direction;
int position;
int speed;
unsigned long startTime;
} motor_t;
#define DEFAULT_DEBOUNCE_PERIOD 10UL // Debounce Delay 10 milliseconds
typedef struct {
private:
bool input;
unsigned long startTime;
public:
bool state;
bool pressed(bool bounce, const unsigned long timeDelay = DEFAULT_DEBOUNCE_PERIOD) {
bool prevState = state;
if (bounce) {
state = true;
} else {
if (state) {
unsigned long currTime = millis();
if (input) {
startTime = currTime;
}
unsigned long elapsedTime = currTime - startTime;
if (elapsedTime >= timeDelay) {
state = false;
}
}
}
input = bounce;
return state != prevState & state == true;
}
} pressed_t;
const uint8_t numberOfMotors = 2;
motor_t motors[numberOfMotors] = {
{DIR1_PIN, STEP1_PIN, EN1_PIN, POT1_PIN},
{DIR2_PIN, STEP2_PIN, EN2_PIN, POT2_PIN}
};
pressed_t enables[numberOfMotors];
void MotorEnable(uint8_t index);
void MotorSpeed(uint8_t index);
void MotorRotation(uint8_t index);
void LCDPrint(uint8_t index);
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
for (uint8_t index = 0; index < numberOfMotors; index++) {
pinMode(motors[index].enPin, INPUT_PULLUP);
pinMode(motors[index].dirPin, OUTPUT);
pinMode(motors[index].stepPin, OUTPUT);
}
}
void loop() {
for (uint8_t index = 0; index < numberOfMotors; index++) {
MotorEnable(index);
MotorSpeed(index);
MotorRotation(index);
LCDPrint(index);
}
}
void MotorEnable(uint8_t index) {
enables[index].pressed(!digitalRead(motors[index].enPin));
motors[index].enable = enables[index].state;
}
void MotorSpeed(uint8_t index) {
int rawValue = analogRead(motors[index].potPin);
motors[index].speed = map(rawValue, 0, 1023, 10, 100);
digitalWrite(motors[index].dirPin, motors[index].direction);
}
void MotorRotation(uint8_t index) {
unsigned long currTime = micros();
if (motors[index].enable) {
if (currTime - motors[index].startTime >= map(motors[index].speed, 10, 100, 100, 10) * 100) {
motors[index].startTime = currTime;
digitalWrite(motors[index].stepPin, HIGH);
digitalWrite(motors[index].stepPin, LOW);
}
}
}
void LCDPrint(uint8_t index) {
static unsigned long startTime;
unsigned long currentTime = millis();
if (currentTime - startTime >= 100UL) {
startTime = currentTime;
lcd.setCursor(0, index);
lcd.print("M0" + String(index + 1));
lcd.print(":");
lcd.print(motors[index].enable ? "ENA" : "DIS");
lcd.print(" SPD:");
lcd.print(PadLeft(String(motors[index].speed), 3, ' '));
lcd.print("%");
}
}
// return string by padding charecter on the Left of the String
String PadLeft(String message, int length, char paddingChar) {
int lenPad = length - message.length();
for (int index = 0; index < lenPad; index++) {
message = paddingChar + message;
}
return message.substring(0, length);
}