#define MILLIS_PER_MIN 59913 // milliseconds per minute - lower number make clock run faster.
#define ROTATION_PERIOD_IN_MSEC 10000 // update clock every 10 sec
// Motor and clock parameters
#define STEPS_PER_ROTATION 4096 // steps of a single rotation of motor
//#define RATIO 15 // min per a rotation / gear ratio between stepper and min gear (60 min per rotation / Gear Ratio of 4)
#define RATIO 60 // min per a rotation / gear ratio (60 min per rotation / Gear Ratio of 1 if stepper is directly driving min hand)
#define LAP 65536 // value to avoid overflow of long int
// wait for a single step of stepper
int delaytime = 10;
// ports used to control the stepper motor
// if your motor rotate to the opposite direction,
// change the order as {4, 5, 6, 7};
int port[4] = { 7, 6, 5, 4 };
//int port[4] = { 4, 5, 6, 7 };
// sequence of stepper motor control
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) {
Serial.begin(115200);
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 setup() {
pinMode(port[0], OUTPUT);
pinMode(port[1], OUTPUT);
pinMode(port[2], OUTPUT);
pinMode(port[3], OUTPUT);
pinMode(14, OUTPUT);
digitalWrite(14, LOW);
}
void loop() {
static long prev_msec, prev_pos;
long msec, pos;
msec = millis() % LAP; // msec = remainder of millis / LAP
// only executed until do rotation is triggered
if (msec < prev_msec) { // Laps around after msec exceeds LAP and until prev_msec can be update by rotation loop
msec += LAP; // hide lap around temporarily - adds back until entering the do rotation loop
}
// do rotation
if (msec >= prev_msec + ROTATION_PERIOD_IN_MSEC) {
pos = calc_step(msec);
Serial.print("pos: ");Serial.println(pos);
rotate(pos - prev_pos);
Serial.print("Not Lapped: "); Serial.println(msec);
if (msec >= LAP) { // Laps around msec and pos
msec %= LAP; //sets msec to remainer of msec / LAP
pos = calc_step(msec); //resets pos lapped msec
Serial.print("Lapped: ");Serial.println(msec);
}
prev_pos = pos;
prev_msec = msec;
}
}
long calc_step(long msec) {
/*
Convert msec to steps w/ 4:1 ratio (1 stepper gear rotation = 1/4 gear rotation of min hand = 15 min)
n msec 4096 steps * 4
---------- * ----------------- = steps
msec / min 60 min
if directly driving the min hand, then each 10000 ms computes to 11.37 steps. But the stepper cannot move .37, so this is lost every 10 seconds.
the actual steps per rotation is 4076 according to the article refenced above. Using that results in 11.34, so a bit less error.
this adds up to 2.03 steps error 60 sec. only 66 steps are commanded per min and 68 (67.93) should have been commanded.
*/
//return STEPS_PER_ROTATION * msec / MILLIS_PER_MIN / RATIO;
return STEPS_PER_ROTATION / RATIO * msec / MILLIS_PER_MIN; // be carefull of order of operation - fractional result become zero with integers
}