Forum: Mikrocontroller und Digitale Elektronik Sekunden mit Uhrenquarz richtig takten


von M. S. (ekkie)


Lesenswert?

Hallo,

ich möchte mit einem Takt von 32Hz in meinem Atmega328p operieren.
Nun möchte ich eine genaue Sekunde erzeugen.
Hier mein Code:
1
/*
2
 * crystal_test.c
3
 *
4
 * Created: 20.07.2020 18:24:24
5
 * Author : meik_
6
 */ 
7
8
#define taster_1 PB1
9
10
#include <avr/io.h>
11
//#include <avr/delay.h>
12
#include <avr/sleep.h>
13
#include <avr/interrupt.h>
14
15
volatile uint32_t sec=0;          //hier kann zeit eingestellt werden
16
volatile uint32_t min=1;
17
volatile uint32_t hr=1;
18
19
int main(void)
20
{
21
  ASSR = (1<<AS2);                          // asynchron laufen lassen
22
  ACSR = 1<<ACD;                            // Strom sparen
23
  PRR = 1<<PRTWI|1<<PRTIM0|1<<PRTIM1|1<<PRSPI|1<<PRUSART0|1<<PRADC;
24
  TCCR2A = (1<<WGM21);                        // CTC auf OCRA
25
  OCR2A = 0;                          // 1sec * 32768/1024
26
  TCCR2B = 1<<CS22|1<<CS21|1<<CS20;                  // Prescaler auf 1024
27
28
  while((ASSR & (1<< TCR2BUB)));    // synchronisieren
29
  TIMSK2 = (1<<OCIE2A);
30
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
31
  sei();
32
33
  DDRD = 0xff;
34
  DDRC = 0xff;
35
  DDRB &= ~(1<<taster_1);
36
37
    while (1) 
38
    {
39
    while((ASSR & (1<< TCR2AUB)));
40
    sleep_mode();
41
    TCCR2A = TCCR2A;          // sonst Mehrfachinterrupts:
42
      
43
    if(sec<60*(32)){}            //hier prescaler einbinden von 32
44
    else{sec=0; min++;}
45
    if(min<=60){}
46
    else {min=0; hr++;}
47
    if(hr<=12){}
48
    else{hr=1;}
49
50
    PORTD = min;
51
    PORTC = hr;
52
53
  }
54
}
55
56
ISR (TIMER2_COMPA_vect) {
57
  sec++;  
58
}

OCR2A lasse ich auf 0 um die 32Hz zu erzeugen. Allerdings muss ich in 
der if-Bedingung diesen als Faktor dazu rechnen oder ?
1
if(sec<60*(32)){}            //hier prescaler einbinden von 32

ich weiß, dass das wahrscheinlich kein all zu schwieriges Unterfangen 
ist. Aber ich sitze da schon wieder 2 Tage dran. Kann mir einer sagen 
welche Werte ich wo einzusetzen habe ?
Vielen Danke

von M. S. (ekkie)


Lesenswert?

achso ich habe natürlich einen 32,768kHz Uhrenquarz an die TOSC1..2 pins 
angeschlossen als Referenz.

von Philipp K. (philipp_k59)


Lesenswert?

1
    if(sec<60*(32)){}            //hier prescaler einbinden von 32
2
    else{sec=0; min++;}
3
    if(min<=60){}
4
    else {min=0; hr++;}
5
    if(hr<=12){}
6
    else{hr=1;}

Eher so, zähle die Variable cnt im Zähler hoch:
1
    if(cnt<32){}            //hier prescaler einbinden von 32
2
    else {cnt=0; sec++}
3
if(sec<60){}
4
else{sec=0;min++;}
5
    if(min<=60){}
6
    else {min=0; hr++;}
7
    if(hr<=12){}
8
    else{hr=1;}

von A. S. (Gast)


Lesenswert?

M. S. schrieb:
> Aber ich sitze da schon wieder 2 Tage dran.

warum? Funktioniert es nicht?

