Forum: Mikrocontroller und Digitale Elektronik Bitte verschieben! Schon wieder ne Uhr!


von Micha W. (blackxiiv)


Angehängte Dateien:

Lesenswert?

Hi,
Meiner einer baut sich eine Uhr. Nun ist meine Ausbildung (EGS) knapp 10 
Jahre her und damals hatten wir "nur" ein PIC16F84, den wir mit 
Assembler programmieren durften. Vor einigen Monaten habe ich von einem 
Freund/Kollegen einen Arduino Nano bekommen. Nun benutze ich als 
Anzeigeelemente für meine Uhr Nixie-tubes. Bedeutet: Wenn ich kein 
Multiplexing betreiben will/kann(!) brauche ich einen Expander - etwa in 
Form eines Schieberegisters. Ansteuerung läuft!
Da ich etwa vor 2 Wochen mit meinem Arduino angefangen habe zu spielen 
und ein paar grundlegende Sachen erkundet und hoffentlich verstanden 
habe, war es nun an der Zeit für meine SEHR primitive Uhr.
Hierzu sei gesagt, dass der "Code" meinen eigenen gedanken entsprungen 
ist - und da es nur eine Uhr sein soll ist es wohl ziemlich egal wie 
performant der Code ist oder was man mir sonst vorwerfen kann. Die 
Routinen habe ich natürlich gegooglt und angepasst.
Jetzt kommt's! Mein Schieberegister wird ordentlich angesteuert ABER aus 
meinem DataPin kommen offensichtlich nur 1-en raus. Habe im Code die 
Gegenprobe gemacht und es kommen auch 0-en raus wenn ich meine 
Ausgangsbedingung ändere.
Ich habe den verdacht, dass:
1. meine Zeit nicht hochzählt
2. meine kleine "Bibliothek" falsch programmiert ist

Ich gebe wie gesagt seriell auf ein Schieberegister aus. 38Sekunden 
würden dann in 16Bit so aussehen:
 Zehner         Einer
0,1,2,3,4,5 / 0,1,2,3,4,5,6,7,8,9
0,0,0,1,0,0 / 0,0,0,0,0,0,0,0,1,0  Das sollte nach einem Durchlauf im 
Schieberegister stehen.

Wie gesagt - Ich bekomme nur 1-en oder 0-en aus meinem DataPin.

Achja - Ich versuche BitShifting zu nutzen, um mein Muster seriell 
ausgeben zu können!
Das würde erklären warum nur 1-en rauskommen wenn meine "Bibliothek" 
nicht funktioniert und/oder der Counter nicht läuft

Code: (Bitte nicht kürschnern!)
1
int data = 10;                      // init declare pins for shift register
2
int clk = 8;
3
int latch = 9;
4
int clr = 7;
5
6
7
void setup() {
8
  pinMode(data, OUTPUT);            //set pin mode
9
  pinMode(clk, OUTPUT);
10
  pinMode(latch, OUTPUT);
11
  pinMode(clr, OUTPUT);
12
13
  digitalWrite(clr, LOW);           //init clear all outputs of shift register
14
  digitalWrite(latch, LOW);
15
  digitalWrite(latch, HIGH);
16
  digitalWrite(clr, HIGH);
17
  delay(500);
18
}
19
20
void loop() {
21
22
23
int sec;                        // Uhr Counter
24
int minu;
25
int hour;
26
int sec1;
27
int sec2;
28
int sech;
29
int minu1;
30
int minu2;
31
int minuh;
32
int hour1;
33
int hour2;
34
int hourh;
35
int data1;
36
37
38
sec = sec++;
39
delay(100);
40
  if (sec >= 60) {
41
    sec = 0;
42
    minu++;
43
    }
44
      if (minu >= 60) {
45
        minu = 0;
46
        hour++;
47
        }
48
          if (hour >= 24) {
49
            hour = 0;
50
            }
51
52
     // Sekunden
53
     
54
55
for (int i=0; i<6; i++) {         // 10er ins Register schieben (6 Stellen)
56
57
sec2 = sec / 10;                    //Zehner ausrechnen
58
sec1 = sec - sec2 * 10;             //Einer ausrechnen
59
60
  switch (sec2) {                   //Muster für 10er auswählen
61
    case 0: sech = 1;
62
    case 1: sech = 2;
63
    case 2: sech = 4;
64
    case 3: sech = 8;
65
    case 4: sech = 16;
66
    case 5: sech = 32;
67
}
68
69
      digitalWrite(latch, LOW);
70
      digitalWrite(clk, LOW);
71
      data1 = sech && 1;
72
      if (data1 = 0) {
73
      digitalWrite(data, LOW);;
74
      }
75
      else digitalWrite(data, HIGH);
76
      sech = sech >> 1;
77
      digitalWrite(clk, HIGH);
78
      digitalWrite(latch, HIGH);
79
      delay(500);
80
      }
81
82
    delay(1000);
83
   
84
  switch (sec1) {                   //Muster für 1er auswählen
85
    case 0: sech = 1;
86
    case 1: sech = 2;
87
    case 2: sech = 4;
88
    case 3: sech = 8;
89
    case 4: sech = 16;
90
    case 5: sech = 32;
91
    case 6: sech = 64;
92
    case 7: sech = 128;
93
    case 8: sech = 256;
94
    case 9: sech = 512;
95
}
96
  for (int i=0; i<10; i++) {       // 1er ins register schieben (10 Stellen)
97
      digitalWrite(latch, LOW);
98
      digitalWrite(clk, LOW);
99
      data1 = sech & 1;
100
      if (data1 = 1) {
101
      digitalWrite(data, HIGH);
102
      }
103
      else digitalWrite(data, LOW);
104
      sech = sech>>1;
105
      digitalWrite(clk, HIGH);
106
      digitalWrite(latch, HIGH);
107
      delay(500);
108
      }
109
    delay(1000);
110
  digitalWrite(clr, LOW);           //init clear all outputs of shift register
111
  digitalWrite(latch, LOW);
112
  digitalWrite(latch, HIGH);
113
  digitalWrite(clr, HIGH);
114
  delay(500);
115
}

