Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt kleiner 10us?


von Ramon M. (ramon_m)


Angehängte Dateien:

Lesenswert?

Hallo

Ich versuche mit einem ATmega644p (8MHz) den Timer Interrupt zu 
programmieren. Das funktioniert soweit auch mit dem Code im Anhang. 
Allerdings brauche ich eine kleinere Genauigkeit. Mit den 84 Zyklen 
erreiche ich nicht ganz 10us pro Inkrementation. Alles, was darunter 
liegt, verzögert das Ganze extrem, so dass die gewollte Sekunde zu 5 
Sekunden wird.

Der Fehler ist an sich nicht zu schlimm, das Ziel, das ich erreichen 
will, wird auch so funktionieren. Es wäre allerdings schöner mit 
besserer Auflösung.

Gruss Ramon

von Εrnst B. (ernst)


Lesenswert?

Du hast nicht unbegrenzt Zeit innerhalb deiner ISR zur Verfügung, wie du 
ja schon bemerkt hast.

Also, Generell: Mehr in Hardware zählen lassen, weniger in Software.

Zur Inspiration:
AVR - Die genaue Sekunde / RTC

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Ramon M. schrieb:
> Allerdings brauche ich eine kleinere Genauigkeit. Mit den 84 Zyklen
> erreiche ich nicht ganz 10us pro Inkrementation. Alles, was darunter
> liegt, verzögert das Ganze extrem, so dass die gewollte Sekunde zu 5
> Sekunden wird.

 Es sind 85 Zyklen und nicht 84.

 Auch so verbringt dein Programm 59 Zyklen (von 85) in der ISR,
 entspricht in etwa 70% der CPU-Zeit.
 Das ist nicht nur schlecht, es ist katastrophal.

 Das ist auch schlecht:
1
  if (counter0_250us == 94118)  // 1 Sekunde erreicht

 Das ist besser:
1
  if (counter0_250us > 94117)  // 1 Sekunde erreicht

 Was mich interessieren würde - wofür braucht man 10us ISR überhaupt ?

von Peter II (Gast)


Lesenswert?

Marc V. schrieb:
> Das ist auch schlecht:  if (counter0_250us == 94118)  // 1 Sekunde
> erreicht

warum findest du das schlecht? Das das ++ direkt darüber steht kann es 
doch zu keinem Fehler kommen.

von Thomas E. (thomase)


Lesenswert?

Marc V. schrieb:
> Das ist auch schlecht:  if (counter0_250us == 94118)  // 1 Sekunde
> erreicht
>
>  Das ist besser:  if (counter0_250us > 94117)  // 1 Sekunde erreicht

Und was ist daran besser?

von Huh (Gast)


Lesenswert?

Thomas E. schrieb:
> Marc V. schrieb:
>> Das ist auch schlecht:  if (counter0_250us == 94118)  // 1 Sekunde
>> erreicht
>>
>>  Das ist besser:  if (counter0_250us > 94117)  // 1 Sekunde erreicht
>
> Und was ist daran besser?

Würde mich auch interessieren. Bitte um eine Lehrstunde :-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter II schrieb:
> warum findest du das schlecht? Das das ++ direkt darüber steht kann es
> doch zu keinem Fehler kommen.
Thomas E. schrieb:
> Und was ist daran besser?
Huh schrieb:
> Würde mich auch interessieren. Bitte um eine Lehrstunde :-)

 Wow. Rudel zusammengekommen.
1
volatile uint32_t counter0_250us = 0;

 Es ist eine 32bit Variable, geht also bis 4,294,967,295.
 Falls diese Variable zufällig mit einem Wert´>= 94118 in die ISR
 reintrudelt, wird noch 4,294,967,294 Mal diese ISR angesprungen und
 munter weitergezählt, entspricht in etwa 12 Stunden.

 Deswegen.

 Wenn Ihr grösser seid und etwas mehr über Steuerungen und Sicherheit
 gelernt habt, gibt es weitere Stunden.

von Peter II (Gast)


Lesenswert?

Marc V. schrieb:
> Es ist eine 32bit Variable, geht also bis 4,294,967,295.
>  Falls diese Variable zufällig mit einem Wert´>= 94118 in die ISR
>  reintrudelt

woher soll der Zufall kommen? Wenn man sich auf den Code nicht verlassen 
kann ist eh alles zu spät.

