PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega 32 Uhr läuft zu schnell



Natureengeneer
18.10.2012, 01:15
Hallo liebe Forengemeinde. Ich frage mich nun schon seid einigen Tagen wie sich 2 Programmteile gegenseitig beeinflussen.

Fakt ist: Die Uhr läuft erst seit der Einbindung der uart.c, uart.h und der dazugehörigen functions in der Main etwas zu schnell. (In 30 min ca. 2 Min abweichung. [Uhr geht vor:confused:])
Jedoch verstehe ich leider nicht wodurch dies verursacht wird. :(
Chip läuft mit einem 8MHz Quarz und ist richtig gefused.

Jemand eine Idee? Bin für jeden noch so kleinen Tipp dankbar!

zschunky
18.10.2012, 13:43
Hallo,

2 Dinge fallen mir auf.

1) Du rechnest 8000000 / 1024 in der clock.c. Dies ergibt 7812.5, also als integer passt es nicht genau in eine Sekunde -> deine Sekunden sind also 0.999 936 Sekunden lang (30 minuten wären aber auch nur 0,1152 Sekunden Fehler in einer halben Stunde)
2) Du setzt bei jeden Overflow den Timer neu auf. Wenn aber gerade ein anderer Interrupt in diesem Moment bearbeitet wird, kann der entsprechende Interrupt verzögert werden. Ich würde eher vorschlagen den Timer Gleich so zu setzen dass man ihn nicht mehr anfassen muss (Clear Timer On Comparer Mode, 8000000 / 1024 -> OCR1A und statt Overflow Interrupt SIG_OUTPUT_COMPARE1A verwenden), Allerdings würde dies aber eher bedeuten dass Deine Uhr nach geht.

Aber wo Deine 2 Minuten herkommen kann ich leider auch nicht sagen.

-Andreas

Natureengeneer
23.10.2012, 09:21
HI ich habe mal ein bisschen herumprobiert und verwende nun den Comparemode.



#ifndef OCR1A
#define OCR1A OCR1 // 2313 support
#endif

#ifndef WGM12
#define WGM12 CTC1 // 2313 support
#endif
#define XTAL 8000000L // nominal value
#define DEBOUNCE 256L // debounce clock (256Hz = 4msec)
#define uchar unsigned char
#define uint unsigned int

uchar prescaler;

TCCR1B = (1<<WGM12) | (1<<CS10); // divide by 1
// clear on compare
TCNT1 = 0; // Timmer startet mit 0
prescaler = (uchar)DEBOUNCE; //software teiler
TIMSK = 1<<OCIE1A;

SIGNAL (SIG_OUTPUT_COMPARE1A) {
/************************************************** **********************/
/* Insert Key Debouncing Here */
/************************************************** **********************/

if( --prescaler == 0 ){
prescaler = (uchar) DEBOUNCE;
ss++;//Addiere +1 zu Sekunden
LED_burned++;
ANALOG_ss++;
if (ss == 60)
{
ss = 0;
mm++;//Addiere +1 zu Minuten
if (mm == 60)
{
mm = 0;
hh++;//Addiere +1 zu Stunden
if (hh == 24)
{
hh = 0;
}
}
}
}
#if XTAL % DEBOUNCE
if (prescaler <= XTAL % DEBOUNCE)
OCR1A += XTAL / DEBOUNCE +1; /* um 1 Takt längere Periode um den Rest abzutragen */
else
#endif
OCR1A += XTAL / DEBOUNCE; /* kurze Periode */
}




Das Erfreuliche: Die Uhr Läuft nicht mehr zu schnell, dafür nun aber leider zu langsam. (Abweichung nach 5h laufzeit ca. 30 minuten. [Uhr geht zurück])

Habe nun auch mal meine Fusesettings mitgepostet falls sich der Fehler vielleicht doch dort verbirgt.

Grundsetzlich ist es aber schon möglich den Timer1 comparemode für eine SoftwareClock (ohne große Abweichungen) zu verwenden und gleichzeitig eine lauffähiges UART Programm zur Kommunikation mit dem PC zu haben?
Weil großteils wird für den UART ja der Timer1 verwendet so wie ich das beurteilen kann...:confused:

zschunky
24.10.2012, 10:04
Was willst Du mit OCR1A += XTAL / DEBOUNCE +1; bzw OCR1A += XTAL / DEBOUNCE; bezwecken?

OCR1A sollte nur einmal beschrieben werden (also nicht im Interrupt) und nicht jedes mal neu. Im CTC zählt der Timer bis zu dem Wert, der im OCR1A steht und wenn er diesen Wert erreicht wird der counter automatisch auf 0 gesetzt und er fängt wieder von vorn an zu zählen (man muss also nichts von Hand wieder neu aufsetzen).

Setze mal den Prescaler auf 256 (8Mhz / 256 = 31.25KHz). Das heißt Du benötigst 31250 Takte damit eine Sekunde vorbei ist. Also Schreibt man einmalig 31250 in das OCR1A. Jetzt sollte der Interrupt jede Sekunde aufgerufen werden.

Die Timer sind komplett unabhängig von der UART und sollten sich nicht gegenseitig beeinflussen.

Bei den Fuses sehe ich keine Probleme.

Natureengeneer
24.10.2012, 11:43
OK ich hab den Debouncingpart weggemacht und Teste dann nun das Programm mit einem OCR1A Wert von 31250

Bericht folgt.

Vielen dank schonmal für die Hilfe.

Natureengeneer
24.10.2012, 12:44
Leider rennt die Uhr nun übertrieben schnell hoch.



#ifndef OCR1A
#define OCR1A OCR1 // 2313 support
#endif

#ifndef WGM12
#define WGM12 CTC1 // 2313 support
#endif
#define XTAL 8000000L // nominal value

TCCR1B = (1<<WGM12)| (1<<CS10); // divide by 1
// clear on compare
OCR1A = 31250; // Output Compare Register
TCNT1 = 0; // Timmer startet mit 0
TIMSK = 1<<OCIE1A; // beim Vergleichswertes Compare Match
sei();

SIGNAL (SIG_OUTPUT_COMPARE1A) {
ss++;//Addiere +1 zu Sekunden
LED_burned++;
ANALOG_ss++;
if (ss == 60)
{
ss = 0;
mm++;//Addiere +1 zu Minuten
if (mm == 60)
{
mm = 0;
hh++;//Addiere +1 zu Stunden
if (hh == 24)
{
hh = 0;
}
}
}


}




Was mach ich denn nur falsch :confused:

Searcher
24.10.2012, 15:08
Setze mal den Prescaler auf 256 (8Mhz / 256 = 31.25KHz).

zschunky hat den Prescaler schon vorgegeben, bei Dir steht was anderes.



TCCR1B = (1<<WGM12)| (1<<CS10); // divide by 1
// clear on compare
OCR1A = 31250; // Output Compare Register


Der genauere Wert für das OCR1A wäre 31249. (Formel im Datenblatt bei Timer1, Modes of Operation, CTC )

Gruß
Searcher

Natureengeneer
24.10.2012, 16:19
Also

TCCR1B = (1<<WGM12)| (1<<CS12);

THX

Hubert.G
24.10.2012, 16:22
Wie wäre es mit

TCCR1B = (1<<WGM12)| (1<<CS12);

Dann wäre der Prescaler auf 256 gestellt.

Natureengeneer
24.10.2012, 16:24
JO dankeschön.

Bin noch ein Noob was uC angeht :hand nimmt Rücksicht. :)