OrreryDriver/Firmware/orreryDriver.ino
2026-02-09 16:56:11 -08:00

283 lines
6.4 KiB
C++

// defines pins
#define stepPin 3
#define dirPin 4
#define potPin 0
#define buttonPin 7
#define motorEnablePin 10
#include "RTClib.h"
#include <AccelStepper.h>
#include <TM1637.h>
#include <Preferences.h>
unsigned int oldVal;
// Define variables for timing
unsigned long lastUpdate = 0;
const int updateInterval = 100; // Update display every 100ms
const unsigned long rtcSyncInterval = 600000; // 172 seconds in milliseconds
unsigned long lastRtcSync = 0;
unsigned long lastDebugTime = 0;
const int debugInterval = 500; // Only check RTC/Print every 500ms
//motor values
uint32_t totalSecondsinYear = 31536000;
//uint32_t fullRotationMotorSteps = 194400;
uint32_t fullRotationMotorSteps = 183348;
bool isCalibrated = false;
bool homingComplete = false;
bool realTime = false;
int count=0;
long targetPos;
//inititate EEPROM with preferences library
Preferences preferences;
// Instantiation and pins configurations
// Pin 2 - > DIO
// Pin 1 - > CLK
TM1637 tm(1, 2);
TM1637 tm2(5, 6);
int potValue = 0;
RTC_DS3231 rtc;
AccelStepper stepper1(1, stepPin, dirPin);
//define state machine
enum {calibrationMode, manualMode, realTimeMode};
unsigned char machineState;
void setup() {
pinMode(buttonPin, INPUT_PULLDOWN);
pinMode(motorEnablePin,OUTPUT);
Serial.begin(115200);
//preferences.begin("persistent-mem", false);
//oldVal = preferences.getUInt("oldVal", 0);
tm.init();
tm2.init();
tm.setBrightnessPercent(5);
tm2.setBrightnessPercent(5);
rtc.begin();
// rtc.adjust(DateTime(2026, 4, 1, 12, 0, 0));
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
stepper1.setMaxSpeed(4000);
stepper1.setAcceleration(500);
stepper1.setSpeed(4000);
//enable motor
digitalWrite(motorEnablePin ,LOW);
}
void loop()
{
switch (machineState){
case calibrationMode:
calibrateOrrery();
break;
case realTimeMode:
if (digitalRead(buttonPin) == HIGH){
tm.display("real");
tm2.display("time");
realTime=true;
updateMotor();
Serial.println("Real time switch");
}
if (realTime && (millis() - lastRtcSync >= rtcSyncInterval)) {
lastRtcSync = millis();
updateMotor(); // Calculates new targetPos based on RTC
Serial.println("Periodic RTC Sync Triggered");
}
manualControl(isCalibrated);
break;
case manualMode:
break;
default:
Serial.println("Default Mode");
// first check if theres state in memorty
if(oldVal == 0){
machineState = calibrationMode;
}else{
stepper1.setCurrentPosition(oldVal);
isCalibrated = true;
realTime=true;
updateMotor();
machineState = realTimeMode;
}
}
}
void calibrateOrrery(){
if (digitalRead(buttonPin) == HIGH && !homingComplete) {
tm.display("clbr");
tm2.display("set");
stepper1.setCurrentPosition(1500);
updateMotor();
homingComplete = true;
}
else if(!homingComplete) {
tm.display("clbr");
tm2.display("reqd");
manualControl(isCalibrated);
}
else{
if (stepper1.distanceToGo() == 0){
isCalibrated = true;
machineState = realTimeMode;
tm.display("done");
realTime = true;
Serial.println("DONE");
}
}
}
long currentMotorPos(){
DateTime now = rtc.now();
DateTime newYear(2026, 1, 1, 0, 0, 0);
uint32_t nowUnixTime = now.unixtime();
uint32_t newYearUnixTime = newYear.unixtime();
uint32_t secondsSinceNewYear = nowUnixTime - newYearUnixTime;
uint32_t motorPosRT = (uint64_t) secondsSinceNewYear * fullRotationMotorSteps / totalSecondsinYear;
// preferences.putUInt("oldVal", motorPosRT);
return motorPosRT;
}
void manualControl(bool calibrated){
potValue = analogRead(potPin);
potValue = map(potValue, 0, 4095, 3000, -3000);
if(potValue > -900 && potValue<300){
}else{
stepper1.setSpeed(potValue);
stepper1.runSpeed();
realTime=false;
}
if (calibrated && (millis() - lastUpdate >= updateInterval)) {
lastUpdate = millis();
if (realTime) {
displayTime(rtc.now());
} else {
displayTime(simulatedTime(stepper1.currentPosition()));
}
}
}
void displayTime(DateTime timeObject) {
char timeStr[10]; // Buffer to hold the formatted string
int h = timeObject.hour();
int m = timeObject.minute();
// Determine if we show the dot (colon)
bool showDot = (millis() / 1000) % 2;
bool screenUpdate = (millis() / 500) % 2;
if(realTime){
if (showDot) {
snprintf(timeStr, sizeof(timeStr), "%02d.%02d", h, m);
} else {
snprintf(timeStr, sizeof(timeStr), "%02d%02d", h, m);
}
if (screenUpdate) {
tm.display(String(timeStr));
tm2.display(formatDate(timeObject.month(), timeObject.day()));
}
} else {
tm.display((int)timeObject.year());
tm2.display(formatDate(timeObject.month(), timeObject.day()));
//tm.display(timeStr);
}
}
DateTime simulatedTime(long motorPosition) {
uint32_t secondsSince2026 = (uint32_t)((uint64_t)totalSecondsinYear * motorPosition / fullRotationMotorSteps);
return DateTime(DateTime(2026, 1, 1, 0, 0, 0).unixtime() + secondsSince2026);
}
String formatDate(int month, int day) {
String months[] = {"Ja", "Fe", "mr", "Al", "ma", "Jn","Jl", "Au", "Se", "Oc", "No", "De"};
String dayStr = (day < 10) ? "0" + String(day) : String(day);
String monthStr = months[month - 1];
return monthStr + dayStr;
}
int motorStep2seconds(int motorStep){
// return motorStep*1460.0/9.0;
return motorStep*172;
}
void updateMotor(){
targetPos = currentMotorPos();
stepper1.moveTo(targetPos);
Serial.print("Target updated to: ");
Serial.println(targetPos);
Serial.print("Current Pos: ");
Serial.print(stepper1.currentPosition());
Serial.print(" Distance to go: ");
Serial.println(stepper1.distanceToGo());
Serial.println("RUNING!");
stepper1.runToPosition();
Serial.print("Current Pos: ");
Serial.print(stepper1.currentPosition());
Serial.print(" Distance to go: ");
Serial.println(stepper1.distanceToGo());
Serial.println("DONE!!");
}
void updateMotorManual(){
manual
stepper1.moveTo(97200);
Serial.print("Target updated to: ");
Serial.println(targetPos);
Serial.print("Current Pos: ");
Serial.print(stepper1.currentPosition());
Serial.print(" Distance to go: ");
Serial.println(stepper1.distanceToGo());
Serial.println("RUNING!");
stepper1.runToPosition();
Serial.print("Current Pos: ");
Serial.print(stepper1.currentPosition());
Serial.print(" Distance to go: ");
Serial.println(stepper1.distanceToGo());
Serial.println("DONE!!");
}