Was ist wenn counter0_250us++; zufällig mal nicht funktioniert? Am 
besten noch eine 2 Variabel hochzählen und mit der ersten vergleichen?

von Huh (Gast)


Lesenswert?

"Wenn die Variable zufällig reintrudelt" klingt nicht so, als wenn du 
weißt, was du programmierst :-)
Aber du wirst sicherlich auch größer und lernst, daß eine Variable eher 
selten die Eigenschaft besitzt "zufällig reinzutrudeln" :-)))

von Huh (Gast)


Lesenswert?

P.S.: Nicht alles, was man an den Haaren herbeizieht, ist ein gutes 
Beispiel. Bzw. Nicht alles, was hinkt, ist ein Vergleich :-D

von Horst M. (horst)


Lesenswert?

Ramon M. schrieb:
> Mit den 84 Zyklen
> erreiche ich nicht ganz 10us pro Inkrementation.

Was wäre, wenn Du die Zählvariable mit 94118 lädst und dann 
dekrementierst?
Womöglich kann der Compiler den Test auf 0 besser optimieren.

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


Lesenswert?

Peter II schrieb:
> woher soll der Zufall kommen? Wenn man sich auf den Code nicht verlassen
> kann ist eh alles zu spät.

Das nennt sich defensiver Programmierstil und jeder der schon mal ein 
nichttriviales Programm debuggt hat, weiß das zu schätzen.

von Sebastian S. (amateur)


Lesenswert?

Eigentlich sollte es nie passieren, aber ich mache solche Abfrage 
ebenfalls so. Nach dem Motto: Wenn es irgend geht, nie auf Gleichheit 
abfragen.

von Peter II (Gast)


Lesenswert?

Axel S. schrieb:
> Peter II schrieb:
>> woher soll der Zufall kommen? Wenn man sich auf den Code nicht verlassen
>> kann ist eh alles zu spät.
>
> Das nennt sich defensiver Programmierstil und jeder der schon mal ein
> nichttriviales Programm debuggt hat, weiß das zu schätzen.

Das > hat sogar einen Nachteil, wenn man bei einem Speicherüberschreiber 
die Variabel "zufällig" erhöht. Dann fällt der Fehler viel schneller 
auf, als wenn es einfach ignoriert wird.

Es mag ja Geschmackssache sein, aber es als falsch oder schlecht zu 
bezeichnen ist hier nicht richtig.

von Einer K. (Gast)


Lesenswert?

Sebastian S. schrieb:
> Eigentlich sollte es nie passieren, aber ich mache solche Abfrage
> ebenfalls so. Nach dem Motto: Wenn es irgend geht, nie auf Gleichheit
> abfragen.

Sehe ich auch so...
Lieber <= oder >= als ==
== nur wenn es muss
Ist mittlerweile ein fester Automatismus.
Und fällt mir in fremden Texten sofort auf.

Aber wenns an der Stelle kein unmittelbares Problem macht..
Von mir aus ..
Jeder ist seines Glückes Schmied.

von Peter II (Gast)


Lesenswert?

Axel S. schrieb:
> Das nennt sich defensiver Programmierstil und jeder der schon mal ein
> nichttriviales Programm debuggt hat, weiß das zu schätzen.

dann bitte aber so
1
counter0_250us++;        //Alle 250us Variable incrementieren
2
if (counter0_250us == 94118)  // 1 Sekunde erreicht
3
{
4
  counter0_250us = 0;      //Timer zurücksetzen
5
  PORTD ^= 1<<0;        //LED toggeln
6
}
7
8
if counter0_250us > 94118) {
9
  while(1);
10
  //assert usw.
11
}

von Thomas E. (thomase)


Lesenswert?

Axel S. schrieb:
> Das nennt sich defensiver Programmierstil

Das ist ein Thema, was hier schon reichlich mit gefletschten Zähnen 
durchdiskutiert wurde. Ich lasse ohnehin immer rückwärts zählen und 
teste auf 0.

Vor allen Dingen aber, kann ich die arrogante Art von diesem 
eingebildeten Fatzke nicht ab:

Marc V. schrieb:
> Wow. Rudel zusammengekommen.

Marc V. schrieb:
> Wenn Ihr grösser seid und etwas mehr über Steuerungen und Sicherheit
>  gelernt habt, gibt es weitere Stunden.

von Sebastian S. (amateur)


Lesenswert?

