PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Systemzeit in Gcc abfragen, ist das möglich ??



oderlachs
15.10.2013, 15:46
Ich muss mal wieder fragen:(

und hoffe, es kan mir wer helfen, bzw. einen Hinweis zu geben.

Ich möchte in einer AVR Anwendung eine Systemzeit setzen und diese auch wieder abfragen können. Es genügen 0..24Stunden 0..60 Minuten 0...60Sekunden eventuell auch noch .

Es geht mir da nicht so um genaue Zeit..wenn da mal etwas Unterschied ist ist es nicht so schlimm, doch sollte aus einer Sekunde keine Minute werden ;=)

Gibt das dafür in GCC Routinen/Variablen ? und mit welchen AVR ist es möglich, ich denke das der Chip einen RTC innen haben muss...?

Würde gerne einen ATTiny2313 o.ä. einsetze,n also mit 20 Bein'chen solch Käferle.. ;)

Danke schon mal für die eventuelle Info, auch für ein Anschauungsbeispiel(Link) vielleicht, wäre ich dann doppelt dankbar...:p

Gruss

Gerhard

P.S. Es soll ohne einen extra RTC Chip bzw. Funkuhrmodul laufen.

oberallgeier
15.10.2013, 16:28
... AVR Anwendung ... Systemzeit setzen und ... abfragen ... ohne einen extra RTC ...Wenns sonst nix ist! DAS ist easy.

Ich habe eine 50µs-ISR, das ist bei mir ein Mehrfach-Timer, der mir die Boardzeit macht und einen heartbeat (LED-1sec-toggel) und so, dazu einen Sekundenzähler, der erst nach rund neun Stunden überläuft. Wer längere Laufzeiten hat, müsste halt nen Stundenzähler dazu definieren, dann ginge das über Jahre . . . . Abweichung je nach Quarzkonstanz ein paar Sekunden im Monat.

Als Skizze für eine headerdatei:

// ================================================== ============================ =
// Zeiten, insbes. Zeitmessung
// ================================================== ============================ =
volatile s16 Izeit_1; // Wertbereich int16: 32.767. uint16: 65.535
// Timer läuft hoch. Die Interruptroutine läuft mit 20 kHz
volatile s16 Izthrznt; // Der zeitliche Horizont, z.B. 20000 für 2 sec
volatile s16 Isecundn; // Sekunden Programmlaufzeit, 32.767 sec sind
// 546,117 Minuten bzw. 9 Std
// ================================================== ============================ =
//================================================== ============================= =
// Modul R5M_tmrij.c Routinen: Timerroutinen
// ================================================== ============================ =
void TC2TMR_init(void); // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
void TC2_stop(void); // Stoppe Tmr/Cntr 2
ISR(TIMER2_COMPA_vect); // Routine zählt hoch im Takt 20 kHz = 50 µs
// ================================================== ============================ =

// ...
#define ToggleBit(ADDR,BIT) ((ADDR) ^= (1<<(BIT))) // Toogelt Bit


Und dazu der eigentliche Timer:


// ================================================== ============================ =
// === Initialisierung fuer Timer2 mega168/328
void TC2TMR_init(void) // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
{ //
TCCR2A |= (1<<WGM21); // Timer im CTC-Mode, Top=OCR2A doc S 157
TCCR2B |= (1<<CS21); // Prescaler 1/8 / Clock <- CPU doc S 158
OCR2A = 124; // Preset 124 für 50µs bei 20Mhz
TIMSK2 |= (1<<OCIE2A); // Tmr/Cntr2 CompareA interrupt enabled
// ##>>> Izeit_1 wird im main initialisiert
} //
// ================================================== ============================ =
// ================================================== ============================ =
// === Stoppen Timer2 mega168
void TC2_stop(void) // Stoppe Tmr/Cntr 2
{ //
TCCR2A &= ~(1<<WGM21); // Timer WGM21 resetten
TIMSK2 &= ~(1<<OCIE2A); // Tmr/Cntr2 CompA interrupt DIS abled
} //
// ================================================== ============================ =

// ================================================== ============================ =
// === Nicht unterbrechbare ISR für timer2 ==================================== */
// Routine zählt hoch im Takt 20 kHz = 50 µs.
ISR(TIMER2_COMPA_vect) // Vektor 7
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{ //
Izeit_1 --; // ###>>> Izeit_1 ist aktuell int16_t ==>>
// Izeit_1 bleibt bis 32000 in der int16-Grenze
if ( Izeit_1 ) // Interrupt-Timer = 1 ... 20 000 ... (1 sec blink)
{ } // WENN Izeit_1 =|= Null => Ausdruck ist wahr => Anweisung ausgeführen
else // Eine Sekunde ist voll =>
{ //
Izeit_1 = Izthrznt; // ansonsten: Rückstellen auf Zeithorizont
ToggleBit (PORTB, L1g); // gnLED auf Pin PB3 toggeln
Isecundn ++; // Sekundenzähler hochtackern, max 9 Std
} // Ende if (Izeit_1 )
// - - - - - - - - - - - - - - - -
return;
} // Ende ISR(TIMER2_COMPA_vect)
// ================================================== ============================ =

