{"id":92,"date":"2015-02-15T19:33:19","date_gmt":"2015-02-15T19:33:19","guid":{"rendered":"http:\/\/techblog.auchmonoabspielbar.de\/?p=92"},"modified":"2016-06-06T19:28:57","modified_gmt":"2016-06-06T19:28:57","slug":"frequenzzaehler-periodenmesser-mit-einem-pic32-teil-4","status":"publish","type":"post","link":"http:\/\/techblog.auchmonoabspielbar.de\/?p=92","title":{"rendered":"Frequenzz\u00e4hler\/ Periodenmesser mit einem PIC32 \u2013 Teil 4"},"content":{"rendered":"<p>Als n\u00e4chstes ben\u00f6tige ich die Z\u00e4hler f\u00fcr das Eingangssignal. Praktischerweise besitzt der PIC32 neben dem Timer1, den ich f\u00fcr die Anzeige verwende, noch vier weitere 16 Bit Z\u00e4hler, die sich zu zwei 32 Bit Z\u00e4hlern zusammenschalten lassen. Heute habe ich mich darum gek\u00fcmmert, die Timer 2 und 3 als 32 Bit Z\u00e4hler zu verwenden.<\/p>\n<p>In einem ersten Schritt habe ich mich auf die Zusammenschaltung konzentriert und mit dem internen Takt wie beim Timer1 gearbeitet. Das geht relativ einfach und ist nach einem kurzen Blick in das Datenbuch leicht zu erledigen.<\/p>\n<p><strong>\u00a0\u00a0\u00a0 OpenTimer23(T23_ON | T23_SOURCE_INT | T23_PS_1_1, 0xffffffff);<\/strong><\/p>\n<p>Statt Timer1 wird nun die Kombination aus Timer2 und Timer3 verwendet. Die vordefinierten Hilfsfunktionen und Konstanten sind erfreulicherweise daf\u00fcr vorbereitet. Der Prescaler wird auf 1 gesetzt, der maximale Timerwert auf volle 32 Bit (die aber nicht komplett ben\u00f6tigen werde).<\/p>\n<p>In der Hauptschleife warte ich nun immer rund eine halbe Sekunde, lese den Timer23 aus und \u00fcbertrage den aktuellen Wert in den Bildspeicher.<\/p>\n<p><strong>\u00a0\u00a0\u00a0 while(1) {<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int del;<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ wait for 500 milliseconds<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (del = 0; del &lt; 80000; del++);<\/strong><\/p>\n<p><strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 setInt(ReadTimer23());<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0 };<\/strong><\/p>\n<p>Das war der einfache Teil, da es im Internet eine Vielzahl von Beispielen gibt, wie man einen Timer mit einem internen Takt verwendet. F\u00fcr einen Frequenzz\u00e4hler ben\u00f6tige aber einen Z\u00e4hler f\u00fcr einen externen Takt. An dieser Stelle habe ich erst mal einen Schreck bekommen, da mir klar wurde, dass ich die Pins f\u00fcr die Ausgangssignale ohne R\u00fccksicht darauf verteilt habe, ob sie eventuell auch von den Timern ben\u00f6tigt werden. Aber ich hatte Gl\u00fcck &#8211; das Timer2 Clock Signal, welches auch Eingang f\u00fcr den kombinierten Timer 2 + 3 ist, hat als Eingang einen programmierbaren Pin (PPS). Da ich auf Anhieb kein Beispiel daf\u00fcr im Internet gefunden habe, musste ich mich jetzt also erst mal mit der Programmierung der Pinbelegung auseinandersetzen. Erfreulicherweise ist es dann aber doch recht einfach. Es gibt zu jedem Eingang eines Funktionsbausteins eine Liste mit den m\u00f6glichen Pins. Aus dieser Liste muss man einen passenden Pin ausw\u00e4hlen, den Mapping-Wert auslesen und in ein Register eintragen. Das war alles &#8211; wenn man es erst mal verstanden hat ist es ganz simpel: T3CKRbits.T3CKR = 0;.<\/p>\n<p><strong>void startCounter() {<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0 OpenTimer23(T23_ON | T23_SOURCE_EXT | T23_PS_1_1, 0xffffffff);<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0 T3CKRbits.T3CKR = 0; \/\/ RA0<\/strong><br \/>\n<strong>}<\/strong><\/p>\n<p>Wie man im Video sieht, habe ich mittlerweile auch das im Teil 3 beschriebene \u00dcbersprechen zwischen den Anzeigestellen in Griff. Das Flackern kommt durch eine \u00dcberlagerung der Kamerafrequenz mit der Anzeigefrequenz, es ist im Original nicht sichtbar. Die Wiederholfrequenz liegt bei ca. 90 Hertz.<br \/>\n<iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/7-HzcWsSCQ4\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><br \/>\n<strong>Aktueller Software Stand:<\/strong><\/p>\n<pre>\/* \r\n\u00a0* File:\u00a0\u00a0 main.c\r\n\u00a0* Author: Matthias Thiele\r\n\u00a0*\r\n\u00a0* Created on 23. Januar 2015, 21:08\r\n\u00a0*\/\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;plib.h&gt;\r\n\r\n\/\/ Configuration Bit settings\r\n\/\/ SYSCLK = 80 MHz (8MHz Crystal\/ FPLLIDIV * FPLLMUL \/ FPLLODIV)\r\n\/\/ PBCLK = 40 MHz\r\n\/\/ Primary Osc w\/PLL (XT+,HS+,EC+PLL)\r\n\/\/ WDT OFF\r\n\/\/ Other options are don't care\r\n\/\/\r\n#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF\r\n#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_8\r\n#pragma config OSCIOFNC = OFF \/\/ CLKO Output Signal Active on the OSCO disabled\r\n#pragma config JTAGEN = OFF \/\/ JTAG Enable (JTAG Disabled)\r\n\r\n#define SYS_FREQ \u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0(80000000L)\r\n\r\nstatic int digits[9];\r\nstatic int dark[9];\r\n\r\n\/\/ Ermittelt das Port B Bitmuster f\u00fcr einen Wert\r\n\/\/ an einer Position im Bildspeicher\r\nint calcPattern(int pos, int value) {\r\n\u00a0 int hexDigit = (value &amp; 0xf) &lt;&lt; 7;\r\n\u00a0 int position = ((pos &amp; 1) &lt;&lt; 11) | ((pos &amp; 0xe) &lt;&lt; 12);\r\n\u00a0 int comma = (pos == 1) ? 0x20 : 0;\r\n\r\n\u00a0 return hexDigit | position | comma;\r\n}\r\n\r\n\/\/ Schreibt eine Ziffer an eine Position im Bildspeicher\r\nvoid setDigit(int pos, int value) {\r\n\u00a0 int pattern = calcPattern(pos, value);\r\n\u00a0 digits[pos] = pattern;\r\n}\r\n\r\n\/\/ Schreibt einen Integer Wert in den Bildspeicher\r\nvoid setInt(int value) {\r\n\u00a0\u00a0\u00a0 int i, j;\r\n\r\n\u00a0\u00a0\u00a0 for (i = 8; i &gt;= 0; i--) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int part = value % 10;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 setDigit(i, part);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 value = value \/ 10;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (value == 0) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ clear leading digits\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (j = i - 1; j &gt;= 0; j--) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 setDigit(j, 0xf);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n\r\n\/\/ Zeigt in einer Schleife die 9 Stellen des\r\n\/\/ Displays an. Wird aus dem Heartbeat Interrupt\r\n\/\/ ca. 1000 mal pro Sekunde aufgerufen.\r\nvoid displayTick() {\r\n\u00a0\u00a0\u00a0 static int pos = 0;\r\n\r\n\u00a0\u00a0\u00a0 \/\/ dunkel schalten\r\n\u00a0\u00a0\u00a0 mPORTBWrite(dark[pos]);\r\n\u00a0\u00a0\u00a0 int delay;\r\n\u00a0\u00a0\u00a0 for (delay = 0; delay &lt; 3; delay++);\r\n\r\n\u00a0\u00a0\u00a0 \/\/ neuen Wert eintragen\r\n\u00a0\u00a0\u00a0 mPORTBWrite(digits[pos]);\r\n\r\n\u00a0\u00a0\u00a0 \/\/ n\u00e4chste Stelle ermitteln (round robin)\r\n\u00a0\u00a0\u00a0 pos++;\r\n\u00a0\u00a0\u00a0 if (pos &gt; 8) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pos = 0;\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n\r\n\/\/ Interrupt Service Routine f\u00fcr Timer1\r\nvoid __ISR(_TIMER_1_VECTOR, ipl2) Timer1Handler(void) {\r\n\u00a0\u00a0\u00a0 displayTick();\r\n\u00a0\u00a0\u00a0 mT1ClearIntFlag();\r\n}\r\n\r\n\/\/ Initialisert das Display\r\nvoid initDisplay() {\r\n\u00a0\u00a0\u00a0 int i;\r\n\u00a0\u00a0\u00a0 for (i = 0; i &lt; 9; i++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dark[i] = calcPattern(i, 0xf);\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n\r\n\/\/ Initialisiert und startet den Heartbeat Timer\r\nvoid startHeartbeat() {\r\n\u00a0\u00a0\u00a0 OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_256, 4);\r\n\u00a0\u00a0\u00a0 INTEnableSystemMultiVectoredInt();\r\n\u00a0\u00a0\u00a0 ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);\r\n\u00a0\u00a0\u00a0 mT1ClearIntFlag();\r\n}\r\n\r\n\/\/ Initialisiert und startet die Z\u00e4hler Timer\r\nvoid startCounter() {\r\n\u00a0\u00a0\u00a0 OpenTimer23(T23_ON | T23_SOURCE_EXT | T23_PS_1_1, 0xffffffff);\r\n\u00a0\u00a0\u00a0 T3CKRbits.T3CKR = 0; \/\/ RA0\r\n}\r\n\r\nint main(void)\r\n{\r\n\u00a0\u00a0\u00a0 SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);\r\n\u00a0\u00a0\u00a0 mJTAGPortEnable(DEBUG_JTAGPORT_OFF);\r\n\r\n\u00a0\u00a0\u00a0 ANSELA = 0;\r\n\u00a0\u00a0\u00a0 ANSELB = 0;\r\n\u00a0\u00a0\u00a0 CM1CON = 0;\r\n\u00a0\u00a0\u00a0 CM2CON = 0;\r\n\u00a0\u00a0\u00a0 CM3CON = 0;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 mPORTBSetPinsDigitalOut( 0xfffc );\r\n\u00a0\u00a0\u00a0 mPORTASetPinsDigitalIn( 0x3 );\r\n\r\n\u00a0\u00a0\u00a0 initDisplay();\r\n\u00a0\u00a0\u00a0 startHeartbeat();\r\n\u00a0\u00a0\u00a0 startCounter();\r\n\r\n\u00a0\u00a0\u00a0 while(1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int del;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ wait for 500 milliseconds\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (del = 0; del &lt; 80000; del++);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 setInt(ReadTimer23());\r\n\u00a0\u00a0\u00a0 };\r\n\u00a0\u00a0 \u00a0\r\n}<\/pre>\n<p><strong><a href=\"http:\/\/techblog.auchmonoabspielbar.de\/?p=110\">Weiter zum Teil 5<\/a><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Als n\u00e4chstes ben\u00f6tige ich die Z\u00e4hler f\u00fcr das Eingangssignal. Praktischerweise besitzt der PIC32 neben dem Timer1, den ich f\u00fcr die Anzeige verwende, noch vier weitere 16 Bit Z\u00e4hler, die sich zu zwei 32 Bit Z\u00e4hlern zusammenschalten lassen. Heute habe ich mich darum gek\u00fcmmert, die Timer 2 und 3 als 32 Bit Z\u00e4hler zu verwenden. In [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-92","post","type-post","status-publish","format-standard","hentry","category-embedded"],"_links":{"self":[{"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/posts\/92","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=92"}],"version-history":[{"count":7,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions"}],"predecessor-version":[{"id":179,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions\/179"}],"wp:attachment":[{"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=92"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=92"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/techblog.auchmonoabspielbar.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=92"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}