I'm an Arduino novice but have dabbled in electronics and Basic programming for some time.
The Project: I want to drive a 3D printed clock with a 28BYJ-48 stepper. The stepper is driven by a ULN2003 driver board connected to an Arduino Nano. And I'm using a DS3231 RTC to provide timing updates to keep the clock accurate. Preliminary testing suggests it should all work fine. The motor has enough torque (we'll see about longevity).
The Problem: The Arduino gets updated seconds from the RTC. Every time the Arduino gets an incremented second from the RTC, it drives the motor enough steps to spin the seconds wheel 6 degrees (or 1 second). Of course, the 4096 steps/rev for the motor is not exactly divisible by 360 degrees, so I have to add steps here and there to get the total step count up to 4096. But after 60 RTC signals, one per second, the seconds wheel on the stepper motor is always about 4 seconds slow regardless of how fast I drive the motor. I'm using the AccelStepper library to control step speed and number of steps. If I set up a sketch to continuously drive the motor 4096 steps, it correctly runs the full 360 degree revolution. It only comes up short when I drive the motor in 1 second bursts. Everything works as expected except that it takes 64 seconds from the RTC, instead of the expected 60, to cause a full revolution of the stepper motor.
All my calculations are described in remarks in the code. So am I losing steps? Because of the motor or the coding? Is my use of the AccelStepper library or the RTC flawed? Any suggestions would be welcome.
Here's the code:
```cpp
/* Sketch is meant to control the "ticking" of the "seconds" wheel of a 3D printed clock driven by a 28BYJ-48
stepper motor. The stepper motor is driven by a ULN2003 driver board connected to an Arduino Nano. The
Nano gets seconds timing from a DS3231 RTC*/
#include "AccelStepper.h"
#include <Wire.h>
#include <RTClib.h>
// Variable declarations
int oldSecs = 0;
int newSecs = 0;
int steps = 68;
int stepSpeed = 750;
// RTC declaration
RTC_DS3231 rtc;
// Motor pin definitions (Motor Pins are the digital pin numbers on Arduino):
#define motorPin1 8 // IN1 on the ULN2003 driver
#define motorPin2 9 // IN2 on the ULN2003 driver
#define motorPin3 10 // IN3 on the ULN2003 driver
#define motorPin4 11 // IN4 on the ULN2003 driver
// Define the AccelStepper interface type; 4 wire motor in half step mode:
#define MotorInterfaceType 8
// Initialize stepper and pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper library
AccelStepper stepper = AccelStepper(MotorInterfaceType, motorPin1, motorPin3, motorPin2, motorPin4);
void setup() {
// Start the serial interface
Serial.begin(57600);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1) delay(10);
}
// Set the maximum steps per second:
stepper.setMaxSpeed(750);
// Set oldSec to current seconds from RTC
DateTime now = rtc.now();
oldSecs = now.second();
//Serial.println(oldSecs);
}
void loop() {
// Set newSecs to current seconds from RTC. For first iteration newSecs = oldSecs
DateTime now = rtc.now();
newSecs = now.second();
//Serial.println(newSecs);
// If a second has passed, rotate the motor
if (newSecs != oldSecs) {
// Adjust oldSecs for next iteration
oldSecs = newSecs;
// Print an indicator to signal a rotatation is expected
//Serial.println("rotate");
// Set the number of steps for this iteration of a "second"
// Approximate steps per second:
// The 28BYJ-48 motor does 4096 microsteps per full revolution
// 4096 steps/360 degrees x 6 degrees/second = 68.2666... steps/second
// 68 steps x 60 seconds = 4080 steps.
// Spread remaining 16 steps (4096 - 4080 = 16) over the full 60 second period
// Every 4th second do 69 steps (instead of 68) to use 15 (60/4 = 15) of the steps
// On the 60th second do 70 steps to make total step count = 4096
// 68*45 + 69*14 + 70*1 = 4096
steps = 68;
if (newSecs % 4 == 0) steps = 69;
if (newSecs == 0) steps = 70;
// Set the stepper speed to a value, under 750, that will cause ~6 degrees (1 second) of
// rotation in ~100ms.
stepSpeed = steps * 10;
// Reset the current motor position to 0:
stepper.setCurrentPosition(0);
// Print value to confirm correct variable values
//Serial.print(newSecs);
//Serial.print(" : ");
//Serial.print(steps);
//Serial.println();
// Rotate the motor the required number of steps
while (stepper.currentPosition() != steps) {
stepper.setSpeed(stepSpeed);
stepper.runSpeed();
}
}
}