>counter0_250us++;        //Alle 250us Variable incrementieren
>if (counter0_250us == 94118)  // 1 Sekunde erreicht
>{
>  counter0_250us = 0;      //Timer zurücksetzen
>  PORTD ^= 1<<0;        //LED toggeln
>}
>
>if counter0_250us > 94118) {
>  while(1);
>  //assert usw.
>}
Ein bisschen wie Hosenträger plus Gürtel;)
Kommt eine solche Abfrage nur gelegentlich vor: Kein Problem
Aber bei der anzunehmenden Häufigkeit...

von Olly (Gast)


Lesenswert?

Horst M. schrieb:
> Ramon M. schrieb:
>> Mit den 84 Zyklen
>> erreiche ich nicht ganz 10us pro Inkrementation.
>
> Was wäre, wenn Du die Zählvariable mit 94118 lädst und dann
> dekrementierst?
> Womöglich kann der Compiler den Test auf 0 besser optimieren.

10 µs rufen geradezu nach Assemblerprogrammierung. So etwas überlässt 
man nicht dem C-Compiler.

von Εrnst B. (ernst)


Lesenswert?

Olly schrieb:
> 10 µs rufen geradezu nach Assemblerprogrammierung. So etwas überlässt
> man nicht dem C-Compiler.

Vermute eher: Da stimmt grundlegend was am Design nicht.
Der AVR hat extra Hardware (Timer) um bei solchen Anforderungen nicht 
unbedingt ISR-Takte zählen muss.

Lässt sich ohne weitere Infos vom TE natürlich nicht sagen, was er 
(außer dem µS genauen Sekunden-Blinker) eigentlich machen will, aber ich 
vermute, dass er es unter Einsatz des ICP oder der Ouput-Compare/PWM 
Hardware stressfreier,  exakter, jitter-ärmer hinkriegt, wenn etwas 
Gehirnschmalz investiert wird.

von Horst M. (horst)


Lesenswert?

Olly schrieb:
> 10 µs rufen geradezu nach Assemblerprogrammierung. So etwas überlässt
> man nicht dem C-Compiler.

Klar, aber die Frage ist, ob der TE damit nicht völlig vom Weg abkäme.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Axel S. schrieb:
> Das nennt sich defensiver Programmierstil und jeder der schon mal ein
> nichttriviales Programm debuggt hat, weiß das zu schätzen.

Mit dem Vergleich auf '>=' verdeckst Du aber einen eventuellen 
Programmfehler, zum Beispiel einen Überschreiber der Variablen. Wenn 
dieser dann erst viele Monate später wegen einer Neuanordnung der 
Variablen auffällt, suchst Du Dich dumm und dämlich, denn: "an dieser 
Stelle habe ich schon eine Ewigkeit nichts mehr geändert!".

Lass es lieber sofort krachen. Dann findest Du den Fehler unmittelbar.

Unter "defensivem Programmierstil" verstehe ich etwas anderes: Wenn 
Werte von außen gegeben werden (z.B. durch Nutzerinteraktion oder von 
einem externen Gerät), dann ist es sinnvoll, vermeintlich niemals 
auftretende Werte zu prüfen. Aber im eigenen Programm?

Marc V. schrieb:
> Wenn Ihr grösser seid und etwas mehr über Steuerungen und Sicherheit
>  gelernt habt, gibt es weitere Stunden.

Wenn Du wirklich so programmierst und das noch als "Sicherheit" 
verkaufst, dann bist Du ein schlechter Lehrer.

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas E. schrieb:
> Das ist ein Thema, was hier schon reichlich mit gefletschten Zähnen
> durchdiskutiert wurde. Ich lasse ohnehin immer rückwärts zählen und
> teste auf 0.

 Und stehst genauso dumm da wie bei vorwärtszählen...


> Vor allen Dingen aber, kann ich die arrogante Art von diesem
> eingebildeten Fatzke nicht ab:

 LOL.
 Vielleicht wird das nur von dir und deinesgleichen als Arrogant
 empfunden, eines bin ich aber bestimmt nicht - eingebildet.
 Im Gegensatz zu dir und deinesgleichen.

von Thomas E. (thomase)


Lesenswert?

Marc V. schrieb:
> Vielleicht wird das nur von dir und deinesgleichen als Arrogant
>  empfunden, eines bin ich aber bestimmt nicht - eingebildet.
>  Im Gegensatz zu dir und deinesgleichen.

