Archiv verlassen und diese Seite im Standarddesign anzeigen : Umdrehungsmessung mit Timer
Hallo, ich weiß es gibt hier schon viele Threads zu diesem Thema aber ich werd daraus irgendwie nicht schlau.
Ich habe einen Taster an einer Drehenden Achse, der jede Umdrehung einen Impuls gibt. Jetzt möchte ich eigentlich nur wissen wieviele Impulse es in einer bestimmten Zeit gibt. Die Impulse zähle ich mit einer Schleife, ohne Interrupts da die Drehzahl sehr gering ist. Nun bräuchte ich eine Sub Routine die immer nach einer bestimmten Zeit (jede Sekunde würde schon reichen) aufgerufen wird, die Umdrehungen speichert und wieder auf Null setzt. Aber wie mache ich das mit dem Timer?
Hab mit den Timern jetzt schon viel rumprobiert aber irgendwie funktioniert das bisher noch nicht...
Kann mir da bitte nochmal jemand helfen?
was hastn fürn quarz???
Martin
(dieser Text steht hier wegen den 30 Zeichen min.)
Also um genau zu sein, brauchst du nur einen Timer, der jede Sekunde einen Interrupt auslöst, oder?
In der Interruptroutine wird dann der zuvor gespeicherte Wert bearbeitet, wie, dass ist dann deine Aufgabe. Hier mal ein wenig Code von mir:
$regfile = "m8def.dat"
$crystal = 8000000
Dim Zaehlerstand As Byte '255 Werte in der Sec. sollte nicht überschritten werden, ansonsten eine Word-varaible verwenden oder so.
Const Timervorgabe = 34286 '65536-31250 = 34286
Config Timer1 = Timer , Prescale = 256
On Timer1 Timer1_isr
Timer1 = Timervorgabe
Enable Timer1
Enable Interrupts
Do
'Bestimmung von Zaehlerstand (deine Aufgabe ;-) )
Loop
End
Timer1_isr:
Timer1 = Timervorgabe
'Hier passiert jetzt was mit deinem Zaehlerstand
Zaehlerstand = 0
Return
Der Code ist schon getestet, da ich weder weiß, welchen Controller du verwendest, noch wie dein uC getaktet ist, überlasse ich dann die anpassung der Werte dir, oder du sagst mir halt, wie es aussieht.
MFG Moritz
Danke, genau das meinte ich RCO. Sorry das ich das vergessen hab ich benutzen einen Mega32 der mit 16Mhz getaktet ist.
Das Prescale bestimmt doch nach wievielen Takten der Timer ausgelöst werden soll, oder?
Den Code hab ich soweit verstanden bis auf diese Rechnung:
Const Timervorgabe = 34286 '65536-31250 = 34286
Die Timervorgabe legt den Startwert des Timers fest, 31250 mal würde der Timerinterrupt in einer Sekunde ausgelöst bei einem Prescale von 256, aber wo kommen die 65536 her?
Also: Wie müste das bei 16Mhz aussehen :-k ?
$regfile = "m32def.dat"
$crystal = 16000000
Config Timer1 = Timer, Prescale = 256
On Timer1 Timer_irq
Const Timervorgabe = 3036
Enable Timer1
Enable Interrupts
Do
'Dein Part
Loop
Timer_irq:
Timer1 = Timervorgabe
Return
Ja, also der Timer ist eingentlich ein Counter ;-) hört sich zwar blöd an, ist aber so, deshalb spricht man oft von "Timer/Counter".
Er zählt alle Takt/Prescaler +1, Timer1 ist also selber eine Variable, die immer erhöht wird. wenn Timer 1 voll ist, bzw. überläuft, dass heißt den Wert 2^16 erreicht (16-Bit Timer) löst er einen Interrupt aus. Unser Ziel ist es jetzt, dass der Timer immer genau jede Sekunde überläuft.
Wenn wir den Timer mit 34286 vorladen, bleiben 31250 Impulse des Prescalers, bis der Timer überläuft.
31250 entspricht in unserem Fall:
8000000 [Takt meines uCs] / 256 [Prescaler]
Also genau einer Sekunde.
Ziehen wir nun von dem Überlaufwert den Wert für eine Sekunde ab, läuft der Timer1 genau jede Sekunde über, dann sollten wir ihn natürlich möglichst schnell wieder beladen, damit keine Fehler entseht.
In deinem fall würde ich einen größeren Prescaler nehmen (1024) weil der uC dann etwas entlastet wird. (Ich habe 256 gewählt, weil ich mit 1024 auf eine Komma-Zahl kam)
Mit 16000000/1024 kommen wir auf 15625. Nun Muss Timervorgabe
2^16-15625 sein, also 49911.
Alles klar?
Müsste mit Timervorgabe 49911 und Prescaler 1024 bei 16 Mhz genau auf eine Sekunde kommen. Kannst ja mal eine Diode toggeln, um es zu prüfen.
Natürlich entstehen aufgrund von Quarzungenauigkeiten etc. immer Fehler, aber da es sich ja nciht um eine Langzeituhr handelt, sollte das kein Problem sein. Bei anderen sind schonmal auf einen Tag einige Sekunden Differenz entsatnden, kannste ja runterrechnen.
Noch fragen?
MFG Moritz
Vielen Dank für die erklärung. Hab wie du sagtest eine Led damit getriggered und es funktioniert :-) Allerdings ist der Timer mit einem Anfangswert von 4991 ungefähr auf 3, 4 Sekunden eingestellt. 16 bit sind nämlich 2^17 und nich 2^16 ;). Also wär der richtige Startwert 115447, mit dem blinkt die Led jetzt im 1 Sekundentakt.
Könnte ich das dann auch mit Timer0 machen? Der Timer1 wird ja beim RN-Control Board für die Motorensteuerung benutzt und ich will die Drehzahl dieser Motoren messen.
Der Timer0 ist ja ein 8Bit Counter. 2^9 sind ja bloß 512 da würde ich auf einen Startwert von -15113 kommen, funktioniert aber leider nicht :(
16 bit sind nämlich 2^17 und nich 2^16
Das ist mir neu, bis jetzt waren 16 Bit bei mir immer 65536!
Ein Bit hat ja auch nur 2^1 also 2 und nicht 2^2 also 4 Zustände.
4991
Wie kommst du nun jetzt auf diesen Wert? Ich hab doch 49911 geschrieben.
ungefähr auf 3, 4 Sekunden eingestellt
Ja mit 4991 kommt man auf 3,1306 sec.
Aber mit 49911 Meiner Meinung nach immer noch auf 1.
Schön, wenn es läuft, mir allerdings total unverständlich.
MFG Moritz
EDIT: könnte es sein, dass 4991 tatsächlich nicht nur ein Schreibfehler war?
Denn: wenn du sagst, das du 2^17 verwendet schreibst du ja in ein 17 nicht mehr in dieser Variable existierendes Bi und schreibst somit also nur 49911 in die Varaible. Was dann meinem Wert entsprechen würde ;-)
MFG Moritz
Hmmm, naja ka es ging jedenfalls lol. Die größte Zahl die man mit 16Bits darstellen kann ist doch 2^17 dachte ich? So haben wir das jedenfalls gelernt lmao. Das 16. Bit ist ja für 2^16, aber wenn man alle anderen Bits auchnoch setzt hat man ja insgesamt 2^17 (2^1+2^2+2^3+2^4....+2^16).
Weiß nich ob das damit zusammenhängt habs auch nur ausprobiert. Kann gut sein das ich mich verschrieben hatte, bin jetzt allerdings auf Timer2 umgestiegen der nur 8Bit hat also kann ich das jetzt leider nicht so schnell ausprobieren.
Frag mich allerdings immernoch wie man das nun mit einem 8Bit Timer macht. Ich fange jetzt bei 0 an, da er leider nicht im negativen anfangen kann lol. Da heißt er läuft 30,51 mal in der Sekunde über. Da das viel zu schnell wäre schalte ich die Lampe nur jedes 31. mal an bzw. aus damit ich wieder auf ~1 sek kommen. Aber irgendwie ist das ein bisschen aufwändig lol. Geht das auch irgendwie besser?
m.artmann
02.01.2005, 19:01
Hallo Static,
Lad Dir doch mal dieses Programm runter.
https://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169
Es erstellt dir gleich den Quelllcode für die Timer.
Damit wirst Du feststellen dass bei 16MHz mit dem Timer0 keine Frequenz mit 1Hz möglich ist..
Du kannst aber 100Hz verwenden und damit Deine Drehzahl messen und dann einfach mal 100 nehmen.
Funktioniert bei hohen Drehzahlen ganz gut.
Gruß
m.artmann
Dann würde ich einen kleineren Prescaler verwenden und in der Timerinterruptroutine noch einen Zähler, der dann halt alle x mal eine Funktion aufruft.
MFG Moritz
So hab ich es dann auch gemacht, RCO. Mit 100Hz messen würde natürlich auch gehen, aber das ist eigentlich nicht nötig.
sebastian.heyn
03.01.2005, 02:24
Hi,
hab sowas schonmal gemacht um einen Frequenzzähler zu bauen, der sollte nur bis 250Hz können, geht aber wesentlich höher, Habe dazu den impuls am eingang auch auf nen interrupt gemacht, damit ich im hauptprogramm mehr zeit habe und dann einfach 1mal pro sekunde (timer) nachgeschaut wie oft der interrupt kam. kann ja morgen mal bei interesse den code posten..
Ich machs jetzt auch mit Interrupts, da ich sonst angst habe Impulse zu verpassen. Hab aber noch Probleme mit dein scheiß Tastern :(, die liefern anscheind auf einmal keine sauberen Impulse mehr da müssen wohl doch Lichtschranken dran.
debounce doch: guck mal im handbuch nach oder hardwaremäßig mit kondensator!
Martin
Also die Sache mit der Timer-Berechnung kann man auch einfacher machen.
Beispiel:
8 MHz Quarz
Prescale = 1024
16 Bit-Timer = 65536 (8 Bit = 255)
8^6 / 1024 / 65536 = x
1/x = Zeit in Sec = 8,39 sec
Stellst Du nun den (16-Bit) Timer immer auf 57736 ein, bleiben ihm nur noch 7800 Takte bis zum Überlauf. Danach wird er wieder auf 57736 eingestellt und nicht auf null, wie er es sonst machen würde!
In bascom also einfach
Timer1 = 57736
eingeben
Dann errechnet sich:
8^6 / 1024 / 7800 = x
1/x = 1,00 Sec
(...und ein paar Nachkommastellen) :-)
Beim 8 Bit-Timer wird eben nicht bis 65536 gezählt, sondern nur bis 255. Deshlab wählt man hier ein anderen Prescale und einen anderen Vorwert (57736 geht also nicht beim 8 Bit-Timer!)
Oder anders gesagt
8-Bit = Byte
16-Bit = Word
Hoffe, das Hilft wenigstens für die Praxis!?
8^6 / 1024 / 65536 = x
1/x = Zeit in Sec = 8,39 sec
Meinst vermutlich 8 * 10^6
Stellst Du nun den (16-Bit) Timer immer auf 57736 ein, bleiben ihm nur noch 7800 Takte bis zum Überlauf.
Ich erkenne hier keinen Unterschied zu meinem Vorschlag! Du verwendest halt einen größeren Prescaler. Wenn man genau rechnet, kommt man übrigens auf 7812,5! Deshalb habe ich ja gerade den 256 Prescaler gewählt, damit glatte Zahlen rauskommen!
7812,5 x 4 = 31250 (genau mein Wert)
Danach wird er wieder auf 57736 eingestellt und nicht auf null, wie er es sonst machen würde!
In bascom also einfach
Timer1 = 57736
eingeben
Das nützt ja nix, der Timer geht nach dem Überlaufen von selber auf null! Schließlich zählt er ja hoch!
Timer1 = Timervorgabe
Hab ich ja auch geschrieben, muss aber halt nach jedem Interrupt neu geschriben werden:
Timer1_isr:
Timer1 = Timervorgabe
'Hier passiert jetzt was mit deinem Zaehlerstand
Zaehlerstand = 0
Return
MFG Moritz
danke, die Software funktioniert jetzt ohne größere Probleme.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.