Die vielen und langen Delays sind zum Debuggen. Mein Shieberegister hat 
an jedem Output eine LED.

*edit: Für Minuten und Stunden ist die Ausgabe-Routine die gleiche. Ist 
aber im Moment im Code auskommentiert. Der Arduino lebt mit einem 
AtMega328P.

Vielen Dank für die Aufmerksamkeit!
Gruß Micha (:

: Verschoben durch Moderator
von icke (Gast)


Lesenswert?

Welches Schieberegister benutzt du.
Für 595er gibt es schon eine fertige Funktion.
https://www.arduino.cc/en/Tutorial/ShiftOut

von Micha W. (blackxiiv)


Lesenswert?

Ja, benutze ich. Ich habe schon Testprogramme, in denen ich Muster aus 
Arrays auslese und übergebe. Das funktioniert. Selbst wenn der wert für 
Einer und Zehner immer Null bleibt, sollte mein Register 0x0401 
anzeigen. Es kommen aber nur 1-en aus dem DataPin und somit habe ich 
immer 0xFFFF

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Forum: Projekte & Code
Hier könnt ihr eure Projekte, Schaltungen oder Codeschnipsel vorstellen 
und diskutieren. Bitte hier keine Fragen posten!

von Stefan F. (Gast)


Lesenswert?

Nächstes mal bitte korrekt einrücken!
1
if (data1 = 1)

Das ergibt immer true, darum schiebt er immer nur einsen raus.

Korrektur:
1
if (data1 == 1)

von Micha W. (blackxiiv)


Lesenswert?

Danke!
Jetzt bekomm ich für meine Einer-Stelle schon mal ne 0 raus. also auf 
16Bit:
 Zehner     /      Einer
1,1,1,1,1,1 / 0,0,0,0,0,0,0,0,0,1 Schieberegister
5,4,3,2,1,0 / 9,8,7,6,5,4,3,2,1,0

Was mich zu dem Schluss bringt, dass mein Zähler nicht läuft ;/

von P. M. (mikro23)


Lesenswert?

Micha W. schrieb:
> void loop() {
>
> int sec;                        // Uhr Counter

Eine lokale Variable, die am Anfang einer Funktion deklariert wird, hört 
am Ende derselben auf zu existieren.

von Micha W. (blackxiiv)


Lesenswert?

Ich habe sie mal global gesetzt. Ändert aber nicht. Ich bleibe Ja im 
"void loop ()" wenn ich das richtig sehe. das setup wird vom Controller 
nur 1 mal ausgeführt.
Danke trotzdem für die Idee!

von P. M. (mikro23)


Lesenswert?

Micha W. schrieb:
> Ich bleibe Ja im
> "void loop ()" wenn ich das richtig sehe.

Ich sehe keinen Funktionsaufruf. Die Funktion muß ja einmal pro Sekunde 
aufgerufen werden, damit die Zeit hochgezählt werden kann.

von Christopher C. (trihexagon)


Lesenswert?

Micha W. schrieb:
> switch (sec1) {                   //Muster für 1er auswählen
>     case 0: sech = 1;
>     case 1: sech = 2;
>     case 2: sech = 4;
>     case 3: sech = 8;
>     case 4: sech = 16;
>     case 5: sech = 32;
>     case 6: sech = 64;
>     case 7: sech = 128;
>     case 8: sech = 256;
>     case 9: sech = 512;
> }

Warum machst du nicht einfach einen Linksshift?
1
sech = (1 << sec1);

Micha W. schrieb:
> int data = 10;                      // init declare pins for shift
> register
> int clk = 8;
> int latch = 9;
> int clr = 7;

Konstanten definiert man in C über den Präprozessor.
1
#define DATA 10
2
#define CLK 8
3
#define LATCH 9
4
#define CLR 7

von Micha W. (blackxiiv)


Lesenswert?

Im moment arbeitet das Programm sequenziell alles ab und löscht am Ende 
das Schieberegister.
So wie ich es sehe springt das Programm wieder nach
1
void loop()
rein.
Sehe ich das falsch und mein Programm beginnt in Zeile eins und 
initialisiert alle Variablen wieder mit 0?
Dann sollte trotzdem der Sekundenzeiger bei 1 und nicht 0 stehen. Und 
ungeklärt ist, warum mein Zehner mir ständigen 1-en auswirft :/
das mit & und && habe ich berichtigt.

von Micha W. (blackxiiv)


Lesenswert?

Das switch/case war "so ausgedacht". Ich bin mir bewusst dass es 
eleganter geht.

Das Definieren habe ich so aus einem Beispiel übernommen. Ich benutze 
wie gesagt einen Arduino und die damit verbundene Software und die 
Beispiele. Trotzdem Danke für den Anstoß!

von P. M. (mikro23)


Lesenswert?

Micha W. schrieb:
> sec = sec++;

sec wird an sec zugewiesen und DANACH incrementiert (und dann verworfen)
1
sec++;
reicht

: Bearbeitet durch User
von Micha W. (blackxiiv)


Lesenswert?

Ich habe Minuten und Stunden mal eingebunden und angepasst.
Was auf meinem Schieberegister nach vollem durchlauf passiert:
Zehner / Einer Sekunden
000000/0000000001
Zehner / Einer Minuten
000001/0000000001
Zehner / Einer Stunden
000001/0000000001

Mein Uhr würde jetzt anzeigen: 00:00:"nichts"0
Also habe ich noch ein Problem mit dem ersten Aufruf der Zehnerstelle 
für die Sekunden.

: Bearbeitet durch User
von Micha W. (blackxiiv)


Lesenswert?

Ich hab's!... Jetzt zeigt mein Register das richtige an! 00:00:00...

Jetzt bleibt die Frage warum der Knilch nicht hochzählt....

von JJ (Gast)


Lesenswert?

Hallo
Meine C-Kenntnisse sind nicht auf dem neuesten Stand.
Aber fehlt hinter jedem case nicht das break?
Gruß
JJ

von Micha W. (blackxiiv)


Lesenswert?

Ich bin soooooooooooo ein Holzkopf....

*APPLAUS!!!!*

Läuft! Läääuuffttt!!!! WoW!

von Micha W. (blackxiiv)


Lesenswert?

Jetzt kommt der nächste Part. Ich traue mich noch nicht an DCF-77 und 
RTC heran.
Ich habe einen 1Hz Counter gebaut der 2,3ppm hat - sind ca 6 Sekunden 
Abweichung pro Monat (30Tage). Damit kann ich sehr wohl leben und ist ja 
gar nicht schlimm.
Der Code ist performant genug um ihn in weniger als einer Sekunde 
auszuführen und auf meine Anzeige auszugeben.
Kann ich meinen 1Hz Counter einfach an einen Digital Port anschließen 
und Diesen als Interrupt deklarieren (mit Option auf Priorität, wegens 
händischer Einstellung der Grund-Zeit)und damit meine Routine ein mal 
ausführen (Sekunde++)?

von Stefan F. (Gast)


Lesenswert?

loop() ist keine Endlosschleife, sondern eine normale Funktion, die vom 
Arduino Framework aus einer Endlosschleife heraus aufgerufen wird. 
Stelle Dir das Arduino Framework so vor:
1
int main()
2
{
3
   interne_initialisierungen;
4
   setup();
5
   while (1)
6
   {
7
       interne_Aufgaben;
8
       loop();
9
   }
10
}

von Micha W. (blackxiiv)


Angehängte Dateien:

Lesenswert?

Hi,

Bin mal wieder dazu gekommen an der Uhr zu arbeiten.
Hinzugekommen sind der 1Hz Counter und 4 Buttons zum Stellen. Die Uhr 
wird mit einem Button angehalten und mit den 3 anderen gestellt. Das 
Stellen wird auch direkt ausgegeben und man kann im Code die Druckdauer 
zwischen einmaligem Hochzählen und dauerndem Hochzählen einstellen. 
Jeweils für Stunden, Minuten und Sekunden ohne beim Überschreiten die 
jeweils nächste Stelle zu beeinflussen (bei 59+ Sekunden bleiben die 
Minuten stehen und die Sekunden fangen bei 0 wieder an).
Der 1Hz Counter ist realisiert mit einem 2,048MHz Oszillator, wessen 
Signal dann durch einen HEF4060 läuft bis ich 500Hz (2^11 glaube ich :/ 
)habe und dann x2 74390 bis ich zu 1Hz komme ( (500 / 2x10) / 5). Der HP 
Frequency Counter auf Arbeit hat mir 1,000.002.3 Hz ausgespuckt, was 
ungefähr 6,2 Sekunden Ungenauigkeit auf 31 Tage einbringt.
Das 150V DC Netzteil für meine Anzeigeröhren ist fast fertig und dann 
fehlt noch das MOSFET Array um sie anzusteuern. Bilder gibts dann davon 
natürlich!

Schönen Abend noch,
Micha

von Micha W. (blackxiiv)


Lesenswert?

Kann ein Moderator bitte den Titel Ändern in "Schon wieder ne Uhr!". 
Habe damals den Thread in einem Falschen Forum gepostet und dann das 
"Bitte Verschieben!" hinzugefügt. Lässt sich jetzt nicht mehr Ändern.
Danke!

von Micha W. (blackxiiv)


Lesenswert?

Hi,
Uhr läuft 3h und ich hab 2min overclock.... also entweder muss ich die 
Schaltung nochmal an den HP Counter hängen oder ich hab da 'nen harten 
Glitch drin, den ich nicht sehe...
Dass die Uhr irgendwann mal was nicht mitbekommt und zu langsam wäre, 
würde ich verstehen - wegen den willkürlich gewählten delays.
aber warum ist die schneller?
Mein Counter (2.048MHz+4060+74390+74390) 1Hz?
Ist der zu schnell weil mein USB (am Arduino, 6x 74595, 1x4060, 2x74390) 
das alles treiben muss und der irgendwann zusammen bricht und dann 
schneller wieder die 5V bringt und damit der Counter schneller ist wegen 
power up?
gruß michi

von Wolfgang (Gast)


Lesenswert?

Micha W. schrieb:
> Uhr läuft 3h und ich hab 2min overclock....

Du erzeugst deinen Zeittakt immer noch mit Aufrufen von delay() an 
diversten Stellen im Code? Oder hast du inzwischen deinen 
DCF77-Empfänger dran?

Bei DCF77 darf das eigentlich nicht passieren.

Wenn du allerdings die Zeit aus dem CPU-Clock ableitest, bist du selbst 
bei Verwendung des Zeitgebers vom Arduino-"Betriebssystem", i.e. milis() 
auf die Genauigkeit der Taktfrequenz angewiesen, die mit Sicherheit 
nicht auf 6 gültige Ziffern dem aufgedruckten Wert entspricht. Mit dem 
delay() liegst du schnell völlig daneben, weil selbst die 
Programmlaufzeit Fehler generiert. Wahrscheinlich geht deine Uhr nach 
den 3 Stunden kräftig nach, sofern sich die delays in loop() auf genau 
1000 Millisekunden aufsummieren ;-)

Lies dir mal diesen Thread von PeDa durch
Beitrag "Die genaue Sekunde / RTC"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.