Nebenuhr mit Arduino steuern

Hallo,
da ich selber nicht wirlich fündig geworden bin, möchte ich hier meine Lösung für die Ansteuerung einer 24V Nebenuhr vorstellen. Vielleicht hilft es ja jemanden.

Benutzt habe ich einen Arduino pro mini, der ein H-Bücke ansteuert. Die 24V gewinne ich mittels Step-Up aus der 5…12V Versorgungsspannung. Nach etwas Optimierung der Variablen “lngInterval” habe ich eine Genauigkeit von -3ms/min erreicht.

Der Taster dienst zum manuellen verstellen der Uhr und zur Synchronisation beim Start.

#include <Bounce2.h>
const byte IN1_PIN = 8;             //Ansteuerung der H-Brücke
const byte IN2_PIN = 9;             //Ansteuerung der H-Brücke
const byte BTN_PIN = 10;            //Taster zum stellen der Uhr
bool bolstatus = false;
bool bolBtnState = false;
unsigned long previousMillis = 0;
unsigned long lngBtnTimeStamp = 0;
const long lngInterval = 59865;     //ms pro Minute - genauen Wert austesten
const long Impuls = 100;            //Schaltdauer für Spule der Uhr

Bounce debouncer = Bounce(BTN_PIN, 5);

void setup() {
  pinMode(IN1_PIN, OUTPUT);
  pinMode(IN2_PIN, OUTPUT);
  pinMode(BTN_PIN, INPUT_PULLUP); 
  Serial.begin(9600);
  Serial.println("Aug. 2020 by Skalar");
}

void loop() {
  //Takt wenn "lngInterval" abgelaufen ist
  if (millis() - previousMillis >= lngInterval) {
    ClockMove();
  }

  //Behandlung des Tasters
  bool btnChanged = debouncer.update();

  if (btnChanged) {
    if ( debouncer.read() == LOW) {
      bolBtnState = true;
      //Serial.println("Button down");
      lngBtnTimeStamp = millis();
      ClockMove();
    }
    else {
      bolBtnState = false;
    }
  }

  if  (bolBtnState) {
    if ( millis() - lngBtnTimeStamp >= 300 ) {
      //Serial.println("Button pressed");
      lngBtnTimeStamp = millis();
      ClockMove();
    }
  }
}

// Minutenzeiger 1mal bewegen 
void ClockMove() { 
  bolstatus = !bolstatus;
  digitalWrite(IN1_PIN, !bolstatus);
  digitalWrite(IN2_PIN, bolstatus);
  delay(Impuls);
  digitalWrite(IN1_PIN, LOW);
  digitalWrite(IN2_PIN, LOW);
  previousMillis = millis();
}

Moin,

Skalar:
Nach etwas Optimierung der Variablen "lngInterval" habe ich eine Genauigkeit von -3ms/min erreicht.

const long lngInterval = 59865;     //ms pro Minute - genauen Wert austesten

void loop() {
 //Takt wenn "lngInterval" abgelaufen ist
 if (millis() - previousMillis >= lngInterval) {
   ClockMove();
 }

// Minutenzeiger 1mal bewegen
void ClockMove() {
 bolstatus = !bolstatus;
 digitalWrite(IN1_PIN, !bolstatus);
 digitalWrite(IN2_PIN, bolstatus);
 delay(Impuls);
 digitalWrite(IN1_PIN, LOW);
 digitalWrite(IN2_PIN, LOW);
 previousMillis = millis();
}

Du kannst die Genauigkeit OHNE langwierig auszutesten, welcher Wert für lngInterval notwendig ist, verbessern.

Du initialisierst lngIntervalmit 60000.

In ClockMove() löscht Du die Zeile:
previousMillis=millis();

Dafür änderst Du

 if (millis() - previousMillis >= lngInterval) {
   ClockMove();
 }

in

  if (millis() - previousMillis >= lngInterval) {
   previousMillis+=lngInterval;
   ClockMove();
 }

Sinn der Änderung ist, das die Länge des Durchlaufes von loop() und der Funktionen keinen Einfluß mehr hat und sich eine Abweichung nicht aufaddiert.

Danke für die Arbeit :slight_smile:

Mich würde noch interessieren, welche Signale die Uhr genau benötigt, und was die beiden Pins der H-Brücke schalten - üblicherweise sind die doch meist mit Dir und Duty oder Input und Enable bezeichnet.

DrDiettrich:
Mich würde noch interessieren, welche Signale die Uhr genau benötigt, und was die beiden Pins der H-Brücke schalten - üblicherweise sind die doch meist mit Dir und Duty oder Input und Enable bezeichnet.

Das sollte ein Syncronmotor sein. Verwendet wie in einer Bahnhofsuhr.

Sinn...ist, dass die Länge des Durchlaufes...keinen Einfluß hat und sich eine Abweichung nicht aufaddiert.

Danke für's Feedback - Arbeit war es ja nicht sondern Spaß
Deine vorgeschlagene Änderungen würden nicht helfen, denke ich:

  1. previousMillis=millis() in ClockMove() brauche ich für den Taster, um die Uhr zu einem bestimmten Zeitpunkt zu starten und ab da die 60s zu zählen. Wenn ich die Uhr z.B. auf 12:00:00 stellen möchten, dann stelle ich die Zeiger auf 11:59 und drücke den Taster 1 mal, wenn die Referenzuhr auf 12:00:00 springt.

  2. auch mit der Variante previousMillis+=lngInterval und lngInterval=60000 addiert sich der Fehler auf, denn 60.000 millis() sind eben nicht 60,000s. Je nach Genauigkeit des Quarzes und der Fertigungstoleranz des 328p gibt es einen anderen Wert.

Im normalen Betrieb verzweigt die loop() nicht und ist zeitlich somit sehr homogen. Langwierig war das Austesten nicht. Die RWTH Aachen hat eine fantastische App namens "phyphox" in der auch eine "Akustische Stoppuhr" enthalten ist. Man muss nur das Handy auf die Uhr legen und die App misst die Rundenzeiten beim Tick des Zeigers automatisch. Nach 4x5min hatte ich den optimalen Wert. Im Bild "Optimierung.jpg" ist die App mit etwa 330 Messungen zu sehen und ein durchschnittliches Intervall von 59,997 s/min.

DrDiettrich:
Mich würde noch interessieren, welche Signale die Uhr genau benötigt, und was die beiden Pins der H-Brücke schalten - üblicherweise sind die doch meist mit Dir und Duty oder Input und Enable bezeichnet.

Das Werk ist ein Lavet-Schrittmotor. Durch den Wechsel der Polaritär an der Spule wird der Rotor um jeweis 180° gedreht. Es geht nur vorwärts. Die Spule braucht 24V für mindestens 0,1s.

PS100.jpg