Hallo,
die PIC32 MCUs haben 5x 16 Bit Timer. Wie kann ich sehen wieviel Zeit
vergehen muss, damit ein Timer um 1 hochgezählt wird? Kann ich zur
Laufzeit etwa in einer Init Funktion festlegen, das Timer A nach 10 us
und Timer B nach 1 ms um 1 hochzählen soll?
Grüße
Tikonteroga schrieb:> Kann ich zur> Laufzeit etwa in einer Init Funktion festlegen, das Timer A nach 10 us> und Timer B nach 1 ms um 1 hochzählen soll?
Steht das nicht im Manual? Ja, ich liebe (hasse) das Manual auch, wenn
ich die Lösung sofort benötige. ;-)
Bei den kleinen PICs 12F675 benutze ich den Predivider, und lade im
Interrupt den Timer mit einem präzisen Wert nach. Das geht dort ganz
gut. Mit dem Predivider vorne dran ist es auch ganz egal, ob bei der
Nachladung mal ein paar mehr oder weniger Taktzyklen vergangen sind.
Denn die synchrone Taktzählung ist von der Nachladung unabhängig.
Also im Manual wird das wohl drinn stehen. Aber ich hab im Mcu Bereich
nicht so die Erfahrung und kann auch niemand sonst fragen. Mein Gebiet
ist eher .Net, JAVA und Win32 C++. Deshalb hab ich den Beitrag erstellt.
Meine Aufgabe ist es zur Zeit zu prüfen, ob der PIC32 diverse
Anforderungen erfüllt ohne es vorab in der Praxis ausprobieren zu
können.
Tikonteroga schrieb:> Aber ich hab im Mcu Bereich> nicht so die Erfahrung und kann auch niemand sonst fragen.
Also, normalerweise kann man mit dem MCU-Takt und den Angaben im Manual
berechnen, wie lange ein Timertakt braucht. Man braucht da überhaupt gar
nichts zu probieren.
Tikonteroga schrieb:> Wie kann ich sehen wieviel Zeit> vergehen muss, damit ein Timer um 1 hochgezählt wird?
Die Frage ist, was genau meinst du mit Auflösung? Die Länge des
Timerregisters hat nur geringe Bedeutung, denn du kannst den Zähler
softwaremässig um beliebig viele Bits erweitern. Wie lange ein einzelner
Zählschritt dauert, ist dagegen eine komplexere Frage, die nur aus dem
Datenblatt zu klären ist (aus dem speziellen für den Prozessor, nicht
allgemein für PIC32). In den meisten Fällen kann der Timer maximal mit
einem bestimmten Bruchteil der Quarzfrequenz zählen, z.B. /4, dazu gibt
es (oder auch nicht) Vorteiler mit bestimmten Teilerfaktoren,
vorzugsweise /2, /4, /8 usw., und es gibt (oder auch nicht) die
Kaskadierung von Timern, so dass Timer1 als Vorteiler für Timer2
arbeitet, wobei beide programmierbar sind (das ist nicht das gleiche wie
ein doppelt so langes Timerregister).
Es gibt wahrscheinlich noch mehr Variationen, die mir gerade nicht
einfallen, bei vielen µC ist das Timersystem das Komplexeste am ganzen
Controller.
Gruss Reinhard
Also wenn ich das Manual so verstehen würde, dass ich das mal kurz
berechnen könnte, dann hätte ich nicht gefragt.
Ich habe vor ein Modul (Gpt.h + Gpt.c) für die 5 Timer zu entwickeln
bzw. entwickeln zu lassen. Es soll u. a. folgende Funktionen geben.
void Gpt_Init();
void Gpt_InitTimer(uchar timer, uchar resolution);
void Gpt_StartTimer(ushort ticks, bool continue);
Ich muss jetzt bewerten, ob das Morden PIC geht.
Tikonteroga schrieb:> Ich habe vor ein Modul (Gpt.h + Gpt.c) für die 5 Timer zu entwickeln> bzw. entwickeln zu lassen.
Das ist schon das erste Missverständnis, die Timer sind keineswegs alle
gleich.
Tikonteroga schrieb:> void Gpt_InitTimer(uchar timer, uchar resolution);
Das ist das 2. Missverständnis - resolution ist nicht frei wählbar. Der
Vorteiler kann z.B. durch 2 teilen oder durch 4, aber nicht durch 3 -
und bei einer Sorte von Timern gehen alle 3 Faktoren nicht. Du kannst
also Resolution nicht vorgeben, sondern musst vorab prüfen, welche denn
verfügbar sind, welche davon für dich geeignet, und welchen Timer man
dafür benutzen kann.
Ich kann schliesslich auch nichts dafür, dass Elektronik kompliziert
ist, du kommst entweder damit klar oder nicht, aber ganz bestimmt
schnitzt dir niemand Spezialtimer passend zu deinem Verständnislevel.
Auch kein anderer Hersteller.
Gruss Reinhard
Reinhard Kern schrieb:> Tikonteroga schrieb:>> Ich habe vor ein Modul (Gpt.h + Gpt.c) für die 5 Timer zu entwickeln>> bzw. entwickeln zu lassen.>> Das ist schon das erste Missverständnis, die Timer sind keineswegs alle> gleich.>> Tikonteroga schrieb:>> void Gpt_InitTimer(uchar timer, uchar resolution);>> Das ist das 2. Missverständnis - resolution ist nicht frei wählbar. Der> Vorteiler kann z.B. durch 2 teilen oder durch 4, aber nicht durch 3 -> und bei einer Sorte von Timern gehen alle 3 Faktoren nicht. Du kannst> also Resolution nicht vorgeben, sondern musst vorab prüfen, welche denn> verfügbar sind, welche davon für dich geeignet, und welchen Timer man> dafür benutzen kann.
Also mit Resolution ist eine Art Enumeration gemeint.
"NS" = 0,
"US" = 1,
"MS" = 2,
"S" = 3
Ich habe gelesen dass ich für bestimmte Timer auch eine externe Clock
verwenden kann. Bin ich flexibler, wenn ich eine externe Clock verwende?
Es ist auch letztendlich so, dass die Timer eine unterschiedliche
Auflösung haben müssen. Also z. B. einer mit "US" pro Tick, einer mit
"MS" pro Tick und einer mit "S" pro Tick. Das ich eine NS pro Tick
erreichen kann wäre "NICE-TO-HAVE".
Ich müsste über einen der Timer (Timer 1 mit Realtime Clock ?) einen
Timestamp realisieren. Hier bräuchte ich aber einen 32 bit Timestamp und
ich habe aber nur einen 16 bit Timer. Könnte ich hier so vorgehen, dass
ich eine zusätzliche 16 Bit Variable anlege. Diese initialisiere ich mit
0 und bei jedem Mal wenn im 16 Bit Timer eine Überlauf entsteht,
inkrementiere ich die Variable in der Timer_Overflow ISR um 1. Wenn dann
der Timestamp abgefragt wird, gebe ich einen 32 Bit Wert zurück, den ich
aus dem Intehalt des Timer (0..15) und der Variable (16..31)
zusammenbaue.
Kann ich das so machen oder gibt es hier geeignetere übliche
Vorgehensweisen?
16-Bit Timer und eine Zählvariable als Erweiterung auf 32 Bit geht
natürlich.
Alternative: Timerkombination2/3 (oder 4/5 etc.) im 32-Bit-Mode
betreiben.
hast du im pdf oben die erste skizze angesehen? offensichtlich nicht.
also ein beispiel timer1:
der timer1 zählt die variable TMR1 mit einem gewissen takt hoch (lässt
sich einstellen), erreicht TMR1 den wert von PR1, gitb's einen interrupt
bei dem du irgendetwas machen kannst und gleichzeitig wird TMR1 wider
auf 0 gesetzt. der timer zählt im hintergrund deiner applikation von
alleine weiter.
ich glaube aber, dass wenn du nach genauigkeit fragt und 'NS' bei dir
für Nanosekunde steht, dass du einfach seeehr genau die länge eines
impulses oder abstand zweier impulse messen willst. das machst du aber
nicht über timer; oder nicht direkt.
So wie es sich anhört will er einfach eine Stoppuhr bauen und denkt, er
brüchte für us einen Timer, für ms einen zweiten, für Sekunden einen
dritten und für Minuten einen vierten. Und weil er es ganz genau haben
will, für ns noch einen.
Er versteht aber nicht, dass so ein Timer an den Takt des Prozessors,
über einen Prescaler, womit man den Takt halbieren, vierteln, ... kann,
gebunden ist.
Ebenso gibt es noch ein Register das der Timer bei jedem
"Geprescaledten"-Takte incrementiert und bei überschreiten eines
bestimmten vom User eingestellten Wertes einen Interrupt auslöst und das
Register des Timers dann wieder von 0 anfängt hochzuzählen, bis zum
Interrupt, wieder 0, ...
Durch diese Methode kann man einstellen, dass der Timer alle ms, oder
alle us oder wann auch immer einen Interrupt auslöst.
Diesen Interrupt verwendet man dann um die eine globale groß
dimensionierte (DWORD) Variable, nennen wir sie, Tick, hochzählt.
D.h. man kann einstellen, dass der Timer jede 1ms einen Interrupt
auslößt. Im Interrupt wird dann Tick incrementiert. Darauß Sekunde,
Minute und Stunde zu berechnen geht durch Mathematik und kann bei Bedarf
geschehen, da braucht man nicht weitere Variablen oder Timer. Die
feinere Auslösung von us oder gar ns bekommt man indem man den Prescaler
möglichst deaktiviert und das Timer Register bei Bedarf ausließt und den
momentanen Wert in us und ns umrechnet.
Hätte er sich die Mühe gemacht und meine Links angeschaut, dann hätte er
es auch selbst herausgefunden, denn dort steht alles drin.
Das Allgemeine Paper von Microchip zum Timer bei PIC32
und etliche Foreneinträge die zeigen wie man einen Timer initialisiert
und benutzt.
Tikonteroga schrieb:> die PIC32 MCUs haben 5x 16 Bit Timer. Wie kann ich sehen wieviel Zeit> vergehen muss, damit ein Timer um 1 hochgezählt wird?
Google mal nach
pic32 timer calculator
Frank M. schrieb:> So wie es sich anhört will er einfach eine Stoppuhr bauen und denkt, er> brüchte für us einen Timer, für ms einen zweiten, für Sekunden einen> dritten und für Minuten einen vierten. Und weil er es ganz genau haben> will, für ns noch einen.
Nein das möchte ich nicht. Ich möchte, dass nach bestimmten Zeiten, die
ein User vorgeben kann, zyklisch eine ISR aufgerufen wird, in der etwas
bestimmtes gemacht wird. Dabei gibt der User diese Zeit in "NS", "US",
"MS" oder "S" zuzüglich eines ganzzahligen Faktors an. Dies ist so
vorgegeben, das kommt nicht von mir.
> Er versteht aber nicht, dass so ein Timer an den Takt des Prozessors,> über einen Prescaler, womit man den Takt halbieren, vierteln, ... kann,> gebunden ist.> Ebenso gibt es noch ein Register das der Timer bei jedem> "Geprescaledten"-Takte incrementiert und bei überschreiten eines> bestimmten vom User eingestellten Wertes einen Interrupt auslöst und das> Register des Timers dann wieder von 0 anfängt hochzuzählen, bis zum> Interrupt, wieder 0, ...
Das mit dem Interrupt ist schon klar. Ich habe jedoch nach Möglichkeiten
gesucht, wie ich die vorgegebenen Zeiteinheiten auf die Hardware
übertragen kann. Sicherlich kann ich die möglichen Zykluszeiten die der
User auswählen darf so einschränken, das es mit dem Takt und den
Prescalern passt, aber das entspricht nunmal nicht meinen Anforderungen.
Der User sollte hier so flexibel sein wie es geht. Deshalb habe ich hier
nachgefragt.
Jens Martin schrieb:> Tikonteroga schrieb:>> die PIC32 MCUs haben 5x 16 Bit Timer. Wie kann ich sehen wieviel Zeit>> vergehen muss, damit ein Timer um 1 hochgezählt wird?>> Google mal nach>> pic32 timer calculator
Danke schön. Ich teste damit mal alles durch.
Tikonteroga schrieb:> Sicherlich kann ich die möglichen Zykluszeiten die der> User auswählen darf so einschränken, das es mit dem Takt und den> Prescalern passt, aber das entspricht nunmal nicht meinen Anforderungen.
Wenn du mit der lieferbaren Hardware nicht auskommst, musst du dir wohl
oder übel deine eigene bauen, so einfach ist das. Aber wenn du nicht
einmal die Funktion eines µControllers verstehst, ist das völlig
illusorisch.
Du kannst es dir und uns auch ersparen, noch ein paarmal zu erklären,
dass du mit der Funktion real existierender Prozessoren nicht
einverstanden bist, die ändern sich deswegen ja nicht.
Gruss Reinhard
Also falls deine Aufgabe so trivial einfach und simpel ist, dann reicht
auch wieder ein einziger 32-Bit (oder gar nur 16-Bit Timer und ein
bisschen mehr Code).
Die Eingabe des Users kann man mit simpler Mathematik in us umrechnen
und bspw. in 'Duration' speichern.
Also 1 Min, 10 Sek, 40ms, 20us ergibt dann Duration = 70040020
Entweder du stellst den Timer fix auf 1us (was genau machbar ist) ein
und incrementierst jedes mal eine globale Variable. In deinem
Hauptprogramm vergleichst du diese mit Duration und machst bei
Überschreiten des Wertes deine Aktion.
Andere Möglichkeit:
Angenommen dein PIC32 taktet mit 80MHz und du hast einen Prescaler von 8
drin, dann ist die Auflösung des Timers 100ns. D.h. alle 100ns wird das
internet Timer Register incrementiert. Jeweils 10 Einheiten muss er
zählen um eine us erreicht zu haben.
Das bedeutetm die Duration rechnest du nun um auf den Wert den dein
Timer Register haben muss, d.h. 70040020 * 10 = 700400200, schaltest den
Interrupt ein und startest den Timer. Nach genau deiner Duration wird
ein Interrupt ausgelöst.
Falls du nun länger Warten willst, sodass ein 32-Bit Register nicht mehr
reichen sollte, dann musst du halt ein paar mal im Interrupt eine zweite
Variable hochzählen bis zu umschaltest, oder dein Konzept übderdenken,
denn was bringt eine us Auflösung wenn er 1s lang laufen soll, das ist
Schwachsinn.
Aber wieder, wie so ein Timer funktioniert, und wie man ihn benutzt,
naja, les dir halt die Threads durch, da steht doch alles.
Und ich verstehe immmer noch nicht wozu du jetzt zig Timer brauchst und
einen rießen Aufwand für so eine Kleinigkeit betreibst.
Frank M. schrieb:> Also falls deine Aufgabe so trivial einfach und simpel ist, dann reicht> auch wieder ein einziger 32-Bit (oder gar nur 16-Bit Timer und ein> bisschen mehr Code).>> Die Eingabe des Users kann man mit simpler Mathematik in us umrechnen> und bspw. in 'Duration' speichern.> Also 1 Min, 10 Sek, 40ms, 20us ergibt dann Duration = 70040020>> Entweder du stellst den Timer fix auf 1us (was genau machbar ist) ein> und incrementierst jedes mal eine globale Variable. In deinem> Hauptprogramm vergleichst du diese mit Duration und machst bei> Überschreiten des Wertes deine Aktion.>> Andere Möglichkeit:> Angenommen dein PIC32 taktet mit 80MHz und du hast einen Prescaler von 8> drin, dann ist die Auflösung des Timers 100ns. D.h. alle 100ns wird das> internet Timer Register incrementiert. Jeweils 10 Einheiten muss er> zählen um eine us erreicht zu haben.> Das bedeutetm die Duration rechnest du nun um auf den Wert den dein> Timer Register haben muss, d.h. 70040020 * 10 = 700400200, schaltest den> Interrupt ein und startest den Timer. Nach genau deiner Duration wird> ein Interrupt ausgelöst.> Falls du nun länger Warten willst, sodass ein 32-Bit Register nicht mehr> reichen sollte, dann musst du halt ein paar mal im Interrupt eine zweite> Variable hochzählen bis zu umschaltest, oder dein Konzept übderdenken,> denn was bringt eine us Auflösung wenn er 1s lang laufen soll, das ist> Schwachsinn.>>> Aber wieder, wie so ein Timer funktioniert, und wie man ihn benutzt,> naja, les dir halt die Threads durch, da steht doch alles.> Und ich verstehe immmer noch nicht wozu du jetzt zig Timer brauchst und> einen rießen Aufwand für so eine Kleinigkeit betreibst.
Ich habe mir jetzt nochmal das Datenblatt durchgelesen und verstehe
viele Stellen schon etwas besser.
http://ww1.microchip.com/downloads/en/DeviceDoc/61105F.pdf
Im Kapitel "14.3.5 16-bit Synchronous External Clock Counter Mode"
steht, dass ich an den TxCK pin eine externe Clock anbinden kann. Kann
ich hier z. B. jeweils ein zusätzliches Bauteil verbauen, dass dann
einen Takt von 1 Hz (Timer 2, 1 Tick/s), 10 Hz (Timer 3, 1 Tick/100 ms),
100 Hz (Timer 4, 1 Tick/10 ms) vorgibt.
Ich hätte gerne vermieden, dass die ISR ständig aufgerufen wird und
globale Variablen hochzählen muss und nur ganz selten das macht, was sie
eigentlich machen soll. Nach meinem Verständnis ist das eine Art
"Polling" und das will ich ja gerade nicht. Bei so Stichwörtern wie
"Polling" und "globale Variable" erscheint bei mir ein "Achtung !!! oder
HALT !!!" im Sinn.
Im Idealfall soll die ISR des Timers nur dann aufgerufen werden, wenn es
an der Zeit ist, dass der Task ausgeführt wird, der durch das zeitliche
Event getriggert wird.
Es mag vielleicht sein, dass ich letztendlich nicht drummherum komme,
das so zu lösen, aber jetzt in der Konzeptphase würde ich auch gerne ein
Konzept ohne Polling und globale Variablen als Alternative ausarbeiten.
Die Hardware wird auch nicht von mir gebaut, dass machen Leute mit
E-Technik-Studion bzw. anderer Themenbezogener Ausbildung und Erfahrung.
Ich mache nur den Projektvorschlag. Den PIC32 habe ich unter anderem
deshalb ausgewählt, weil man hier die IDE, den Kompiler, einen Custom
USB Treiber + Library, ... aus einer Hand bekommt. Ich habe mir aber
auch Arm7, Arm9, Cortex M3/M4 angesehen.
Tikonteroga schrieb:> Ich hätte gerne vermieden, dass die ISR ständig aufgerufen wird und>> globale Variablen hochzählen muss und nur ganz selten das macht, was sie>> eigentlich machen soll.
Die ISR wird doch nicht ständig aufgerufen!?
Wenn du einen Timer mit 1ms extern Taktest und du möchtest das nach
1234ms ein bestimmtes Ereigniss ausgelöst wird, dann lädst du das
Timerregister mit 64302 (2^16 - 1234). Erst beim Überlauf wird der INT
ausgelöst.
Du hast das Prinzip des Timers noch nicht ganz verstanden:
1. Takt: Der kann vom Prozessortakt abhängen oder von eine externen
geliefert werden. Ein externen wird gerne für eine RTC verwendet, da so
der PIC im Stromsparmodus laufen kann, während die RTC im Hintergrund
weiter laufen kann. Auch kommt es darauf an wie genau der Timer sein
soll. Der PIC hat einen internen RC-Schwingkreis mit mäßiger
Genauigkeit. Willst du es genauer, so kannst du den ganzen PIC mit einem
externen Quarz noch versorgen, dennoch kann der Timer vom Takt des
Prozessors abhängig bleiben. Muss sogar, da du sonst ja auch gar nicht
deine us oder gar ns Auflösung hinbekommst.
2. Prescaler: Nun kann dieser Takt halbiert, geviertelt, ... werden um
den Timer gröber zu laufen lassen, da nicht immer so ein schneller Timer
(im Fall von 80MHz: 12.5ns) von nöten ist.
3. Timerregister: Es ist ein internes Register das bei jedem Timertakt
incrementiert wird. Dieser Prozess läuft im Hintergrund in der Hardware,
nicht in der Software. Dieses Register kann nun 16-Bit bzw. 32-Bit groß
sein. D.h. interner Takt und kein Prescaler: Alle 12.5ns wird das
Register incrementiert.
4. Ein zweites Register dient als Vergleich. In dieses Register kannst
du einen Wert deiner Wahl eintrage. Erst wenn das Timerregister den Wert
des Vergleichregisters übersteigt wird ein Interrupt ausgelößt. Nochmal:
Das automatische incrementieren des Timers geschieht im Hintergrund in
der Hardware.
Mit Hilfe diesem Vergleichregister und einem geeignet gewähltem
Prescaler kannst du so ziemlich jede erdenkliche Zeitspanne dir
einstellen.
Wie ich oben eben gerechnet habe.
Schau dir doch auch endlich mal meine verlinkten Threads an. Dort ist
ein Code Beispiel, dort steht geschrieben was wie gemacht wird.
Vor allem: http://www.microchip.com/forums/m641880.aspx
Und da den gelb hervorgehobenen Teil.
Im Datenblatt schaue mal die Register:
TMR.. und
PR.. an.
Das eine enthält den aktuellen Wert des Timerregisters, das andere den
Vergleichswert bis zu dem er zählen soll bis er einen Interrupt auslöst.