PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Umdrehungsmessung mit Timer



Static
02.01.2005, 15:21
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?

x-ryder
02.01.2005, 16:00
was hastn fürn quarz???

Martin

(dieser Text steht hier wegen den 30 Zeichen min.)

RCO
02.01.2005, 16:11
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

Static
02.01.2005, 16:44
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 ?

x-ryder
02.01.2005, 16:59
$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

RCO
02.01.2005, 17:05
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

Static
02.01.2005, 17:40
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.

Static
02.01.2005, 17:49
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 :(

RCO
02.01.2005, 17:54
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

Static
02.01.2005, 18:33
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

RCO
02.01.2005, 19:41
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

Static
02.01.2005, 22:55
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..

Static
03.01.2005, 12:37
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.

x-ryder
03.01.2005, 12:51
debounce doch: guck mal im handbuch nach oder hardwaremäßig mit kondensator!

Martin

05.01.2005, 07:55
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!?

RCO
05.01.2005, 09:53
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

Static
05.01.2005, 11:01
danke, die Software funktioniert jetzt ohne größere Probleme.