Forum: Mikrocontroller und Digitale Elektronik Timer mit us Auflösung


von Schnurzelpurzel (Gast)


Lesenswert?

Ich habe einen ATtiny25 und brauche einen Timer mit us Auflösung bei 
einer Verzögerungszeit von 1 Minute.
D.h. meine Verzögerungszeit ist ca 60000000us plus minus ein paar us
Dafür brauche ich doch einen 32 Bit Timer?

Was kann man machen?

von S. T. (cmdrkeen)


Lesenswert?

mit dem 16bit timer eine 16bit zahl hochzählen?

von Falk B. (falk)


Lesenswert?

@  Schnurzelpurzel (Gast)

>Ich habe einen ATtiny25 und brauche einen Timer mit us Auflösung bei
>einer Verzögerungszeit von 1 Minute.

Was soll das werden?

>D.h. meine Verzögerungszeit ist ca 60000000us plus minus ein paar us
>Dafür brauche ich doch einen 32 Bit Timer?

Jain. Das kann man aber aufteilen in 16 Bit Hardwarezähler und 16 Bit 
Softwarezähler.

MFG
Falk

von Peter D. (peda)


Lesenswert?

Schnurzelpurzel schrieb:
> D.h. meine Verzögerungszeit ist ca 60000000us plus minus ein paar us

Dann hast Du bestimmt auch nen temperaturstabilen hochgenauen 
kalibrierten Quarzgenerator (oder Atomuhr) als Takt angeschlossen.
Ansonsten kannst Du nämlich Deine µs in der Pfeife rauchen.

Das Erweitern auf 32Bit ist dagenen ein leichtes:

Beitrag "AVR Timer mit 32 Bit"


Peter

von Manu (Gast)


Lesenswert?

Da dies gerade verlinkt wurde, eine kleine Frage hierzu
1
u32 get_ticks( void )        // read T2 as 32 bit timer
2
{
3
  u32 val;
4
  u8 tifr;
5
6
  cli();
7
  val = t2_soft + TCNT2;
8
  tifr = TIFR;          // read interrupt flags
9
  sei();
10
  if( (tifr & 1<<TOV2) && !(val & 0x80) ) // overflow prior reading TCNT2 ?
11
    val += 256;          // then add overflow
12
13
  return val;
14
}

In dieser Zeile:
1
  if( (tifr & 1<<TOV2) && !(val & 0x80) ) // overflow prior reading TCNT2 ?
2
    val += 256;          // then add overflow
wird ja geprüft, ob ein OVF ansteht, wenn ja, und das 7 byte 0 ist, also 
der Wert klein und es somit zu dieser Messung gehört, addiert. Das ist 
auch richtig.
Aber, das Flag zum Ausführen des OVF Int. wird ja nicht gelöscht. Nach 
verlassen der Funktion get_ticks wird dann doch der OVF Int. ausgeführt 
und somit nochmal dazu gezählt.
Müsste man nicht das Flag löschen, wenn man das bereits addiert hat, 
also so:
1
  if( (tifr & 1<<TOV2) && !(val & 0x80) ) // overflow prior reading TCNT2 ?
2
    val += 256;          // then add overflow
3
    TIFR = (1 << TOV2);                   // Flag löschen (Schreiben einer 1)

Wenn ich falsch liege, erklärt mir bitte wieso :)

von Peter D. (peda)


Lesenswert?

Manu schrieb:
> Aber, das Flag zum Ausführen des OVF Int. wird ja nicht gelöscht. Nach
> verlassen der Funktion get_ticks wird dann doch der OVF Int. ausgeführt
> und somit nochmal dazu gezählt.

Du hast den Wert ausgelesen und dann wird da auch nichts mehr 
dazugezählt.
Eine Variable ändert sich ja nicht von selbst.

Aber der Interrupt muß auch seinen Counter mitzählen, sonst stimmt ja 
die nächste Auslesung nicht mehr.

Die Auslesefunktion und der Interrupt arbeiten auf 2 verschiedenen 
Variablen und daher müssen beide den Überlauf behandeln, sonst gibts 
Ärger.
Natürlich setzt nur der Interrupt auch das Flag zurück.


Peter

von Manu (Gast)


Lesenswert?

Danke Peter, klar. Ich hatte wohl Tomaten auf den Augen, sind ja 2 
unterschiedliche Variablen.

von Schnurzelpurzel (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Das Erweitern auf 32Bit ist dagenen ein leichtes:
>
> Beitrag "AVR Timer mit 32 Bit"

Hallo Peter,
vielen Dank, habe ich mir angesehen, ist toll.
Wenn ich das richtig verstehe, kann der µC damit nachsehen *wie spät es 
ist*

Was ich brauche ist eine Routine um exakte Zeitverzögerungen zwischen 
setzen und löschen einer Portleitung zu haben.

>Dann hast Du bestimmt auch nen temperaturstabilen hochgenauen
>kalibrierten Quarzgenerator (oder Atomuhr) als Takt angeschlossen.
>Ansonsten kannst Du nämlich Deine µs in der Pfeife rauchen.

Ich bekomme ein 10MHz-Rubidium-Normal das der Vater von einem Freund 
hat, als Dauerleihgabe. Wir bauen uns ein 10MHz Verteilnetzwerk im 
ganzen Haus. Hihi  :-)