https://www.youtube.com/watch?v=2_0zwbNpJvI

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Wenn Du wirklich so programmierst und das noch als "Sicherheit"
> verkaufst, dann bist Du ein schlechter Lehrer.

 Ja, ich programmiere so und ja, ich nenne das Sicherheit.
 Verkaufen tue ich allerdings etwas anderes.

 Die Abfrage auf Gleichheit ist vom Sicherheitsaspekt her viel
 schlechter als Abfrage auf erreichen/überschreiten des Grenzwertes.

> Mit dem Vergleich auf '>=' verdeckst Du aber einen eventuellen
> Programmfehler, zum Beispiel einen Überschreiber der Variablen.

 Nein, mit diesem Vergleich engst du den möglichen Fehler auf
 +/- 1 Aufruf, anstatt auf +/- 4,294,873,176.

 Und es geht nicht immer um Programmfehler, es können auch andere
 Umstände dazu führen, auf welche du als Programmierer zum Zeitpunkt
 des Programmschreibens gar keinen Einfluss hast.

 Auf jeden Fall kostet es nichts, weder Code noch Zeit und deswegen
 ist diese Abfrage besser als blind auf eine einzige Möglichkeit aus
 gegebenen 4,294,967,295 zu vergleichen.

P.S.

 Mal angenommen, diese Variable zählt die Anzahl der 10us-Abschnitte
 die vergangen sind, seit in einem Industriekessel die Temperatur die
 125 Grad Grenze überschritten hat.

 Nach zwei Sekunden soll der Alarm losgehen.

 Wenn man auf die richtige Art prüft, gibt es keine Probleme, auch
 beim Überschreiben der Variable nicht.
 Wenn man einen auf AllesBesserWisser macht, (wie einige hier)
 fliegt die ganze Abteilung und vielleicht Fabrik in die Luft.

 Etwas klarer ?

: Bearbeitet durch User
von Jacko (Gast)


Lesenswert?

Ramon will aus 8,000 MHz mit CTC-Max = 84 (1/85) alle
10 µs ??? einen Interrupt auslösen.
Womöglich noch 86 Befehlstakte in der IRS unterbringen,
obwohl nur < 79 maximal möglich sind.

Muss man zu so einem Beitrag noch streiten?

Der Troll hat sich jedenfalls schon getrollt. ;-)

von Wolfgang (Gast)


Lesenswert?

Peter II schrieb:
> woher soll der Zufall kommen? Wenn man sich auf den Code nicht verlassen
> kann ist eh alles zu spät.

Da frag mal Satellitenbetreiber. Die wissen, warum strahlengehärtete 
Prozessoren und Fail Save Algorithmen eingesetzt werden. Auf der 
Erdoberfläche ist es dank einer soliden Atmosphäre schon seltener, das 
Höhenstrahlung zum Kippen eine Bits führt.

Wer das Risiko liebt, vergleicht auf Gleichheit.

von THOR (Gast)


Lesenswert?

Strahlungsgehärtet bedeutet, dass die keinen Strahlungsinduzierten 
Latch-Up haben können, nicht dass da keine Bits kippen.

von Peter D. (peda)


Lesenswert?

Ramon M. schrieb:
> Der Fehler ist an sich nicht zu schlimm, das Ziel, das ich erreichen
> will, wird auch so funktionieren. Es wäre allerdings schöner mit
> besserer Auflösung.

Dann wäre es besser, wenn Du mal das Ziel nennen würdest. Dann könnte 
man feststellen, ob es wirklich einen 10µs Interrupt benötigt oder 
anders lösbar wäre.

Zu beachten ist auch, daß der AVR keine Interruptprioritäten kann, d.h. 
jede weitere Interruptquelle würde die 10µs zusätzlich verlängern.

von Gerhard O. (gerhard_)


Lesenswert?

Also, ich bin der Ansicht, daß man in einer idealen Welt den uC 
Programmablauf nicht in eine Zeitzwangsjacke stecken sollte. Das ist 
immer ein Hinweis, daß besser anwendungspezifische Hardware 
zeitkritische Funktionen den Job erledigen sollte.

Die Auswahl und Funktionen der HW Peripherien, obwahl in manchen uC sehr 
vielseitig, hat auch ihre Grenzen. Wenn es die nicht alleine sauber 
schaffen eine Aufgabe ohne Klimmzüge zu erledigen, ist das immer ein 
Anzeichen, daß in der Richting etwas unternommen werden sollte.

