PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer1 - Clear Timer on Input-Capture?



Tyrald
25.05.2010, 18:52
Timer1 ist ja u.a. auch zur Frequenzmessung gedacht und dafür möchte ich Ihn auch benutzen.

CPU Frequenz und Prescaler sind für miene Frage ja nicht relevant.

Wenn am ICP1 die flanke steigt soll ein Zeitstempel angelegt werden:
TCCR1B &= (1<< ICES1);

nun wäre es doch mehr als sinnvoll, wenn dieses Ereignis auch gleich den Timer zurücksetzt! Oder muss man in der Interrupt-Routine, die mit dem Input-Capture ausgelößt werden kann, den Timer "von Hand" reseten?
Da gingen jedoch ein paar Takte verloren und der Gecapturte Wert währe immer ein bisschen zu klein.

Beim rauf und runter lesen vom Atmega8535 Datenblatt hab ich nix gefunden!

Besserwessi
25.05.2010, 21:31
Ein zurücksetzen des Timers auf ein Externes Signal ist nicht vorgesehen. Für die Genaue Zeitmessung läßt man den Timer einfach weiterlaufen und mißt die Zeit für das Start und Stop Ereigniss getrennt. Man ließt das ICP resgister alle 2 mal aus. Einmal für den Start, und einmal für Stop. Dannach kann man die Differenz berechnen. Im RN-Wissen unter timer steht dazu ein Beispiel.

Destrono
25.05.2010, 21:35
Hallo,
das würde mich auch interessieren.
Ich bräuchte den Timer zur Drehzahlbestimmung am Motor über Hall Sensor.
Da habe ich im Grunde auch das selbe Problem, denn wie soll ich wissen, wie lange er für eine Umdrehung gebraucht hat, wenn der Timer nicht zurückgesetzt wird. Evlt. könnte man das noch mit der Differenz zwischen letzten Timerwert und aktuellem Timerwert ausrechnen. Dann hätte ich aber immer noch das Problem, dass eine Messung, nämlich die beim Overflow nicht stimmt.
Wenn das Problem mit dem Overflow nicht wäre, müsste es über die Differenz gehen.
Hat jemand eine Idee, wie man das lösen kann ?

MfG
Destrono

Destrono
25.05.2010, 21:39
habe gerade gemerkt, dass ich zu langsam war mitm Posten.
Es bleibt aber immer noch die Frage, ob bei der Differenzrechnung von neuer Wert - alter Wert während des Overflows nicht ein Fehler auftritt

sternst
25.05.2010, 21:46
Es bleibt aber immer noch die Frage, ob bei der Differenzrechnung von neuer Wert - alter Wert während des Overflows nicht ein Fehler auftrittBei nur einem Overflow nicht. Und wenn mehrere Overflows auftreten können, muss man das so oder so zusätzlich berücksichtigen.

