#include <Button2.h>
#include <RTClib.h>;
RTC_DS3231 rtc;
// SDA to A4, CLK to A5, VCC to 5V
// Note the stepper in the simulation window does not run at 4096 steps per rotation - set to 400:1 - see diagram.json, also it is 4 phase instead of 8
// Motor and clock parameters
const long STEPS_PER_REV = 4096; //64 STEPS PER MOTOR REV * 64:1 GEAR RATIO
//#define STEPS_PER_REV 4096 // steps of a single rotation of motor
//#define RATIO 15 // minutes per a rotation - use if stepper output to min hand is not 1:1
#define BUTTON_PIN 12
Button2 button;
// wait for a single step of stepper
int delaytime = 2;
// ports used to control the stepper motor
// if your motor rotate to the opposite direction,
// 7 to IN1, 6 to IN2, 5 to IN3, 4 to IN5
// change the order as {4, 5, 6, 7};
int port[4] = { 7, 6, 5, 4 };
// sequence of stepper motor control - 8 phase
int seq[8][4] = {
{ LOW, HIGH, HIGH, LOW },
{ LOW, LOW, HIGH, LOW },
{ LOW, LOW, HIGH, HIGH },
{ LOW, LOW, LOW, HIGH },
{ HIGH, LOW, LOW, HIGH },
{ HIGH, LOW, LOW, LOW },
{ HIGH, HIGH, LOW, LOW },
{ LOW, HIGH, LOW, LOW }
};
void rotate(int step) {
static int phase = 0;
int i, j;
int delta = (step > 0) ? 1 : 7;
step = (step > 0) ? step : -step;
for (j = 0; j < step; j++) {
phase = (phase + delta) % 8;
for (i = 0; i < 4; i++) {
digitalWrite(port[i], seq[phase][i]);
}
delay(delaytime);
}
// power cut
for (i = 0; i < 4; i++) {
digitalWrite(port[i], LOW);
}
}
void pressed(Button2& btn) {
while (digitalRead(12) == LOW) {
delaytime = 2;
rotate(68);
}
delaytime = 10;
}
#define ENCODER_CLK 2
#define ENCODER_DT 3
void readEncoder() {
int dtValue = digitalRead(ENCODER_DT);
if (dtValue == HIGH) {
Serial.println("Rotated clockwise ⏩");
delaytime = 2;
rotate(68);
delaytime = 10;
}
if (dtValue == LOW) {
Serial.println("Rotated counterclockwise ⏪");
delaytime = 2;
rotate(-68);
delaytime = 10;
}
}
int prevMin = 0;
int thisMin = 0;
DateTime now;
void setup() {
Serial.begin(9600);
pinMode(port[0], OUTPUT);
pinMode(port[1], OUTPUT);
pinMode(port[2], OUTPUT);
pinMode(port[3], OUTPUT);
pinMode(14, OUTPUT);
digitalWrite(14, LOW);
pinMode(16, INPUT_PULLUP);
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
if (!rtc.begin()) {
Serial.println(F("Couldn't find RTC"));
while (1)
;
}
button.begin(BUTTON_PIN);
button.setPressedHandler(pressed);
// following line sets the RTC to the date & time this sketch was compiled
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); //uncomment to set time, then recomment and reupload
//rtc.adjust(DateTime(2023, 8, 16, 0, 15, 0)); // YYY, MM, DD, HH, MM, SS
now = rtc.now();
Serial.print(now.hour());
Serial.println(" hr");
Serial.print(now.minute());
Serial.println(" min");
// Doesn't work - won't rotate the full number of times to set the intial time from midnight, stops at just over 2 rotations
// unsigned long initStepper = (now.hour() * 60 + now.minute()) * STEPS_PER_REV / 60;
// Serial.print(initStepper);
// Serial.println(" initial stepper pos");
// rotate(initStepper);
prevMin = now.minute();
thisMin = prevMin;
int delaytime = 10;
}
int interval = 1000;
unsigned long lastmilli = 0;
long steps = 0;
int incr = 0;
void loop() {
unsigned long thismilli = millis();
button.loop();
if (thismilli - lastmilli > interval) {
lastmilli = thismilli;
now = rtc.now();
thisMin = now.minute();
//Serial.print(thisMin); Serial.println(" thisMin");
}
if (thisMin != prevMin) {
prevMin = thisMin;
Serial.print(thisMin);
Serial.println(" mins");
// if stepper to min hand is 1:1 then each min = 68.26666... steps (4096/60).
// therefore move 68 steps each time, then on the 15th time, move an extra 4 steps (15*.2666666)
if (thisMin % 15 == 0) {
incr = 72;
} else {
incr = 68;
}
Serial.print(incr);
Serial.println(" incr");
rotate(incr);
steps += incr;
Serial.print(steps);
Serial.println(" steps");
Serial.println();
// if stepper to min hand has a 4:1 ratio (4 stepper motor rotor rotations per 1 min increment) then
// each 1 min tick would require 68.266666 * 4 steps = 273.0666666... steps. So a correction of 4 steps would
// be needed at each full rotation (1 hr | .06666 * 60 = 4) instead of each 15 min.
}
}