von Falk B. (falk)


Lesenswert?

@  Schnurzelpurzel (Gast)

>Was ich brauche ist eine Routine um exakte Zeitverzögerungen zwischen
>setzen und löschen einer Portleitung zu haben.

Sag mal lieber, was das insgesamt werden soll.

Wenn es denn wirklich auf den Takt/die µs genau sein soll, muss man ggf. 
in Assembler was machen. Oder einen CPLD nutzen.

MFG
Falk

von Schnurzelpurzel (Gast)


Lesenswert?

>Sag mal lieber, was das insgesamt werden soll.

>Wenn es denn wirklich auf den Takt/die µs genau sein soll, muss man ggf.
>in Assembler was machen. Oder einen CPLD nutzen.

Insgesamt soll es eine art TTL-Impulsgenerator werden, wo man die 
High-und Low-Zeit in 1-us Schrittweite getrennt einstellen kann.
Einstellbereich ist von 1ms bis 100s in 1us Schrittweite.

Was ich brauche ist eine Routine die eine Verzögerung macht.
Es ist wahrscheinlich blöd während einer Verzögerung zu warten und die 
CPU ist mit nur mit Zählen  beschäftigt, aber da die CPU sowieso nix 
anderes zu tun hat...

Die folgende Routine ist suboptimal, da je nachdem was sonst im 
Programm steht, der Compiler die unterschiedlich optimiert
1
//***********************************************
2
void my_Delay(volatile unsigned long int Zeit)
3
{
4
  for(;Zeit>0;Zeit--);
5
}
6
//***********************************************

von Falk B. (falk)


Lesenswert?

@Schnurzelpurzel (Gast)

>Insgesamt soll es eine art TTL-Impulsgenerator werden, wo man die
>High-und Low-Zeit in 1-us Schrittweite getrennt einstellen kann.
>Einstellbereich ist von 1ms bis 100s in 1us Schrittweite.

Willst du Agilent und TEK Konkurrenz machen? Da musst du aber sehr früh 
aufstehen ;-)

>Was ich brauche ist eine Routine die eine Verzögerung macht.

Gibt es, _delay_us() und delay_ms(). Das reicht aber nicht, weil das 
Problem etwas kniffliger ist.
Mit ASM und ne guten Idee sollte man das aber hinbekommen.
Ich würde einen CPLD nehmen.

>Die folgende Routine ist suboptimal, da je nachdem was sonst im
>Programm steht, der Compiler die unterschiedlich optimiert

>//***********************************************
>void my_Delay(volatile unsigned long int Zeit)
>{
>  for(;Zeit>0;Zeit--);
>}
>//***********************************************

Wenn du µs genauses Timing willst, ist C nicht wirklich das Mittel der 
Wahl. Und da der AVR sowieso nix weiter macht als LOW, Warten, High, 
Warten, ist ASM sehr zu empfehlen.

MFG
Falk

von Peter (Gast)


Lesenswert?

Falk Brunner schrieb:
> Wenn du µs genauses Timing willst, ist C nicht wirklich das Mittel der
> Wahl. Und da der AVR sowieso nix weiter macht als LOW, Warten, High,
> Warten, ist ASM sehr zu empfehlen.

wenn man es über den Timer macht, sollte der overhead durch C nicht 
weiter stören. Das mit es mit C in so einer schleife nicht hinbekommt 
ist klar.

von Schnurzelpurzel (Gast)


Lesenswert?

Falk Brunner schrieb:
> Willst du Agilent und TEK Konkurrenz machen? Da musst du aber sehr früh
> aufstehen ;-)

Nein nein, es soll nur ein kleines Ticky-tool sein. Überhaupt keine 
Konkurrenz zu Agilent.
Ist mit TEK Tektronix gemeint?


>Wenn du µs genauses Timing willst, ist C nicht wirklich das Mittel der
>Wahl. Und da der AVR sowieso nix weiter macht als LOW, Warten, High,
>Warten, ist ASM sehr zu empfehlen.

Naja, etwas mehr schon:
1
while(1)
2
{
3
   my_delay( Switch_board(0) );
4
   Port_an;
5
   my_delay( Switch_board(1) );
6
   Port_aus;
7
}
Ist mit ASM Assembler gemeint?
Wenn ja, kann man Assembler nicht auch in C einbinden?
Wie kann ich denn
1
//***********************************************
2
void my_Delay(volatile unsigned long int Zeit)
3
{
4
  for(;Zeit>0;Zeit--);
5
}
6
//***********************************************
in Assembler schreiben und dieser Routine auch noch eine
unsigned long int variable übergeben?

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.