von M. S. (ekkie)


Lesenswert?

ich weiß es ehrlich gesagt nicht genau. Ich habe das Programm noch nicht 
mehrere Stunden laufen lassen um eine aussagekräftige Antwort zu 
liefern.
Bevor ich aber nach dem Motto: Trial and Error versuche die richtigen 
Werte (wahrscheinlich tagelang, man hat ja auch noch anderes zu tun..) 
herauszufinden, dachte ich frage ich hier mal unter den Profis für denen 
das ein Leichtes ist, mir die richtigen Werte mitzuteilen.

von Axel S. (a-za-z0-9)


Lesenswert?

M. S. schrieb:
> OCR2A lasse ich auf 0 um die 32Hz zu erzeugen.

Ich weiß gar nicht, ob das funktioniert. Hat 0 nicht eine besondere 
Bedeutung?

> Allerdings muss ich in der if-Bedingung diesen als Faktor dazu
> rechnen oder ?
>
1
if(sec<60*(32)){}  //hier prescaler einbinden von 32

Wenn du den Interrupt mit 32 Hz auslöst und die Variable sec mit jedem 
Interrupt inkrementierst, dann schon.

Nur:

1. Warum nennst du die Variable sec (wie "Sekunde"), obwohl sie doch 
gar nicht die Sekunden zählt, sondern 32-tel Sekunden?

2. Warum überhaupt 32 Interrupts pro Sekunde? Laß doch den Timer die 
Frequenz bis auf 1Hz runter teilen. Und falls du die 32Hz aus 
irgendeinem Grund brauchst (ich sehe keinen), dann zähle die 32-tel 
Sekunden halt in einer extra Variable.

3. Warum sind sec, min und hr jeweils vom Typ uint32_t ? Die 
können doch nur Werte von 0-59 bzw. 0-23 annehmen. Dafür braucht man 
doch keinen 32-Bit Datentyp.

von Thomas E. (thomase)


Lesenswert?


von Peter D. (peda)


Lesenswert?

Hau das ganze Sleep-Gedöns raus.
Das Stromsparen macht man erst ganz zum Schluß, nachdem alles andere 
einwandfrei läuft.
Nie nen Haufen Baustellen gleichzeitig aufreißen, immer einen Schritt 
nach dem anderen.

von Stefan F. (Gast)


Lesenswert?

M. S. schrieb:
> Ich habe das Programm noch nicht
> mehrere Stunden laufen lassen um eine aussagekräftige Antwort zu
> liefern.

Grobe Abweichungen bemerkt man doch schon nach wenigen Sekunden, wenn 
man mit dem Ticken einer mechanischen Uhr vergleicht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

M. S. schrieb:
> achso ich habe natürlich einen 32,768kHz Uhrenquarz an die TOSC1..2 pins
> angeschlossen als Referenz.
32768Hz/32Hz = 1024.
Du brauchst also einfach einen 10-Bit Zähler, der geradeaus durchläuft. 
Und beim Überlauf hast du deine 32Hz.

> OCR2A lasse ich auf 0 um die 32Hz zu erzeugen
Da ist also gar kein Compare-Register nötig. Ein simpler TOV reicht aus.

Axel S. schrieb:
> dann zähle die 32-tel Sekunden halt in einer extra Variable.
Und weil es der Timer 2 ist, könnte der per 1024-Prescaler gleich die 
32stel Sekunden mitzählen.

: Bearbeitet durch Moderator
von A. S. (Gast)


Lesenswert?

M. S. schrieb:
> Bevor ich aber nach dem Motto: Trial and Error versuche die richtigen
> Werte (wahrscheinlich tagelang, man hat ja auch noch anderes zu tun..)
> herauszufinden, dachte ich frage ich hier mal unter den Profis für denen
> das ein Leichtes ist, mir die richtigen Werte mitzuteilen.

Meist liegen die Fehler im
 * off by one (<x statt <=x)
 * falschen Takt (nur halber, viertel oder doppelter)
 * falsche Zahl (32*60 in 8 Bit)

