Forum: Mikrocontroller und Digitale Elektronik Auflösung der Timer beim PIC32


von Tikonteroga (Gast)


Lesenswert?

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

von Wilhelm F. (Gast)


Lesenswert?

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.

von Tikonteroga (Gast)


Lesenswert?

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.

von Wilhelm F. (Gast)


Lesenswert?

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.

von Reinhard Kern (Gast)


Lesenswert?

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

von Tikonteroga (Gast)


Lesenswert?

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.

von Frank M. (frank_m35)


Lesenswert?


von Reinhard Kern (Gast)


Lesenswert?

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

von Tikonteroga (Gast)


Lesenswert?

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?

von Chris B. (dekatz)


Lesenswert?

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.

von Master S. (snowman)


Lesenswert?

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.

von Frank M. (frank_m35)


Lesenswert?

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.

von Jens M. (Gast)


Lesenswert?

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

von Tikonteroga (Gast)


Lesenswert?

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.

von Tikonteroga (Gast)


Lesenswert?

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.

von Reinhard Kern (Gast)


Lesenswert?

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

von Frank M. (frank_m35)


Lesenswert?

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.

von Tikonteroga (Gast)


Lesenswert?

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.

von Chris B. (dekatz)


Lesenswert?

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.

von Frank M. (frank_m35)


Lesenswert?

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.

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.