Der "TC2_stop" ist ja im Prinzip für eine Boardzeit nicht sinnvoll, den habe ich für sonstige Anwendungen, die hier nicht interessieren.

Ist es das, was Du suchst ?

oderlachs
15.10.2013, 17:19
Danke JoeamBerg !!

Ich glaube das es das ist was ich suche..."glaube" darum , weil ein solches projekt noch nie bewust angegangen bin. Erst dachte ich mit _wait_ms(xx) arbeiten zu können , aber das legt ja meine ganze Überwachungs(Main-)Routine lahm für die Wartezeit.
Danke Dir auch für die Codeabschnitte, da kann ich mal lesen und hoffe dann auch besser zu verstehen... :) .
Ich brauche ein wenig Zeitgefühl in der Anwendung, grob gesagt könnte ich Tag Nacht per Helligkeit unterscheiden, aber das möchte ich ungerne nutzen. Der Wetterdienst hat für hier Regen angesagt, also AVR Zeit und nicht im garten rum ackern angesagt....da werde ich probieren..

Gruss & Danke

Gerhard

oberallgeier
15.10.2013, 17:30
... Ich glaube das es das ist was ich suche ... für hier Regen angesagt ...War ja gut, wenns Dir hilft. Eine Sache hatte ich nicht dokumentiert, die Variablendefinition:

typedef unsigned short u16;
typedef signed short s16;

gehört natürlich auch in den Header. Hatte ich vergessen, weils bei mir eine allgemeine Bibliothek ist. Sorry.

oderlachs
15.10.2013, 17:35
Danke für den superschnellen Nachtrag... :)

Nachtrag:
Habe auf Microcontroller.net ein gutes Beispiel (http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR) gefunden und hoffe das ich es auf meine q-freq. umstricken kann, befasse mich aber trotzdem mit den Timern vom Chip und deren Anwendung, denn das ist bislang noch, ein von mir unbetretendes Feld bei der Programmierung

Gruss und Danke

Gerhard

markusj
15.10.2013, 23:03
War ja gut, wenns Dir hilft. Eine Sache hatte ich nicht dokumentiert, die Variablendefinition:

typedef unsigned short u16;
typedef signed short s16;

gehört natürlich auch in den Header. Hatte ich vergessen, weils bei mir eine allgemeine Bibliothek ist. Sorry.

Evtl. möchtest du dir Mal int16_t, uint16_t und ihre großen/kleinen Geschwister aus stdint.h ansehen. Das ist seit C99 der Weg um plattformunabhängig(er) mit Variablen einer bestimmten Mindestbreite zu arbeiten.

@Gerhard: So ist das mit den kleinen µCs. Alles muss man selbst machen. Typischerweise lässt man einen Timer mit 10..1000Hz laufen, zählt im Interrupt die Zeit hoch und kann gleich noch Dinge erledigen die ein exaktes Timing erfordern.

mfG,
Markus

oberallgeier
15.10.2013, 23:48
Evtl. möchtest du dir Mal int16_t, uint16_t und ihre großen/kleinen Geschwister aus stdint.h ansehen...Netter Hinweis, aber danke, die kenne ich. Und plattformunabhängig bin ich auch, da gibts nämlich Möglichkeiten . . . mit denen man formgerecht auch mal etwas mit weniger als sechs, sieben Buchstaben hinkriegt *ggg*.

sternst
16.10.2013, 08:53
Und plattformunabhängig bin ich auchMit dem oben gezeigten aber nicht.



auch mal etwas mit weniger als sechs, sieben BuchstabenNiemand sagt, dass du auf dein u16/s16 verzichten sollst. Aber wenn du es so schreibst
typedef uint16_t u16;
typedef int16_t s16;
müssen deine Typ-Definitionen bei anderen Plattformen nicht erst hinterfragt und ggf. angepasst werden.

oberallgeier
16.10.2013, 09:18
Mit dem oben gezeigten aber nicht ... Aber wenn du es so schreibst ...Stefan, danke! Da dachte ich, ich hätte die typedef int aus der Library Reference von der AVR Libc Home Page verstanden - und nu gehöre ich doch zu den 60% Pisa-Erwachsenen, die Leseprobleme haben (eher Verständnisprobleme).

Hab gerade meine Zentralbibliothek geändert !

oderlachs
16.10.2013, 13:33
Ganz habe ich das mit den Timern noch nicht geschnallt, die Art und Weise schon verstanden nur nicht wie ich da zum konkreten Ergebis einer bestimmten Zeit komme, also die Konfiguration der Timerwerte, Vorteiler bei bestimmter FQu. (3.686400Hz oder 16.000000Hz zBsp).

Na ja habe zwar jetzt ein funzenden ASM Beispiel, aber da muss ich erst mich wieder durchdenken was genau die SourceCode da macht...
Es wird aber... ;)
Gerhard

oberallgeier
16.10.2013, 13:43
... das mit den Timern noch nicht geschnallt ... nicht wie ich da zum konkreten Ergebis ...
... Habe auf Microcontroller.net ein gutes Beispiel gefunden und hoffe das ich ...Hmmm, da kann ich jetzt nicht weiterhelfen, weil ich Dein microcontroller.net-Beispiel nicht kenne.