lass das ganze darum einfach schneller laufen (z.B. die Takte nur bis 32 
statt 32*60, also Minuten als Sekunden). Dann siehst Du offensichtliche 
Fehler sofort. Dann 12 Minuten (als Stunden) gestoppt auf eine Sekunde, 
dann bist Du ziemlich nah an perfekt, in wenigen Minuten (+Pause mit 
Eieruhr bei den 12 Minuten).

Danach mit echten Werten nach einer Minute und nach einem Tag prüfen.

von c-hater (Gast)


Lesenswert?

M. S. schrieb:

> ich weiß, dass das wahrscheinlich kein all zu schwieriges Unterfangen
> ist.

Ist es nicht.

> Aber ich sitze da schon wieder 2 Tage dran.

Du hättest sie nutzen sollen, um das verdammte Datenblatt zu lesen. Dann 
ist das eine Sachen von 10 Sekunden, das SELBER korrekt umzusetzen.

Wenn man allerdings nur raubkopierten Code zusammenleimt, kann man mit 
solch trivialen Problemen natürlich Tage an Lebenszeit verschwenden.

Im richtigen Moment die richtige Entscheidung treffen. Das ist der 
Trick...

von W.Gates (Gast)


Lesenswert?

c-hater schrieb:
> Wenn man allerdings nur raubkopierten Code zusammenleimt, kann man mit
> solch trivialen Problemen natürlich Tage an Lebenszeit verschwenden.

Wenn man wirklich stehlen muss, dann nur von den Besten!

von c-hater (Gast)


Lesenswert?

W.Gates schrieb:

> Wenn man wirklich stehlen muss, dann nur von den Besten!

Tja, wenn man ein voll funktionierendes tolles Auto geklaut hat, muss 
man trotzdem immer noch lernen, wie man es fährt, wenn man damit nicht 
im Graben landen will...

von MaWin (Gast)


Lesenswert?

M. S. schrieb:
> OCR2A lasse ich auf 0 um die 32Hz zu erzeugen.

Das steht dann wohl eher für 256.

Setze den Prescaler auf 4 und nutze den Timerüberlaufinterrupt.

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> Im richtigen Moment die richtige Entscheidung treffen. Das ist der
> Trick...

Das Wort zum Sonntag:
Es gibt NUR drei Wege, welche zum Ziel führen:

1. Der goldene Weg
Problem analysieren, Lösung erarbeiten und durchsetzen.

2. Der silberne Weg
Abschauen, genau so manchen, wie die Anderen.

3. Der bronzene Weg
Aus den gemachten Erfahrungen lernen.

---
Alle anderen Wege führen ins Versagen.

von MaWin (Gast)


Lesenswert?

Uups, gar nicht geguckt, ob 4 überhaupt ein legaler Prescalerwert ist. 
Stellt man ihn auf 16, passt Overflow natürlich nicht für 32Hz, dann 
müsste Compare-Interrupt auf 64. Wenn man dann aber keinen reload macht, 
kommt der nächste Compare trotzdem erst wieder in 256 Takten, es sei 
denn, die Interrupt-Routine seztz ihn weiter auf 128 und 192 und 0 und 
64. Macht man einen reload per Programm, passt es um ein paar 
Mikrosekunden nicht.

von Axel S. (a-za-z0-9)


Lesenswert?

MaWin schrieb:
> Uups, gar nicht geguckt, ob 4 überhaupt ein legaler Prescalerwert ist.
> Stellt man ihn auf 16, passt Overflow natürlich nicht für 32Hz, dann
> müsste Compare-Interrupt auf 64. Wenn man dann aber keinen reload macht,
> kommt der nächste Compare trotzdem erst wieder in 256 Takten, es sei
> denn, die Interrupt-Routine seztz ihn weiter ...

Ähhm. Nein. Die AVR-Timer haben dafür praktischerweise den CTC Mode.
CTC = Clear Timer on Compare match.

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.