Auch wenn tüfteliges Assemblieren es trotzdem schafft, macht man sich 
nur das Leben unnötig schwer.

Wenn es die eingebauten HW Resourcen eines uC eben nicht alleine 
schaffen, dann sollte man besser externe HW wie CPLD, FPGA oder 
spezifisch geschaltete Logikbausteine einsetzen. Damit ist das Programm 
von den Hardware Abläufen entkoppelt und dient lediglich der Steuerung 
der Randbedingungen einschließlich Datenverbindung mit externen 
Entitäten.

Die Zeit die Manche aufwenden müssen um den uC (und sich) zu quälen um 
zeitsynchrone Funktion zu erzielen wäre einer besseren Sache wert. 
Jedenfalls halte ich es so und bin damit immer sehr gut damit gefahren.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Zu beachten ist auch, daß der AVR keine Interruptprioritäten kann, d.h.
> jede weitere Interruptquelle würde die 10µs zusätzlich verlängern.

"Jacko (Gast)" hat gestern schon angemerkt, dass bereits die 
ürsprünglichen Annahmen des TO völlig unrealistisch sind (und dabei noch 
massiv untertrieben, denn tatsächlich stehen bei 8MHz Systemtakt und 
100kHz Interrupfolgefrequenz nicht 79, sondern bestenfalls 70 Takte für 
Nutzcode in der ISR zur Verfügung.

Jacko hat hier den Interruptframe mit mindestens 8 Takten vergessen und 
auch die Tatsache, dass in main() zwangweise eine Schleife laufen muss, 
die zwangsweise irgendwie geschlossen werden muss, was im worst case 
eben nicht nur einen, sondern zwei Takte klaut. Und bei regelmäßig 
erfolgenden Interrupts kann man nunmal nicht darauf hoffen, das der 
nächste erst später erfolgt und so das Debit ausgeglichen werden kann...

Und in C bleiben von diesen schon rein theoretisch maximal 70 nutzbaren 
Takten nochmal deutlich weniger über. Sogar erschreckend wenig, genau 
das ist ja, was ich an C ständig kritisiere und warum ich für den AVR 
praktisch ausschließlich in Assembler programmiere.

> Dann wäre es besser, wenn Du mal das Ziel nennen würdest. Dann könnte
> man feststellen, ob es wirklich einen 10µs Interrupt benötigt oder
> anders lösbar wäre.

Ja, das allerdings ist ein sehr guter Einwand. Manche glauben ja einfach 
nur, solche Zeitauflösung zu benötigen, weil sie letztlich einen 
dümmlichen Polling-Ansatz mit Hilfe von Interrupts umsetzen wollen...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

c-hater schrieb:
> "Jacko (Gast)" hat gestern schon angemerkt, dass bereits die
> ürsprünglichen Annahmen des TO völlig unrealistisch sind (und dabei noch
> massiv untertrieben, denn tatsächlich stehen bei 8MHz Systemtakt und
> 100kHz Interrupfolgefrequenz nicht 79, sondern bestenfalls 70 Takte für
> Nutzcode in der ISR zur Verfügung.

 Wie ich gestern schon angemerkt habe:
Marc V. schrieb:
> Auch so verbringt dein Programm 59 Zyklen (von 85) in der ISR,
>  entspricht in etwa 70% der CPU-Zeit.
> Das ist nicht nur schlecht, es ist katastrophal.

 Das man in den verbleibenden 24-26 Takten nichts gescheites machen
 kann, ist wohl klar. Zumindest nichts, ohne ständig unterbrochen
 zu werden.


 Und meine Frage (auch von gestern) steht immer noch:
Marc V. schrieb:
> Was mich interessieren würde - wofür braucht man 10us ISR überhaupt ?

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Sparfüchse können die ISR auch "nacked" machen, sind dann aber für jeden 
Furz selber verantwortlich.

von Ramon M. (ramon_m)


Lesenswert?

c-hater schrieb:
>> Dann wäre es besser, wenn Du mal das Ziel nennen würdest. Dann könnte
>> man feststellen, ob es wirklich einen 10µs Interrupt benötigt oder
>> anders lösbar wäre.
>
> Ja, das allerdings ist ein sehr guter Einwand. Manche glauben ja einfach
> nur, solche Zeitauflösung zu benötigen, weil sie letztlich einen
> dümmlichen Polling-Ansatz mit Hilfe von Interrupts umsetzen wollen...

Ich habe zwei Rechtecksignale mit einer Frequenz von 5 kHz, die 
phasenverschoben sind. Ich will bei positiver Flanke der beiden Signale 
die Timervariabel auslesen, um dann die Zeitdifferenz zwischen den 
beiden positiven Flanken und somit die Phasenverschiebung ausrechnen zu 
können.
Ausserdem wirde noch der Assembler genannt. Ich möchte hier noch sagen, 
dass ich den Assembler überhaupt nicht beherrsche, und nicht die Zeit 
dazu habe, diesen noch zu lernen.

von THOR (Gast)


Lesenswert?

Dann gibst du das eine Rechteck auf INT0 und das zweite auf INT1, lässt 
ab dem ersten Interrupt den Timer loslaufen und stoppst ihn beim 
Zweiten.

von Gerhard O. (gerhard_)


Lesenswert?

Wie wäre mit zwei CAPTURE Eingängen die von einem gemeinsamen TIMER 
gespeist werden? Den CAPTURE stellt man auf beiden Kanälen so ein, daß 
sie auf die positiven Flanken reagieren. Dann braucht man nur zu warten 
bis die CAPTURE Logik die entsprechende ISR triggert. Danach können die 
beiden CAPTURE Event Werte nebst etwaigen overflows dann bequem 
innerhalb von weniger als 200us behandelt werden und kann den 
Zeitunterschied supergenau erfassen.

Bei 1MHz Timer Clock ist die Auflösung immerhin 1us und ist beim AVR bei 
entsprechender Quarzfrequenz noch nicht einmal die oberste Grenze. Bei 
dem vorher vorgeschlagenen INT0/1 Methode ist doch ein nicht zu 
vernachläßigbarer Overhead. Bei 16Mhz Quarzfrequenz stellt man z.B. den 
Prescaler für 1us Auflösung auf 16 ein damit der 16-bit TIMER mit 1Mhz 
getaktet wird.

Mir ist diese Hardware Methode lieber weil die Messung komplett in 
Hardware realisiert sein würde. Das läßt sich alles bequem ohne 
Assembler erledigen. Ich finde man sollte die uC Resourcen diesbezüglich 
voll ausschöpfen.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ramon M. schrieb:
> um dann die Zeitdifferenz zwischen den
> beiden positiven Flanken und somit die Phasenverschiebung ausrechnen zu
> können.

Dann kannst Du beide Signale abwechselnd über den analog Multiplexer und 
analog Comparator an den Capture Input legen. Damit erreichst Du sogar 
125ns Auflösung, also 80-mal besser als mit 10µs und hast keinerlei 
Zeitprobleme mehr.
Wichtig ist, im Capture-Mode den Timer durchlaufen zu lassen und die 
Differenz der Timestamps zu nehmen. Ein SW-Reload oder Start/Stop würde 
sonst wieder einen Jitter bewirken.
Den Fall, daß die Phasenverschiebung klein ist und daher die Signale nur 
jede 2. Periode triggern, stellt man einfach dadurch fest, daß nun statt 
5kHz die Periode eines Eingangs 2,5kHz entspricht.

von m.n. (Gast)


Lesenswert?

Ramon M. schrieb:
> Ich habe zwei Rechtecksignale mit einer Frequenz von 5 kHz, die
> phasenverschoben sind. Ich will bei positiver Flanke der beiden Signale
> die Timervariabel auslesen, um dann die Zeitdifferenz zwischen den
> beiden positiven Flanken und somit die Phasenverschiebung ausrechnen zu
> können.

Mit ein bißchen Rechnerei kann man die Phasenverschiebung auch direkt 
anzeigen. Das Programm wertet die Signale an INT0 und INT1 aus, wobei 
die jeweilige Flanke einstellbar ist: 
Beitrag "Stoppuhr – Geschwindigkeit – Pulsweite mit Atmega88"

von Ramon M. (ramon_m)


Lesenswert?

Gerhard O. schrieb:
> Wie wäre mit zwei CAPTURE Eingängen die von einem gemeinsamen TIMER
> gespeist werden? Den CAPTURE stellt man auf beiden Kanälen so ein, daß
> sie auf die positiven Flanken reagieren. Dann braucht man nur zu warten
> bis die CAPTURE Logik die entsprechende ISR triggert. Danach können die
> beiden CAPTURE Event Werte nebst etwaigen overflows dann bequem
> innerhalb von weniger als 200us behandelt werden und kann den
> Zeitunterschied supergenau erfassen.

Das klingt schon mal sehr vielversprechend. Allerdings wäre ich jetzt 
froh um ein Codebeispiel, da ich die Interrupts noch nie benutzt habe. 
Ich weiss nicht, wie ich die Interrupts konfigurieren und starten muss 
und wie ich dann den Timer auslöse.

von Ramon M. (ramon_m)


Lesenswert?

Ramon M. schrieb:
> Das klingt schon mal sehr vielversprechend. Allerdings wäre ich jetzt
> froh um ein Codebeispiel, da ich die Interrupts noch nie benutzt habe.
> Ich weiss nicht, wie ich die Interrupts konfigurieren und starten muss
> und wie ich dann den Timer auslöse.

Korrektur: INT0 und INT1 auf positive Flanken zu konfigurieren habe ich 
geschafft, allerdings weiss ich nun nicht, wie ich den Timer starten 
soll. Muss das in der ISR von INT0 und INT1 geschehen?

von m.n. (Gast)


Lesenswert?

Ramon M. schrieb:

> Allerdings wäre ich jetzt
> froh um ein Codebeispiel

Noch eins?

von Stephan (Gast)


Lesenswert?

Ramon M. schrieb:
> Ich versuche mit einem ATmega644p (8MHz) den Timer Interrupt zu
> programmieren. Das funktioniert soweit auch mit dem Code im Anhang.

Ramon M. schrieb:
> Das klingt schon mal sehr vielversprechend. Allerdings wäre ich jetzt
> froh um ein Codebeispiel, da ich die Interrupts noch nie benutzt habe.
> Ich weiss nicht, wie ich die Interrupts konfigurieren und starten muss

ja was nun ? Ist der Timer Interrupt kein Interrupt ? Im Int0 oder 1 
einfach den Timer starten und stoppen. Konfigurieren kannst du den ja 
schon vorher in Ruhe oder er läuft durch und Du gibst nur den Int in der 
ISR frei. Viele Wege führen nach Rom.

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


Lesenswert?

Ramon M. schrieb:
> Ramon M. schrieb:
>> Das klingt schon mal sehr vielversprechend. Allerdings wäre ich jetzt
>> froh um ein Codebeispiel, da ich die Interrupts noch nie benutzt habe.
>> Ich weiss nicht, wie ich die Interrupts konfigurieren und starten muss
>> und wie ich dann den Timer auslöse.
>
> Korrektur: INT0 und INT1 auf positive Flanken zu konfigurieren habe ich
> geschafft, allerdings weiss ich nun nicht, wie ich den Timer starten
> soll. Muss das in der ISR von INT0 und INT1 geschehen?

Du brauchst weder INT0 nocht INT1. Du sollst die Capture-Funktionalität 
der Zähler/Timer im AVR benutzen. Und der Timer wird nur einmal 
gestartet, wenn dein Programm losläuft. Danach wertest du nur noch die 
Differenz des Zählerstands zwischen zwei Capture-Ereignissen aus.

Lies hier: AVR-GCC-Tutorial/Die Timer und Zähler des AVR
und hier: High-Speed capture mit ATmega Timer

benutze ruhig auch die Suchfunktion (Stichwort: "capture") des Forums

: Bearbeitet durch User
von Ramon M. (ramon_m)


Lesenswert?

Naja, ich habe da einen Mist erzählt. Mittlerweile konnte ich den 16 Bit 
Timer mit der Capture Funktion zu meinen Gunsten konfigurieren. 
Allerdings habe ich nun das Problem, dass es nur einen Capture Eingang 
gibt und ich zwei Signale habe. Ich glaube ich könnte aus den zwei 
Signalen eines machen mit einer Schaltung, das Problem ist nun aber, 
dass ich die Interrupts deaktivieren muss, um den Capture Wert 
auszulesen. Dadurch wird doch auch der Timer angehalten, oder?
Mit INT0 und INT1 den Timer starten und stoppen hat noch nicht 
funktioniert

von Peter II (Gast)


Lesenswert?

Ramon M. schrieb:
> das Problem ist nun aber,
> dass ich die Interrupts deaktivieren muss, um den Capture Wert
> auszulesen. Dadurch wird doch auch der Timer angehalten, oder?

wenn man die Interrupts deaktivieren laufen die Timer weiter, aber warum 
musst du ihn überhaupt deaktivieren? Wenn du in einer ISR bist, sind sie 
schon deaktiviert.

von Ramon M. (ramon_m)


Lesenswert?

Peter II schrieb:
> Wenn du in einer ISR bist, sind sie
> schon deaktiviert.

Nur bin ich nicht in einer ISR mit der Capture Funktion. Ich habe die 
Werte im main ausgelesen. Habe ich da was falsch gemacht?

von Peter II (Gast)


Lesenswert?

Ramon M. schrieb:
> Nur bin ich nicht in einer ISR mit der Capture Funktion. Ich habe die
> Werte im main ausgelesen. Habe ich da was falsch gemacht?

das müsste richtig sein, aber warum willst du beim auslesen die ISR 
sperren?

Zeig doch mal wie du es genau machst.

von Ramon M. (ramon_m)


Lesenswert?

In dem Code habe ich auch noch die ISR drin (auskommentiert)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ramon M. schrieb:
> In dem Code habe ich auch noch die ISR drin (auskommentiert)

Sorry, ich habe ihn (als Mod) versehentlich gelöscht, als ich auf die 
Codeansicht wollte. Kannst Du ihn nochmal reinstellen?

von Ramon M. (ramon_m)


Angehängte Dateien:

Lesenswert?

Kein Problem ;)

von Peter D. (peda)


Lesenswert?

Ramon M. schrieb:
> Ich glaube ich könnte aus den zwei
> Signalen eines machen mit einer Schaltung

Die Schaltung befindet sich bereits im ATmeg644.
Schau mal im Datenblatt unter:
1
24.2. Analog Comparator Multiplexed Input

Du kannst insgesamt 9 Pins auf den Analog Comparator legen und dessen 
Ausgang auf den Capture-Input.
AIN0 legt man auf die Bandgap (1,1V) als Schwelle.
Nach jedem Umschalten muß man das ICF1-Bit setzen, damit kein 
Pseudointerrupt auftritt.

von Jakob (Gast)


Lesenswert?

10 µs Interrupt bei 8 MHz.

Kann man machen, WENN MAN GENAU WEISS,
A) dass man max. 70 Takte zur Verfügung hat
B) dass man JEDEN Takt JEDER weiteren ISR (inklusive
   10 Takte Aufruf + Rücksprung) von den 70 abziehen muss.
