Hallo zusammen, Ich habe Laufzeitprobleme. Dass heisst, der Code-Block im Anhang braucht zu lange. Ist es möglich, dass ich die Laufzeit eines Programmabschnittes (in C) berechnen (oder messen?) kann? Der 8-bit PIC16F15325 läuft mit 4MHz. Ich weiss, dass eine Instruktion bei meinem PIC 4 Takte braucht, aber wie viele Instruktionen braucht dann ein if, ein floor(), ein kleiner als, ...? Der Code im Anhang berechnet die Ziffern einer 4-stelligen 7-Segment-Anzeige die aber nur in 25-er Schritten anzeigen soll (0,25,50,75,100,125,150,...2750). Danke & Grüsse Severin
Hi, Kein Wunder, die Gleitkommaarithmetik (float) ist ursächlich dafür. Wirf die raus, arbeite mit Ganzzahlen (entsprechend skaliert)! Viele Grüße, Michael
Severin E. schrieb: > Ist es möglich, dass ich die Laufzeit eines Programmabschnittes (in C) > berechnen (oder messen?) kann? direkt nicht. Entweder am Anfang einen Pin high und am Ende wieder low schalten (und Oszi dran), oder in der Assemblerdatei Instructions/Zyklen zählen, oder aber step für step Simulieren und Steps zählen. Rest wurde schon gesagt: Michael schrieb: > Kein Wunder, die Gleitkommaarithmetik (float) ist ursächlich dafür.
:
Bearbeitet durch User
Michael schrieb: > Wirf die raus, arbeite mit Ganzzahlen (entsprechend skaliert)! Am Besten so skaliert, dass Divisionen durch z.B. 1024 anstatt 1000 durchgeführt werden, denn der Compiler macht dann keine "echte" Division mehr daraus sondern shiftet den Wert dann einfach. Dann wirds richtig schnell.
:
Bearbeitet durch User
Danke für die Infos. Hab den Block mit Pin hoch/tief und Oszi gemessen. Braucht etwa 10ms. Seeehr lang. Dass heisst ja bei 4MHz, dass da 10'000 Instruktionen ausgeführt werden. Ich werde mal versuchen, die floats wegzubringen ... Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen.
Jede Menge zu tun für diesen Kern bei dieser Berechnung.
Der Screenshot von MPLAB ist spannend. Dass heisst, es gibt irgendwo beim Debuggen ein "Stopwatch" zum messen von Laufzeiten. Muss mal suchen gehen...
Severin E. schrieb: > Ich werde mal versuchen, die floats > wegzubringen ... Nicht versuchen, machen! Das Schlimmste was dabei passieren kann, ist dass Du ne Menge dabei lernst und wenn gar nichts mehr geht, dass Du hier noch mal fragen musst. Bei solchen Problemen ist hier jeder gern bereit zu helfen. > Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen. Das ist cheaten..
Thomas S. schrieb: > Severin E. schrieb: >> Ich werde mal versuchen, die floats >> wegzubringen ... > > Nicht versuchen, machen! Das Schlimmste was dabei passieren kann, ist > dass Du ne Menge dabei lernst und wenn gar nichts mehr geht, dass Du > hier noch mal fragen musst. Bei solchen Problemen ist hier jeder gern > bereit zu helfen. > >> Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen. > > Das ist cheaten.. GENAU! Takt bleibt erst mal auf 4MHz. Die Berechnung muss sich ändern. Aber vielleicht nicht mehr heute Abend. Danke euch allen!
Severin E. schrieb: > Der Code im Anhang berechnet die Ziffern einer 4-stelligen > 7-Segment-Anzeige Interessant. Wer liest die Anzeige so schnell ab, dass das ein Problem ist? leo
leo schrieb: > Severin E. schrieb: >> Der Code im Anhang berechnet die Ziffern einer 4-stelligen >> 7-Segment-Anzeige > > Interessant. Wer liest die Anzeige so schnell ab, dass das ein Problem > ist? > > leo Die 4 Ziffern sollen nicht flackern. Als etwa 100Hz-Betrieb damit die Augen das nicht mitbekommen. 100Hz heisst bei 4 Ziffern, dass jede Ziffer 2,5ms bekommt. Da sollte man nicht noch andauernd 10ms-Berechnungen dazwischenschieben.
Okay, was mir auffaellt:
1 | uint16_t RPMdec; |
2 | uint16_t PWM10bit = 323; |
3 | |
4 | RPMdec = (float)PWM10bit*2750/1024; |
Wozu der Cast auf float? Die Nachkommastellen werden ja eh abgeschnitten. Dann tut es auch ein Cast nach uint32_t statt float.
1 | DIG1 = (RPMdev/1000) % 10; |
Mathematisch macht es keinen Unterschied ob du durch 1000 teilst oder nicht und dann den Rest nimmst. (RPMdev/1000) % 10 = RPMdev % 10. Ob es im erzeugten Code einen Unterschied macht musst du gucken. Selbiges fuer DIG2.
1 | float temp1; |
2 | temp1 = RPMdec - 100 * (floor(RPMdec/100)); |
Den Aufruf von floor() koenntest du auch sparen. Es ist eine Integer-Division. Das Abrunden passiert ja von ganz alleine. Kurz: 100 * (floor(RPMdec/100)) = 100 * (RPMdec/100) Und damit ist auch der float weg. Gruesse
Kaj schrieb: > Kurz: > 100 * (floor(RPMdec/100)) = 100 * (RPMdec/100) > > Und damit ist auch der float weg. Falsch! in "floor()" steckt der wieder drin... Dies muss auch noch weg. Integer-Division ist automatisch ohne Nachkommastellen.
Severin E. schrieb: > Die 4 Ziffern sollen nicht flackern. Als etwa 100Hz-Betrieb damit die > Augen das nicht mitbekommen. 100Hz heisst bei 4 Ziffern, dass jede > Ziffer 2,5ms bekommt. Da sollte man nicht noch andauernd > 10ms-Berechnungen dazwischenschieben. Du darfst du nur keine festen 10ms Blöcke dazwischen schieben. Die Rechnerei kann ganz in Ruhe ablaufen und die Anzeigesteuerung muss dann alle 2.5ms per Interrupt die Rechnerei irgendwo kurz unterbrechen und ein paar Takte für die Aktualisierung einfordern.
Severin E. schrieb: > Der Screenshot von MPLAB ist spannend. Dass heisst, es gibt irgendwo > beim Debuggen ein "Stopwatch" zum messen von Laufzeiten. Muss mal suchen > gehen... Geht im Simulator. https://www.youtube.com/watch?v=bUookr-2O-s (Stopwatch kommt so bei 5min.)
:
Bearbeitet durch User
Volker S. schrieb: > Severin E. schrieb: >> Der Screenshot von MPLAB ist spannend. Dass heisst, es gibt irgendwo >> beim Debuggen ein "Stopwatch" zum messen von Laufzeiten. Muss mal suchen >> gehen... > > Geht im Simulator. https://www.youtube.com/watch?v=bUookr-2O-s > (Stopwatch kommt so bei 5min.) Nicht nur. Das geht so auch zur Laufzeit auf dem Device. Man setzt zwei Breakpoints, und kann die Anzahl der Takte zwischen diesen messen. Das ist dann praktisch, wenn die Laufzeit von externen Faktoren abhängt. Außerdem kann man sich den Simulator so sparen.
soso... schrieb: > Nicht nur. Das geht so auch zur Laufzeit auf dem Device. Man setzt zwei > Breakpoints, und kann die Anzahl der Takte zwischen diesen messen. Aber leider nicht mit jedem Debugger-Tool und nicht bei jedem PIC.
Volker S. schrieb: > soso... schrieb: >> Nicht nur. Das geht so auch zur Laufzeit auf dem Device. Man setzt zwei >> Breakpoints, und kann die Anzahl der Takte zwischen diesen messen. > > Aber leider nicht mit jedem Debugger-Tool und nicht bei jedem PIC. Hmm. Also ich sehe aus dem Datenblatt des erwähnten PIC keine Grund, warum das nicht ginge. Man sollte den ja debuggen können, und ein PICkit3 kann Stopwatch. Eigentlich sollte das auch mit den billigen Klones gehen. Woran sieht man, ob das geht oder nicht? Bei mir gings bisher immer (hauptsächlich PIC24 allerdings).
Es wird zum Testen des Codeabschnittes keinerlei wechselwirksamer Peripherie beansprucht. Also Simulator. Da gibt es jede menge Breakpoints, Stopwatch, Disassembly, ... Und man sieht gleich, wie langsam der Code des freien XC8 ist. Gut optimierend käme wohl sowas wie folgend raus.
1 | uint8_t segment_code(uint8_t x) |
2 | {
|
3 | asm ("andlw 0x0f"); |
4 | asm ("brw"); |
5 | asm ("retlw 0xfc"); |
6 | asm ("retlw 0x60"); |
7 | asm ("retlw 0xda"); |
8 | asm ("retlw 0xf2"); |
9 | asm ("retlw 0x66"); |
10 | asm ("retlw 0xb6"); |
11 | asm ("retlw 0xbe"); |
12 | asm ("retlw 0xe0"); |
13 | asm ("retlw 0xfe"); |
14 | asm ("retlw 0xf6"); |
15 | asm ("retlw 0x00"); |
16 | asm ("retlw 0x02"); |
17 | asm ("retlw 0x01"); |
18 | asm ("retlw 0xff"); |
19 | asm ("retlw 0xff"); |
20 | asm ("retlw 0xff"); |
21 | |
22 | return 0xff; // suppress warning |
23 | }
|
soso... schrieb: > ein PICkit3 kann Stopwatch... > > Bei mir gings bisher immer (hauptsächlich PIC24 allerdings). Ups, da muss ich mal schauen, ob das bei PIC16/18 auch geht. Sollte laut dieser Tabelle mit PICkit3 eigentlich gar nicht gehen: http://microchipdeveloper.com/tls0201:debug-tool-capabilities Vielleicht veraltet? (ging evtl. früher nicht und ich habe es noch gar nicht bemerkt, dass das jetzt geht, weil ich den Simulator praktisch nicht benutze)
Kaj schrieb: > Mathematisch macht es keinen Unterschied ob du durch 1000 teilst oder > nicht und dann den Rest nimmst. > (RPMdev/1000) % 10 = RPMdev % 10. Das stimmt nicht ganz. Bsp: (5000 / 1000) % 10 = 5 5000 % 10 = 0 MfG
Volker S. schrieb: > Ups, da muss ich mal schauen, ob das bei PIC16/18 auch geht. Nope, geht nicht bei MPLABX v5.10 PICkit3 PIC18F25K22.
:
Bearbeitet durch User
Severin E. schrieb: > Danke für die Infos. Hab den Block mit Pin hoch/tief und Oszi gemessen. > Braucht etwa 10ms. Dann ist ja alles im grünen Bereich. Der Mensch kann nicht mehr als 2..5 Werte/s ablesen, d.h. Du hast 200..500ms Zeit für die Berechnung.
Volker S. schrieb: > soso... schrieb: >> ein PICkit3 kann Stopwatch... >> >> Bei mir gings bisher immer (hauptsächlich PIC24 allerdings). > > Ups, da muss ich mal schauen, ob das bei PIC16/18 auch geht. > Sollte laut dieser Tabelle mit PICkit3 eigentlich gar nicht gehen: > http://microchipdeveloper.com/tls0201:debug-tool-capabilities > > Vielleicht veraltet? > (ging evtl. früher nicht und ich habe es noch gar nicht bemerkt, > dass das jetzt geht, weil ich den Simulator praktisch nicht benutze) Interessant, laut deinem Link dürfte es mit dem PICkit3 nicht gehen. Ich bin mir aber zu sicher, dass ich mit MPLABX, dem PICkit3 und der Stopwatch auf und einige Projekte damit optimiert zu haben (zu 100% sicher bin ich mir bei den Devices PIC24FJ128GB204 und PIC32MX370). Das war mit einem MPLABX 3.xx. Naja, falls alle Stricke reißen, gibts ja noch Timer. Man kann sich einen aufsetzen, der im µs-Takt zählt, und damit die Zeit messen. Man kann sogar OC-Timer nehmen, falls vorhanden. Das Scope wurde schon genannt.
Eine Rückmeldung meinerseits: Ich habe nun den Code umgeschrieben(float weg, floor weg und leicht geändert) und nun braucht der Block im Anhang nur noch 2,5ms und nicht mehr 10ms wie der Code im ersten Post. Also etwa 4x schneller! Danke allen & Grüsse
Was ich gesehen habe, nutzt du das ganze für Anzeigezwecke im BCD-Format. Da könntest du die Berechnung doch auch mehr oder weniger gleich in BCD machen. Den Quelltext habe ich mal angehängt. Die 1000er Stelle kann ja nur 0, 1 oder 2 werden --> deswegen if - Abfrage "zu Fuß". Die noch verbliebenen Hunderter können Wertemäßig noch über 255 sein, deshalb wird ein konstantes 16 Bit Array zum Vergleich genutzt und die Wertigkeit bestimmt. Bei der Berechnung der 10er - Stelle kann im verbleibenden Wert niemals etwas über 255 stehen --> es wird mit 8 Bit gearbeitet, das macht das ganze schneller. Auf die Berechnung der 1er Stelle habe ich verzichtet, das würde ich dann aber auch wieder "zu Fuß" machen, wenn benötigt - ungenau ist es allemal. Damit sollte sich noch etwas mehr Rechenzeit sparen lassen, schlecht ist nur: Es muss ggf. bei anderer Skalierung der Drehzahl umgeschrieben werden. Ob du dir so eine Code-Krake ins Programm holen willst, ist auch noch eine Frage... :)
1 | #define MUL 1024*1024/2750
|
2 | const unsigned int div100[9] = { //16 Bit Vergleichsarray für 100er |
3 | 1*MUL/10, 2*MUL/10, 3*MUL/10, 4*MUL/10, 5*MUL/10, |
4 | 6*MUL/10, 7*MUL/10, 8*MUL/10, 9*MUL/10 }; |
5 | |
6 | const unsigned char div10[9] = { //8 Bit Vergleichsarray für 10er |
7 | 1*MUL/100, 2*MUL/100, 3*MUL/100, 4*MUL/100, 5*MUL/100, |
8 | 6*MUL/100, 7*MUL/100, 8*MUL/100, 9*MUL/100 }; |
9 | |
10 | unsigned char bcdout[4] = {0,0,0,0}; //BCD-Ausgabe-Array (1000er - 1er) |
11 | unsigned char j; //Schleifenzähler |
12 | unsigned char RPMdecLowerByte; |
13 | |
14 | RPMdec = PWM10bit; |
15 | |
16 | if (RPMdec >= 2*MUL) { //1000er Stelle --> Wertigkeit 2 |
17 | bcdout[0] = 2; |
18 | RPMdec -= 2*MUL; |
19 | }
|
20 | if (RPMdec >= 1*MUL) { //1000er Stelle --> Wertigkeit 1 |
21 | bcdout[0] = 1; |
22 | RPMdec -= 1*MUL; |
23 | }
|
24 | |
25 | |
26 | //Ermittle 100er Stelle mit 16-Bit-Vergleichsarray
|
27 | for (j = 8; j >= 0; j--) { // fange bei höchster Wertigkeit an |
28 | if (RPMdec >= div100[j]) { //sobald RPMdec größer als vergleichswert |
29 | bcdout[1] = j + 1; //schreibe Ziffer |
30 | RPMdec -= div100[j]; //Ziehe Ziffernwertigkeit von RPMdec ab |
31 | break; //und beende for-schleife |
32 | }
|
33 | }
|
34 | |
35 | RPMdecLowerByte = RPMdec & 0xFF; //Lower Byte in 8 Bit Variable |
36 | |
37 | //Ermittle 10er Stelle mit 8-Bit-Vergleichsarray
|
38 | for (j = 8; j >= 0; j--) { // fange bei höchster Wertigkeit an |
39 | if (RPMdecLowerByte >= div10[j]) { //sobald RPMdec größer als vergleichswert |
40 | bcdout[2] = j + 1; //schreibe Ziffer |
41 | RPMdecLowerByte -= div10[j]; //Ziehe Ziffernwertigkeit von RPMdec ab |
42 | break; //und beende for-schleife |
43 | }
|
44 | }
|
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.