seite5
16.10.2013, 14:20
Hi,
...doch sollte aus einer Sekunde keine Minute werden ;=)
pro Tag, Woche oder Jahr ??? Mit Standardquarz bist Du ganz schnell in dem Bereich von einigen 10 Sekunden / Tag
mfg
Achim

markusj
16.10.2013, 14:24
Ganz habe ich das mit den Timern noch nicht geschnallt, die Art und Weise schon verstanden nur nicht wie ich da zum konkreten Ergebis einer bestimmten Zeit komme, also die Konfiguration der Timerwerte, Vorteiler bei bestimmter FQu. (3.686400Hz oder 16.000000Hz zBsp).

Eigentlich ist das gar nicht so schwer:

Du hast deinen Systemtakt mit X Mhz (F_CPU).
Würdest du damit direkt deinen Zähler betreiben, würde der irrsinnig schnell laufen. Die messbare Zeit wäre also sehr kurz. Daher teilt man den Systemtakt bei Bedarf noch (Prescaler).
Dein Zähler zählt mit einer bestimmten Frequenz F_CPU/Prescaler. Je nach Timer kann der Zähler maximal 2^8 (256), 2^10 (1024) oder 2^16 (65536) verschiedene Zustände annehmen.
Relevant für dich ist das Auftreten des Interrupts. Der wird bei erreichen eines bestimmten Wertes (konfigurierbar über sogenannte Output Compare Units oder fest bei Zählerüberlauf)
Implizit stellt der Zähler nur ein weiterer Taktteiler dar, er teilt die Zählerfrequenz durch die Anzahl der Schritte bis zum Überlauf.
Damit ergibt sich die Überlauffrequenz F_Out = F_CPU / Prescaler / Zählschritte
Umgekehrt musst du also, wenn du eine bestimmte Frequenz (und damit Zeitintervalle, da f=1/T) generieren möchtest, die Parameter passend wählen. In der Regel sucht man sich dabei ausgehend von F_CPU den kleinsten Prescaler für den das Zählerregister für die Wunschfrequenz noch ausreichend ist.
Diese Bedingung lässt sich formulieren als Prescaler >= F_CPU/Max_Zählschritte/F_Out


Beispiel: F_CPU = 1Mhz. Wunschfrequenz F_Out 2kHz (0,5ms Periodendauer). Timer: 8-Bit.
Prescaler >= 1Mhz/2^8/2kHz = 1,95
Zur Verfügung steht beim Mega8 damit zum Beispiel der Prescaler F_CPU/8

Zählschritte = 1Mhz/8/2kHz = 62,5 (obere Formel umgestellt)
Probe: F_Out = 1Mhz/8/62 = 2016Hz

Achtung: Der TOP-Wert der im CTC-Modus gesetzt wird, ist Zählschritte-1, da von 0 bis TOP gezählt wird!

mfG,
Markus

oderlachs
16.10.2013, 19:38
Danke Markus, das ist sogar für mich Dummie nun besser verständlich, ja manchmal "klemmt der Groschen", wie man früher so sagte, heute sind's ja 10 Cent.. ;)
Ich habe jetzt ein Listig gefunden und etwas verändert und hoffe das ich das richtig damit verstanden habe, die LED soll alle 2 sec hier Aufleuchten:

/* uC: Attiny2313 */
/* F_CPU = 2.000.000 Hz */
#include <avr/io.h>
#include <avr/interrupt.h>

//Variablen für die Zeit
volatile unsigned int millisekunden;
volatile unsigned int sekunde;
volatile unsigned int minute;
volatile unsigned int stunde;

int main(void)
{
DDRB |= (1<< PB0);
// Timer 0 konfigurieren
TCCR0A = (1<<WGM01); // CTC Modus
TCCR0B |= (1<<CS11); // Prescaler 8
// ((2000000/8)/1000) = 125 bei Qu = 2,0 MHz
OCR0A = 250-1;

// Compare Interrupt erlauben
TIMSK |= (1<<OCIE0A);

// Global Interrupts aktivieren
sei();

while(1)
{
/*Hier kann die aktuelle Zeit
ausgeben werden*/
if (sekunde % 2 == 0) //alle 2 sec LED ON/OFF
{
PORTB &= ~(1<< PB0);//PB0... LOW = LED ON
}else {
PORTB |= (1<< PB0);//PB0...HIGH = LED OFF
}
}
}

/*
Der Compare Interrupt Handler
wird aufgerufen, wenn
TCNT0 = OCR0A = 125-1
ist (125 Schritte), d.h. genau alle 1 ms
*/
ISR (TIMER0_COMPA_vect)
{
millisekunden++;
if(millisekunden == 1000)
{
sekunde++;
millisekunden = 0;
if(sekunde == 60)
{
minute++;
sekunde = 0;
}
if(minute == 60)
{
stunde++;
minute = 0;
}
if(stunde == 24)
{
stunde = 0;
}
}
}


Gruss und Danke(!!)

Gerhard