C) Der Rest muss für's Hauptprogramm reichen.

Ist also machbar. Gibt dann auch plausible Ergebnisse.

Aber, so wie du fragst, würde ich mal sagen:
Das hast du nicht berechnet.

Ergebnis: Mal macht er's, mal nicht...

von Ramon M. (ramon_m)


Lesenswert?

Peter D. schrieb:
> 24.2. Analog Comparator Multiplexed Input

Ich habe mir das angesehen und ich verstehe das ehrlich gesagt gar 
nicht...
Entweder nimmt man AIN0 und AIN1 oder man ersetzt AIN1 durch die 
Analogeingänge. Habe ich das so richtig verstanden? Und so wie ich das 
verstehe, muss man den Eingang selber mit den MUX Bits auswählen?

von Peter D. (peda)


Lesenswert?

Für 2 Eingänge reicht auch schon, zwischen ICP und AIN1 umzuschalten.
Den MUX brauchst Du erst für 3..10 Eingänge oder wenns fürs Layout 
besser paßt.

von Ramon M. (ramon_m)


Lesenswert?

Peter D. schrieb:
> Für 2 Eingänge reicht auch schon, zwischen ICP und AIN1 umzuschalten.

Okay. Vielleicht tue ich mich hier schwer, aber wieso jetzt ICP und AIN1 
und nicht AIN0 und AIN1?
Und sollte dann jede Flanke von beiden Signalen ein Capture Event 
auslösen?

von M. K. (sylaina)


Lesenswert?

Ramon M. schrieb:
> Und sollte dann jede Flanke von beiden Signalen ein Capture Event
> auslösen?

Du könntest die erste Flanke als Startbedingung wählen (z.B. über ein 
Pin-Change-Event) und die zweite als Capture-Event.
Schau noch mal was genau Peter hier geschrieben hat, er hat dir oben 
sicher schon ein paar Tipps gegeben (hab den Fred nicht komplett 
gelesen).

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei mal ein Beispielcode (ungetestet).

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.