oberallgeier
25.05.2010, 23:49
... bräuchte den Timer zur Drehzahlbestimmung am Motor ...Ich weiß nicht, wieviele Lösungsmöglichkeiten es an At mel-Megas bzw. in C gibt. Meine Lösung ist nur eine davon, sie läuft. (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=463986&sid=8a792a36e7fa73558d75ed2539e0afbf#463986) Das Konzept stammt aus einer Zeit, in der meine C-Kenntnisse noch bescheidener als heute waren; es ist also sicher KEIN Optimum. Mir ist klar, dass die Zeitmessung mit Auslesen des aktuellen Counterstandes genauer wäre - wäre aber eben ein anderer Lösungsweg, den ich in der Konzeptphase nicht schaffte.

Diese Zeitmessung hat als Zeitsignal einen 50 µs-Takt mit dem Timer2 am mega168/328 - damit brauche ich bei 20 MHz (wenn ichs grad richtig im Kopf habe) unter 5 % CPU-Zeit bzw. knapp 60 Maschinenbefehle (*.lls). In der ISR wird ein 2Byte-Counter hochgesetzt - theoretisch geht das also über 3 sec gut, praktisch zählt diese Uhr eine Sekunde bis der Counter zurückgesetzt wird. Ausgelesen wird diese Boardzeit in einer ISR, die vom extINT ausgelöst wird, der auf die steigende Flanke einer Gabellichtschranke mit vier Schlitzen an der Motorwelle anspricht. Max. Drehzahl des Motors unter 800 Hz, dh. weniger als 2400 Hz Interrupts an der Gabellichtschranke. Derzeit wird nur jeder zweite Interrupt gezählt, so als hätte die Encoderscheibe (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=437282&sid=8d097fe1fcf82ede29d1e84fc8cfff32#437282) nur zwei Schlitze *ggg*. Die Timerinitialisierung setze ich als geläufig voraus. Die ISR für die Boardzeit sieht so aus:
/* ================================================== ============================ */
/* === Nicht unterbrechbare ISR für timer2 ===================================== */
/* Routine zählt hoch im Takt 20 kHz = 50 µs. Der Zählerwert wird von den ISR für
EXT_INT0 und -INT1 ausgelesen und den Werten Iz_yseci zugewiesen ...... */
ISR(TIMER2_COMPA_vect) // Vektor 7
{
if (Izeit_1 < Izthrznt) //Interrupt-Timer = 0 ... 19 999 ... (1 sec blink)
{
Izeit_1 ++; // ###>>> Izeit_1 ist aktuell int16_t ==>>
} // Izeit_1 bleibt bis 32000 in der int16-Grenze
else
{
PORTC ^= (1<<PC5); // LED auf Port PC5/I2C/SCL toggeln
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
icntdwn = icntdwn + 1; // Countdownzähler hoch(!!)zählen
if (icntdwn < 0) // Countdownzähler geht maximal 9 Std.
icntdwn = 0;
if (Iencdr0 == Ienc0alt) { Iz_diff0 = 0; }
}
}
/* ================================================== ============================ */
Nachteil: Bei hohen Drehzahlen habe ich Werte um 13 tupsi (Timer Units Per Sensor Interrupt) - das ist also recht grob für die Regelaufgabe. Eine Drehrichtungserkennung ist nicht möglich - das liegt aber nicht an der Zeitmessung. Eine Stillstandserkennung ist nicht so ohne weiteres möglich, derzeit wird ein hoher Zählerstand als Stillstand definiert.
Vorteil: Es geht kein Zeitbruchstück verloren, übrige "Zeitbruchteile" werden der folgenden Messung zugeschlagen. Das dadurch auftretende Flattern des Zeitsignals durch diese Zeitbruchteile um den tatsächlichen Wert wird vom Regler ausgebügelt. Ausserdem wird dieser 50µs-Takt für andere Aktionen als Zeitsignal genutzt. Die toggelnde LED auf PC5 ist ein praktisches Signal für die Timerfunktion. Der ebenfalls mitlaufende Countdown icntdwn wird (ebenfalls) für Zeitmessungen benutzt, er geht theoretisch für Zeitmessungen bis 18 Stunden mit Sekundengenauigkeit.

Destrono
28.05.2010, 11:12
Hallo,
Danke an oberallgeier für die ausführliche Beschreibung. Leider habe ich das nicht ganz verstanden, weil mir die Kenntnisse für die Kontrollerinternen Vorgänge fehlen.
Ich habe es jetzt mit der oben beschriebenen Methode versucht und bin gescheitert, da der Kontroller die Zeit für eine Umdrehung nicht richtig oder gar nicht berechnet.
Als Tachosignal verwende ich einen Lüfter (ist im Grunde nichts anderes als ein Hallsensor).
Verarbeitet wird das Signal über den Input Capture Interrupt. In der ISR wird dann auch gleich die Zeitdifferenz für aufeinanderfolgende Interrupts berechnet. Mein Atmega 16 läuft mit 8Mhz und als Prescaler für den Timer1 habe ich 1024 verwendet.
Der Timer wird also mit einer Frequenz von 7812,5 erhöht.
Folglich habe ich die Zeitdifferenz zweier aufeinanderfolgender Interrupts durch 7,813 geteilt, um auf die Millisekundendifferenz zu kommen.
Nachdem ich feststellen musste, dass das nicht funktioniert habe ich die Rechnung vereinfacht und die Zeitdifferenz nur noch durch 7 teilen lassen. Auch dabei kommen keine vernünftigen Werte raus.
Nebenbei lasse ich in der ISR auch die Anzahl der Interrupts (entspricht der Anzahl der Lüfterumdrehungen) hochzählen. Zumindest das macht er.

Wenn ich den Lüfter mit der Hand drehe, dann bekomme ich ordentliche plausible Ergebnisse für die Zeitdifferenz. Wenn ich den Lüfter hingegen unter Strom setze, scheint der Kontroller nicht mehr hinterherzukommen und er zeigt für die Zeitdifferenz entweder 0 oder 36 ms an. Dieser Wert ändert sich auch nicht , wenn ich den Lüfter mit der Hand abbremse :(

Hat jemand eine Idee, was ich ändern muss, damit das noch funktioniert?
Den Code kann ich leider schlecht posten, da er aus mehreren Teilen besteht.

Dann hätte ich noch eine Frage:
Ich habe den Kontroller so programmiert, dass er die steigende Flanke des Tachosingals vom Lüfter für einen Input Captur Interrupt auswerten soll. Bei einem Wechsel von low auf high funktioniert das auch wunderbar, nur dummerweise registriert er auch beim Wechsel von high auf low gleich mehrere (bis zu 10 ) interrupts auf einmal :(
Ich habe mir jetzt damit beholfen, einen Kondensator am Einganspin dranzuhängen. Damit ist das Problem behoben, aber ich kann mir vorstellen, dass ich bei hohen Drehzahlen Probleme bekommen könnte.
Hat jemand eine Idee, woran das liegt?
Das Problem, dass er Zeit für eine Umdrehung nicht richtig ausgibt hat nicht mit dem Kondensator zu tun, da das Problem auch ohne Kondensator besteht.

MfG
Destrono

Besserwessi
28.05.2010, 13:00
Das man mehrere Interrupts bei einer Flanke beim langsamen drehen bekommt kann an einer Art Prellen liegen. Die Lösung mit dem Kondensator ist schon nicht schlecht. Wenn der Kondensator klein genug ist, sollte es auch noch zu ziehmlich hohen Drehzahlen funktionieren. Eventuell müßte noch ein Widerstand vor den Kondensator, wenn der Ausgangswiderstand des Sensors sehr unsymetrisch ist.
Wenn die Messung beim langsamen Drehen funktioniert, nicht aber wenn der Motor läuft, könnte das Porblem von Störungen vom Motor kommen, also eine Hardware Problem und keines in der Software.

Ohne Code ist es schwer einen Fehler zu finden. Damit die Rechnung mit dem Überlauf richtig funktioniert, sollte man mit Variablem vom Typ Word rechnen. Könnte es sonst noch sein, das beim Auslesen des ISP registers was durcheinander gerät mir high/low Byte ? 36 ms würde gerade zu 256 Timer-schritten passen.

Destrono
28.05.2010, 17:05
Wenn die Messung beim langsamen Drehen funktioniert, nicht aber wenn der Motor läuft, könnte das Porblem von Störungen vom Motor kommen, also eine Hardware Problem und keines in der Software.


Hallo,
danke für die Antwort. Ich habe den Kontroller wegen diesem Problem jetzt schon mindestens 20 mal mit einer abgeänderten Software geflasht und er geht immer noch nicht. Ich versuche das noch mal genauer zu beschreiben. Ich hatte den Lüfter mit den Input Capture Interrupt dran, dann noch einen Adc mit Poti und einen Timer der Sekunde für Sekunde nach oben zählt. Alle diese Werte habe ich dem Display ausgeben lassen. Da der Adc auch bei laufenden Lüfter auf jede kleinste Veränderung reagiert und sofort der richtige Wert am Display ausgegeben wird ( was in der while Schleife der main Funktion passiert) kann ich mir nicht vorstellen, dass der Kontroller überlsatet ist.
Ich habe zur Sicherheit trotzdem den Code so abgeändert, dass nur noch der Input Capture Interrupt verarbeitet wird (also kein Adc mehr). Auch das hat nicht gebracht. Auch habe ich die Zeitdifferenz nicht mehr teilen lassen, sondern direkt auf dem Display ausgegeben und auch bringt keine Verbesserung, da er jetzt bei laufendem Lüfter für die Zeitdifferenz nur 256 oder 0 ausgibt :(
Nebenbei habe ich auch noch eine Led toggeln lassen, wenn der Interrupt auftritt. Das funktioniert komischerweise wunderbar, denn wenn der Lüfter auf voller Drehzahl läuft, wird die Led praktisch gedimmt und wenn ich dne Lüfter mit der Hand abbremse kann man irgendwann bei langsamer Lüfterdrehzahl ein Blinken erkennen.
Auch die Anzahl der Interrupts, die ich ebenfalls auf dem Display ausgeben lasse, werden vernünftig hochgezählt.
Da ich noch Anfänger bin, was die Avrs betrifft, werde ich jetzt doch mal meinen Code ausschnittsweise posten:

Hier die ISR:
Ich lasse die Zeitdifferenz für eine Umdrehung erst nach 4 Interrupts berechnen, weil der Lüfter für eine Umdrehung 4 mal von low auf high wechselt. Sobald "difference_new" ihren Wert verändert, wird der neue Wert in der Hauptschleife auf dem Display ausgegeben.


ISR(TIMER1_CAPT_vect)
{
PORTC ^= (1<< PC7); //PC7: Led
if (test >9998){ // Test zählt die interrutps und gibt sie auf dem Display aus

test = 1;}
else { test ++;}



if (calculate >= 3){
timer_compare_new= ICR1L;
timer_compare_new= ( ICR1H<< 8);
difference_new = (timer_compare_new - timer_compare_old);
timer_compare_old = timer_compare_new;
calculate =0 ;

}

else{
calculate ++;}
}


Hier ein Auszug aus meinem headerfile, in dem die Variablen deklariert werden:
Alle Variablen, die sowohl von der ISR als auch von den Funktionen aus der Main genutzt werden habe ich als volatile deklariert und ihnen in der Main Funktion, aber noch vor der while Schleife, den Wert 0 zugeordnet.
Ist das in Ordnung mit volatile?


volatile uint16_t timer_compare_new;
volatile uint16_t timer_compare_old;
volatile uint16_t difference_new;
uint16_t diff_old;
volatile uint8_t calculate;


Den Code aus der main Funktion spare ich mir, weil er ja bei langsamen Drehzahlen (nicht schneller, als man mit der Hand so nen Lüfter drehen kann) vernünftige Werte für die Zeitdifferenz liefert und auch bei laufenden Lüfter die Adc Werte sofort aktuallisiert hat, was darauf schließen lässt, dass die main Funktion noch ausreichend häufig durchlaufen wird, also nicht von Interrupts lahmgelegt ist.

Würde mich sehr freuen, wenn ihr mir noch mal helfen könntet, da ich mit meinem Latein jetzt echt am Ende bin und schon viel Zeit in dieses Projekt investiert habe.

MfG
Destrono

sternst
28.05.2010, 17:17
timer_compare_new= ICR1L;
timer_compare_new= ( ICR1H<< 8);Ist es Absicht, dass du den Wert aus ICR1L einfach "wegschmeißt" und nur den Wert aus ICR1H verwendest? Ich vermute mal nein, denn sonst würde es dich ja nicht wundern, dass du als Ergebnis nur 0 oder 256 bekommst. ;-)

Warum machst du es dir nicht etwas einfacher, und verwendest "timer_compare_new= ICR1;".

Destrono
28.05.2010, 18:58
NEIN, verdammt, das ist ja bitter. ](*,)
Ich ärgere mich jetzt fast 2 Tage lang damit rum, versuche und tue und alles scheitert, nur weil da ein einfacher "oder Strich" fehlt.
Vielen Dank für den Hinweis jetzt funktioniert es endlich. Ich bin richtig erleichtert, jetzt kanns endlich weiter gehen.
Gibt es sonst noch was an dem Code, was ich verbessern könnte?
Bin für Verbesserungsvorschläge immer dankbar, da ich mich nur an den Tutorials orientieren kann.

MfG
Destrono

Koertis
11.08.2010, 11:12
Hallo Leute,
Ich versuche auch mit einem Atmega644 20Mhz die Umdrehung zu messen.
Ich habe mir das so vorgestellt: immer wenn der Hallsensor eine positive Flanke sendet. Soll der aktuelle Zählerwert gespeichert und zurückgesetz (man kann ihn Zurücksetzen steht im Datenblatt) werden.
Stimmt das das ich den Hall sensor am Capture Pin anschließen muss (OC2B ?)um den 16-bit Timer zu benutzen?

p.s. Ich habe noch nie mit Timern gearbeitet...
lg

Besserwessi
11.08.2010, 14:25
Man kann den Timer auch über einen anderen Eingang nutzen. Es bietet sich aber an auch den Input-capture Pin zu nutzen.

Wenn es sehr genau werden soll, sollte man den timer nicht zurücksetzen, sondern die Differenz berechnen. Bei zurücksetzen hat man immer noch die Verzögerung bis die ISR ausgeführt wird, und die ist nicht immer ganz gleich.

Destrono
11.08.2010, 22:20
Hallo,
dazu hätte ich dann auch gleich noch mal eine Frage:
Bei meiner Zündanlage ist der Hallsensor bei ca. 40 Grad vor dem Totpunkt des Motors angebracht,bei dem gezündet werden muss.
In Abhängigkeit von der Drehzahl muss der Kontroller also die Zeit warten, die der Motor vom Durchlaufen des Hallsensors bis zum Totpunkt braucht. Dafür werde ich auch einen Timer einsetzten müssen und der muss wohl auch jedes mal neu gestartet werden, dann bei einem bestimmten Ocp Wert einen Interrupt auslösen, anschließend wieder gestoppt werden und das TCNTx Register muss auf 0 zurückgesetzt werden, oder gibt es da eine elegantere Lösung?
Wenn nein, gibt es einen Möglichkeit herauszufinden wie lange der Kontroller alleine für das Starten des Timers braucht? Denn die Zeitintervalle müssen in diesem Fall bis auf die ms stimmen.

MfG
Destrono

Koertis
12.08.2010, 07:26
Hallo,
Also wenn ich mein Programm Simuliere, wird nicht PD6 (Capture Pin) verwendet, sondern PD4 (OC1B). Sollte nicht PD6 verwendet werden sobald ich das Register ICIE1 auf High setze?

Meine 2 Frage ist, wenn ich einen Timer2 bis OCR2A laufen lasse, dann kommt es zu einem Overflow Interrupt, dabei wird der Timer auf 0 gesetzt. Zudem möchte ich, wenn Timer1 ein Interrupt aufruft, sol Timer2 gelöscht werden. Wenn ich das Overflow Flag setze(bei Timer2), löscht er sich nicht. Habt ihr eine Idee wie ich das am besten realisieren kann? TCNT2= 0 geht offenbar zu langsam??

lg




#include <avr/io.h>
#define F_CPU 20000000
#include <util/delay.h>
#include <avr/interrupt.h>

// Umdrehung durch Hallsensor messen

uint8_t softtimer = 0, LB =0, HB = 0;
double TIME=0, OLDTIME = 0;

ISR(TIMER1_OVF_vect) // Timer1 Überlauf
{
softtimer++; // zählen der Überläufe
}

ISR(TIMER1_CAPT_vect) // Flanke an ICP pin
{
// Variablendeklaration

LB = ICR1L; // low Byte zuerst, high Byte wird gepuffert
HB = ICR1H;
TIME = (HB<<8)| LB;

if(softtimer) {
TIME += 65535 * softtimer-OLDTIME;
TIFR1 = (1<<TOV1);
}
OLDTIME = TIME;
}


int main(void) {
TCCR1A = 0; // kein PWM, kein INPUT bei OC1...
TCCR1B |= (1<<ICES1); // reagiert bei steigender Flanke
TCCR1B |= (1<<CS11) | (1<<CS10); // TAKT /64
TIMSK1 |= (1<<ICIE1)|(1<<TOIE1); // ICP steigende Flanke und overflow
TIFR1 |= (1<<TOV1);

DDRC = 0xff;
PORTC =0;

long int Zahl =0;


while(1){
sei();
Zahl = TIME;
cli();
PORTC = Zahl;
sei();
}
return 0;
}

oberallgeier
12.08.2010, 09:17
... herauszufinden wie lange der Kontroller alleine für das Starten des Timers braucht ... die Zeitintervalle müssen ... bis auf die ms stimmen ...Meine Controller - z.B. mega168 und mega328 - laufen vorzugsweise mit 20 MHz. Die arbeiten in einer Millisekunde 20 000 (zwanzig tausend) Maschinenzyklen ab - genug Zeit, um einen Tim er einzuschalten, auszulesen, abzuschalten - und dazwischen noch zu gähnen.

Ich weiß nicht, ob Deine Millisekundengenauigkeit ausreicht. Wenn ich mein Moped mit einer nicht allzu hohen Drehzahl fahre - 7200 Upm - dann dreht die Kurbelwelle in 23 µs ein Grad - in einer Millissekunde rund 43 Grad. Deswegen brauche ich mich um Fehler im Millisekundenbereich nicht mehr zu kümmern. Bei solchen Fehlern steh ich schon am Strassenrand und telefoniere nach dem ADAC.

Besserwessi
12.08.2010, 18:24
Die verzögerung ab der Flanke die man per ICP detektiert, würde ich mit dem selben Timer machen, ohne den Timer neu zu starten. Zu dem wert aus dem ICP Registern wird die Verzögerung addiert und dann in eines der OCP Register geschreiben. Man bekommt so nach der Gewünschten Zeit einen Interrupt und ggf. auch gleich ein Signal am Ausgang. Das wird dann auf einen Zyklus (z.B. 100 ns bei 10 MHz Takt) genau.

Die Verzögerung zum Stoppen/ Starten des Timers könnte man im Simulator bestimmen. Da wird vermutlich in der Größenordnung 50 Zkylen, also ein paar µs liegen.

Destrono
12.08.2010, 22:42
Die verzögerung ab der Flanke die man per ICP detektiert, würde ich mit dem selben Timer machen, ohne den Timer neu zu starten.
Das geht aber nur, wenn der Timer so langsam hochzählt, dass er nicht mehr als seinen Ausgangswert erreicht, oder?
Bsp.: Der Timer 1(16bit) hat einen Zählstand von 65000 beim Eintreffen des ICPs. Muss die Zeitdifferenz zum Warten so groß sein, dass der Timer1 bis zum Overflow und dann anschließend noch bis 65500 hochzählen muss, gibt es Probleme, da sich über die Differenz und das Zählen der Overflows die korrekte Zeit nicht mehr ermitteln lässt, oder?
In diesem Fall hlift es nur den Timer auf 0 zurückzusetzen, um eine konstante Zeitdifferenz für einen Overflow zu erhalten?

Ich habe das mal durchgerechnet und bin bei einer Taktfrequenz des Kontrollers von 8Mhz, einer Drehzahl von 6000 U/min, dem Hallsensor, der 40 Grad vor dem Totpunkt angebracht ist, dem Timer 1 mit 16bit und einem Precaler von 256 auf eine Auflösung von 1/32 ms gekommen. Das wäre noch zu verkraften. Auch würde der Prescaler von 256 bei diesen Einstellungen einen Overflow verhindern.

MfG
Destrono

Besserwessi
13.08.2010, 16:50
Die Einschränkung die man hat, ist das die Verzögerungszeit nicht zu lang für die 65000 Schritte des timers ist. Für ein Timer der mit 8 MHz läuf sind das dann ca. 125 ns * 65000 also ca. 8 ms. Es kann gut sein das der Timer in der Wartezeit einen überlauf hat, aber das stört überhaupt nicht, wenn man mit Word variablen rechnet - den Überlauf macht die Atithmetik in C auch genau so mit. Der Timer läuft die ganze Zeit durch, die Überläufe können also also praktisch jeder Position auftreten. Solage man keine Zeitdifferenzen hat, die länger sind als eine Überlauf des Timers ist das kein Problem. Das messen längerer Zeitdifferenzen geht auch, ist aber etwas schwieriger.

Wenn die 8 ms für rund 45 Grad sein sollen, dann hätte man 64 ms per Periode oder ca. 930 U/min. Das wird gerade etwas knapp - also wäre dann doch ein kleiner Vorteiler (z.B. /8 ) nötig. Man hätte dann 1 µs an Zeitauflösung, und eine Mindestdehrzahl von etwa 150 U/min. Das sollte für einen kleinen Motor reichen. Wenn man sich bei der Drehzahlmessung und der Berechnung der Verzögerungszeit daraus die berücksichtigung der Überläufe sparen will, dann sollte man einen Vorteiler von 64 nehmen, damit man auch für eine volle Umdrehung höchstens einen Überlauf drin hat.

Destrono
14.08.2010, 14:35
Danke erst mal für die Hilfe.
Die Berechnungen habe ich auch angestellt. Ich bin aber auf einen min. Prescaler 256 gekommen bei einer Drehzahl von max. 6000 U/min und einer Controllerfrequenz von 16Mhz.
Ich muss aber trotzdem den Timer zurücksetzen, weil ich möchte, dass der Kontroller unter einer gewissen Drehzahl von z.B. 1U/s in den Modus Stillstand wechselt und nicht mehr zündet. Ohne Zurücksetzen des Timers könnte ich mit der bloßen Differenz und den Interrupts nicht exakt feststellen, wie viel Zeit zwischen zwei ICP Interrupts aufgetreten ist. Hierzu wieder ein Beispiel. Der alte, gespeicherte Zählerwert soll 65000 betragen. Der Timer zählt dann weiter hoch bis zum Overflow, dort kann er einen Interrupt auslösen. Nach dem Overflow zählt er wieder hoch bis 65500 und genau jetzt kommt der ICP Interrupt, mit dem die vergange Zeit ermittelt werden soll.
Nur wie soll das gehen? Laut Differenz hat der Timer gerade mal 500 Schritte hoch gezählt. Und der Overflowinterrupt hilft einem auch nicht weiter, da man daraus keine Schlüsse auf die vergange Zeit schließen kann (da der Zähler ja bei 65000 angefangen hat und nicht bei 0 )

Oder irre ich da, denn Besserwessi schreibt:
Es sei denn:

Solage man keine Zeitdifferenzen hat, die länger sind als eine Überlauf des Timers ist das kein Problem. Das messen längerer Zeitdifferenzen geht auch, ist aber etwas schwieriger.


Und noch eine kurze Frage hinterher, da ich mich mit der kontrollerinternen Arithmetik nicht auskenne:
Ist so was möglich ? Wenn ja, macht es Sinn, oder geht der Fließkommavorteil beim Umwandeln in eine Ganzzahl wieder verloren?


OCR1A = (unsigned short int) ( current_icp + current_icp / 9.00) ;



MfG
Destrono

Besserwessi
14.08.2010, 19:39
Auch um die langen Zeitdifferenzen zu erkennen, muß man den Timer nicht zurücksetzen. Man kann z.B. die Overflows als vollwertige erweiterung der Zählerauflösung benutzen, dann auf 32 Bits was einigen Minuten entspricht. Dabei muß man aber ein paar kleine Tücken beachten, wenn die beiden Interrupts fast gleichzeitig auftreten. Ein lösung dafür gibt es z.B. hier:
http://www.rn-wissen.de/index.php/Timer/Counter_(Avr)
Nur ganz langen Stillstand über die Minuten hinaus müßte man extra abfangen. Da hat man aber viel Spielraum.

Wenn man ohnehin einen Vorteiler von 256 oder 64 nimmt, könnte man den Timer auch zurücksetzen. Das wird etwas einfacher, die Ungenauigkeit wird auch im Bereich einiger weniger Taktzyklen sein, wenn keine weiteren Interrupts für zusätzliche Verzögerungen sorgen.
Der Overflow interrupt kann dann direkt zum erkennen von Stillstand genutzt werden.


Die Berechnung des OCR1A wertes kann man auch mit Ganzzhalen machen. Bei der einfachen Division durch eine ganze Zahl ganz einfach so ähnlich wie geschrieben, nur mit einem normalen unsigned int, kein unsigned short int , das wären nur 8 Bits. Für mehr Auflösung in der Verzögerung würde ich multiplizieren auf ein 32 Bit Zwischenergebnis und dann um 16 Bits verschieben. Wenn man es eilig hat, geht das auch per Union.

Wenn man den Timer zurücksetzt kommt der ICP Wert nicht mehr in die Formel. Sonst müßte für die Perioden dauer der vorherige Wert abgezogen werden.