Hallo
ich habe ein Prg, was im Timer Betrien läuft. Habe als Beispiel kurz
dargestellt:
1
....
2
Timer
3
....
4
ISR10ms
5
....
6
while(1)//Beginn Timer Schleife
7
if(wait10ms//timer/ISR)
8
{.....
9
.............
10
//mach was
11
//Toggelt eine LED mit 1s
12
wait10ms=0
13
// End
Wichtig dabei ist, das die ganze Schleife in 10ms komplett durchlaufen
wird. Bei einigen Sachen, z.B. Berechnungen ist mir aufgefallen, das es
mehr Zeit braucht als sonst. Zur Kontrolle habe ich am Ende des Prg eine
LED drin, die mir die Zeit anzeigt. Andere Teile des Prg habe ich
Unterprogramme ausgelagert. Einfache Frage dazu. Wie kann ich die
Berechnungen gestalten ohne unnötig Zeit zu vergeuden?
achim
Ich suche noch die Berechnung !
Mit Wertebereichen für die Funktionen ist auch eine Umstellung evtl. auf
32 oder 64-Bit Integer möglich, aprox. mit Polygonen, Tabellen und what
ever denkbar !
Mit dem Programmfetzen ist nicht viel anzufangen. Also was möchtest du
und wie sieht das Programm aus? Zumindest die Timer ISR, die
Timerinitialisierung und Angaben über MC und Taktfrequenz wären sehr
hilfreich.
Es wäre sinnvoller wenn du die Berechungen gepostet hättest. Dann
könnten dir die Leute hier mit konkreten Verbesserungsvorschlägen
weiterhelfen.
Hast du mal gemessen wie lange dein aktueller Code braucht um
abgearbeitet zu werden? Du könntest ja einen anderen Timer am Anfang der
While-Schleife starten und am Ende den Zählstand auslesen. u.U. musst du
ja gar nicht so viel optimieren wie du denkst.
Auserdem wäre noch interessant welchen µC du verwendest. Ein Atmega hat
beispielsweise einen Hardware-Multiplier, ein Attiny meines Wissens
nicht. Das hat natürlich auch einen entscheidenden Einflus auf die
Berechnungszeit.
lg much
Geht es Dir nur darum, Deinen Code soweit zu optimieren,
dass die notwendigen Berechnungen immer in unter 10ms abgearbeitet
werden können?
Lösung 1: Dein Code lässt sich optimieren und Du schaffst die
Berechnungen in unter 10ms.
Lösung 2: Dein µC hat nicht genug Performance.
[Lösung 3: Falls Du aber meinst, dass es Applikationen gibt,
die im 10ms-Raster laufen müssen und die nicht von größeren
Berechnungen gestört werden dürfen: Geschicktes Aufteilen der
Berechnung oder Einsatz eines Betriebssystems.]
Habe denn Timer und die ISR drin. Es ist auch die Entprellung nach Peter
dabei. Im gesamten Prg verwende ich keine delay. Dadurch wird der
gesamte Ablauf durch den Timer gesteuert. Es gibt einen Artikel im Netz
"Warten verboten". Nach diesem habe ich das Prg geschrieben.
Habe festgestellt, das bei Berechnungen z.B. Ort oder Spannung das
gesamte Prg langsamer wird. Wie kann ich das vermeiden?
achim
Hallo
nach dem Code von Peter Dannegger ist die Key Entprellung in der ISR
drin und wird durch den Timer gesteuert. Hier im Netz gibt es genügend
Artikel dazu. Kann nur sagen, es läuft hervorragend.
Das Problem sind die Berechnungen. Werden diese in Unterprg ausgeführt,
bruachen diese sehr viel Zeit. Die LED am Ende des Prg laufen immer in
dem bestimmten Takt von 1s. Sobald die Berechnung kommt, werden die LED
zeiten länger und gehen auf ca 2 bis 3 s.
achim
Hallo,
nun das liegt nicht mehr in deinem Einfluss Bereich, die NIBO Library
ist für dich nicht veränderbar.
Ist also ein sytemisches Problem.
http://www.nibo-roboter.de/wiki/NIBO_2
Hallo Uwe
gibt es keine Möglichkeit Math. Ausdrücke oder Formeln zu zerlegen (?)
um diese zu nutzen?
Die Grundrechenarten werden reduziert auf das nächste kleinere. Mal und
geteilt auf plus und minus. Diese können wiederum durch Bitoperationen
gemacht werden. Ist dadurch etws möglich? Einige der getesteten
Funktionen verzögern das gesamte Prg.
achim
Achim Seeger schrieb:> Hallo Uwe> gibt es keine Möglichkeit Math. Ausdrücke oder Formeln zu zerlegen (?)> um diese zu nutzen?
Wo sind denn die in deinem Programm?
Oder anders gefragt: Was in deinem Programm dauert zu lange, so dass die
Hauptschleife nicht mehr in 10ms durch ist?
Das das Hinpinseln auf einem grafischen LCD nicht unbedingt schnell ist,
kann ich mir schon vorstellen. Dann muss man sich halt überlegen, was
davon ist eigentlich bei jedem Durchlauf durch die Hauptschleife immer
gleich (Beschriftungen etc.), das pinselt man nur einmal hin und was
ändert sich laufend (Messwerte, Diagramme etc) und muss daher laufend
aktualisiert werden.
UNd wenn das dann immer noch nicht reicht, gibt es 2 Möglichkeiten
* entweder den Update eben auf mehrere Durchgänge durch die
Hauptschleife verteilen. Das Stichwort 'Statemaschine' ist ja
schon gefallen.
* oder die Zeitvorgaben lockern. Wenn die 10ms nicht in Stein gemeisselt
sind, kann man ja auch auf 20ms gehen. Für einen Benutzer macht das
kaum einen Unterschied. Ob 1/100 oder 2/100 Sekunden kann kein
Mensch mit freiem Auge unterscheiden.
> Einige der getesteten Funktionen verzögern das gesamte Prg.
WELCHE?
Der erste Schritt bei der Optimierung lautet immer:
* Muss ich überhaupt optimieren oder bin ich schnell genug
* Wenn ich nicht schnell genug bin, kommt das vielleicht daher
das ich einen Programmfehler habe
* Ist das alles nicht der Fall und steht fest, dass optimiert werden
muss, dann ist die nächste Frage: Wo wird Zeit verbraten? Welche
Programmteile verbrauchen wieviel Zeit?
* Und erst dann kann man eine Strategie austüfteln, wie man
optimiert.
Hallo Karl Heinz
ich hatte in einem anderen tread in einem Prg eine Berechnung drin. So
was einfaches wie a=b/c. Du hattest mir dann empfohlen diese
rauszunehmen, weil es zu lange dauert.
Habe an den Timern weitergemacht. Brauche auch für andere Sachen eine
Berechnung z.B. Spannungsgrösse berechnen und weiter in Prozent und die
Ausgabe dazu. Leider wird der Timer dadurch ausgebremst. Gibt es dazu
eine Lösung?
achim
Achim Seeger schrieb:> Hallo Karl Heinz> ich hatte in einem anderen tread in einem Prg eine Berechnung drin. So> was einfaches wie a=b/c. Du hattest mir dann empfohlen diese> rauszunehmen, weil es zu lange dauert.
Das war 'gestern'. Heute ist ein neuer Tag, heute sieht dein Programm
schon ganz anders aus. In der Zwischenzeit hat sich die ganze
Programmstruktur geändert.
> Habe an den Timern weitergemacht. Brauche auch für andere Sachen eine> Berechnung z.B. Spannungsgrösse berechnen und weiter in Prozent und die> Ausgabe dazu. Leider wird der Timer dadurch ausgebremst.
Nochmal: WO genau passiert das?
Es bringt nichts, wenn du dich jetzt aus dem Bauch heraus vor etwas
fürchtest, das in Wirklichkeit überhaupt kein Problem darstellt. 10
Millisekunden sind auch für einen AVR eine lange Zeitdauer, in der er
schon einiges schafft. Wirf deine Berechnung rein, achte darauf, das du
vernünftige Datentypen benutzt (Floating Point nimmst du nur dann, wenns
nicht anders geht und auch dann nur unter Protest, ansonsten willst du
nach Möglichkeit uint8_t, wenn das nicht reicht uint16_t und wenn das
nicht reicht uint32_t) und lass es einfach mal darauf ankommen, dass die
Berechnung schnell genug ist. Und wenn sich DANN rausstellt, das du zu
langsam bist, dann wird über Möglichkeiten zur Optimierung nachgedacht.
Aber nicht vorher.
Achtung: Das bedeutet NICHT, das man sich bei der Erstimplementierung
nicht Gedanken über einen vernünftigen Codeaufbau macht. Natürlich tut
man das. Man will ja auch nicht MUTWILLIG das Programm ausbremsen, wenn
es nicht sein muss. Aber in der Erstimplementierung machst du dir keine
Gedanken über 'Kleinviehoptimierung'. Wenn du multiplizieren musst, weil
deine Berechnung eben eine Multiplikation erfordert, dann multiplizierst
du und denkst nicht über Tricks nach. Das du vorher die Formeln auf dem
Papier vereinfacht hast um nicht unnötig Dinge zu berechnen, die kein
Mensch braucht, versteht sich von selbst.
Wenn du einen Tacho baust und dazu Weg und Zeit misst, dann wird dir zur
Bestimmung der Geschwindigkeit nichts anderes übrig bleiben als Weg
durch Zeit zu dividieren. Wenn das schnell genug ist: super - Fall
abgehakt, interessiert keinen mehr. Ist es aber nicht schnell genug,
dann muss man sich was überlegen. Zb ob es eine Möglichkeit gibt die
Zeit auf 1 festzunaglen. Denn durch 1 dividieren ist leicht. Geht das
nicht, dann kann man die Zeit vielleicht auf eine 2-er Potenz
festnageln. Auch das nimmt dem µC Arbeit ab. Und du siehst schon: Die
Optimierung läuft jetzt in eine ganz andere Richtung als 'mit welchen
Tricks kann ich eine Division an sich schneller machen' bzw. 'kann ich
eine Division auf mehrmals aufteilen'
ich hatte an der Stelle von textro++ eine Berechnung drin. Hatte diese
auch als Ort der Anzeige verwendet. Dies Berechnung verbrauchte sehr
viel zeit, wodurch das ganze Prg langsam lief. Suche noch das original.
achim
ich verwende hier
text1o=textro/20;
diese Zeile verursacht eine längere Verarbeitungzeit. Wie kann ich es
ändern ohne die Laufzeit zu behindern?
In dem eigentlichen Prg habe ich es bereits durch eine andere Routine
ersetzt. Bleibt nur noch die Frage der Beechnung. Das Prg, wo es drin
war steht weiter oben
achim
> ich verwende hier> text1o=textro/20;> diese Zeile verursacht eine längere Verarbeitungzeit.
'länger' ist ein dehnbarer Begriff.
> Wie kann ich es> ändern ohne die Laufzeit zu behindern?
Genau so, wie du es gemacht hast: Mit einer zusätzlichen Variablen, die
bis 20 zählt.
Dein 'länger' kommt in erster Linie nicht von der Division, sondern
davon, dass du 19 mal einen LCD Update machst, der unnötig ist!
Wenn sich textro immer nur um 1 erhöht und text1o ein 20-tel davon ist,
dann kommt 20 mal hintereinander derselbe Wert bei dieser Division raus!
1
Aufruf textro textro / 20 text1o
2
---------------------------------------------
3
1 0 0 0 -> Text an Position 0 schreiben
4
2 1 0 0 -> Text an Position 0 schreiben
5
3 2 0 0 -> Text an Position 0 schreiben
6
4 3 0 0 -> Text an Position 0 schreiben
7
.....
8
17 16 0 0 -> Text an Position 0 schreiben
9
18 17 0 0 -> Text an Position 0 schreiben
10
19 18 0 0 -> Text an Position 0 schreiben
11
20 19 0 0 -> Text an Position 0 schreiben
12
21 20 1 1 -> Text an Position 1 schreiben
13
22 21 1 1 -> Text an Position 1 schreiben
14
...
D.h. du schreibst zwar korrekterweise EINMAL (das erste mal) mittels
>> gfx_move(text1o,45); // Angabe Ort unter Logo>> gfx_print_text(" N I B O 2"); // Ausgabe Nibo 2
den Text aufs LCD, zb. an die Position 0. Aber bei den nächsten 19
Durchläufen durch diesen Code ergibt deine Berechnung ebenfalls die
Position 0 und du schreibst somit 19 mal einen Text aufs LCD, der schon
dortsteht!
Und DAS muss nicht sein und lässt sich leicht abstellen.
Das ist der Grund für die 'Optimierung'.
Der Zeitbedarf für die Division ist dahingehend komplett zu
vernachlässigen. Die Ausgabe eines Textes dauert wesentlich länger als
so eine popelige Division durch 20.
Die Umstellung mit einer zusätzlichen Variablen hat also in erster Linie
den Zweck, unnötige Ausgaben aufs LCD zu unterbinden. Das dadurch auch
die Division weggefallen ist, ist ein netter Nebeneffekt.
ist NICHT gleichwertig!
Im ersten Fall werden 20 mal so viele LCD-Textausgaben gemacht, wie im
2.ten Fall. Das das keinen optischen Unterschied macht, liegt nur daran,
dass von 20 Textausgaben, 19 mal ein Text ausgegeben wird, der schon am
LCD steht und die somit alle mitsammen überflüssig sind, die aber sehr
wohl Zeit benötigen.
Karl Heinz Buchegger schrieb:> Die Umstellung mit einer zusätzlichen Variablen hat also in erster Linie> den Zweck, unnötige Ausgaben aufs LCD zu unterbinden.
Unnötige Ausgaben kosten nicht nur viel CPU-Zeit, sondern stören sogar.
Der Mensch kann nur begrenzt schnell ablesen. Schneller bewirkt ein
Flackern und die Augen ermüden.
In meinen Programmen werden Ausgaben daher oft absichtlich verlangsamt
(z.B. nur alle 200ms).
Auch sind Ausgaberoutinen in der Regel nicht reentrant. D.h. bei
Ausgaben im Main und in Interrupts knallts (wirrer Text an falscher
Position).
Peter
Hallo Karl Heinz
leider sind die 19 mal nicht überflüssig. Der kleine Text geht als
Laufschrift über das Display. Hat die Aufgabe zu zeigen, was alles mit
der Timer Steuerung möglich ist. Durch das fast gleichzeitige ausführen
verschiedener Sachen, sieht man es am besten. Bei der Schrift " Nibo 2"
habe ich die erste Stelle vor Nibo freigelassen. Bei jeder neuen Schrift
löscht es dadurch ein Teil der alten. Mit deiner Verzögerung hat es sehr
gut funktioniert. Die Zeit zur Verzögerung beträgt bei mir auch 20x10ms.
Dadurch bewegt sich die Schrift langsam und ist verhältnismässig gut zu
sehen. In beiden Fällen erfolgt die Ausgabe auf das Display. Bei ersten
Version ist die Berechnung noch zusätzlich drin. Die Zeit (Kontrolle
durch LED) wird dadurch ca 2 bis 3 mal so lang. Die Kontrolle arbeitet
mit 0,5 Hz und sollte immer gleich sein. Dort ist Änderung deutlich
sichtbar. Habe die Erfahrung machen müssen, das Timer Programmierung, so
wie ich mache, nicht so leicht ist. Muss immer umdenken und neues
probieren. Ansonsten kann ich nur sagen, es macht sehr viel Spass. Bin
einfach am staunen was alles (fast) gleichzeitig möglich ist.
achim
Hallo
habe ein Stück Prg unetn dargestellt. Das restliche Prg steht schon
oben. Es wird durch einen Timer und die ISR gesteuert. Am Ende läuft
eine LED, die mir anzeigt wie der gesamte Takt ist. Ohne dieses Prg
läuft die LED mit ca. 0,5Hz. Mit dem Prg Teil drin verlangsamt es sich
auf ca 3 bis 5 S. Habe noch ein bisschen Graphik dazu genommen.
Kommentiere ich dei Formeln aus, stimmt die Geschwindigkeit.
1
voidnibo_batt1()
2
{
3
uint16_tcharge;
4
uint8_tB1;
5
charge=(10*(bot_supply-505))/160;
6
B1=(105-(charge/5));
7
8
gfx_move(10,50);gfx_hline(105);
9
gfx_move(10,60);gfx_hline(105);
10
gfx_move(10,50);gfx_vline(11);
11
gfx_move(115,50);gfx_vline(11);
12
gfx_draw_mode(GFX_DM_JAM2);
13
gfx_move(10,50);gfx_box(B1,10);
14
15
bot_update();chartext[20];
16
17
floatvolt=0.0166*bot_supply-0.4;
18
sprintf(text,"%3.2f V %4.0f Prz.",(double)volt,(double)B1);
19
20
gfx_move(10,5);gfx_set_proportional(0);
21
gfx_print_text("Batteriespannung :");
22
gfx_move(10,29);gfx_set_proportional(0);
23
gfx_print_text("Bitte Akku laden !");
24
gfx_move(15,17);gfx_set_proportional(0);
25
gfx_print_text(text);
26
gfx_move(35,41);gfx_set_proportional(1);
27
gfx_print_text("8,0V");
28
gfx_move(105,41);gfx_set_proportional(1);
29
gfx_print_text("10,5V");
30
}
Einfache Frage dazu, wie kann ich die Berechnung ändern, damit die Zeit
wieder stimmt? Arbeite mit Atmega 128 16MHz und alles über einen Timer
gesteuert.
achim
Achim Seeger schrieb:> Hallo Karl Heinz> leider sind die 19 mal nicht überflüssig.
Doch sind sie.
Etwas auf ein Display zu schreiben, was schon dortsteht, und zwar an
exakt dieser Position, ist überflüssig!
> Der kleine Text geht als> Laufschrift über das Display.
Das ist ein anderes Thema.
Wenn der Text um 1 Position weiterhüpft ist das eine andere Sache.
Aber 20 mal denselben Text an dieselbe Position auszugeben, ist
überflüssig.
Rück mal ein Stück zur Seite. Du sitzt gerade auf der Leitung.
> Einfache Frage dazu, wie kann ich die Berechnung ändern,> damit die Zeit wieder stimmt?
Indem du die Ausgabe unterdrückst, wenn das was du ausgeben willst,
schon am Display steht.
Es macht zb keinen Sinn, das hier aufs DIsplay hinmalen zu lassen
1
gfx_move(10,5);gfx_set_proportional(0);
2
gfx_print_text("Batteriespannung :");
wenn genau das schon am Display steht. Diesen Text gibst du beim ersten
mal aus. Danach steht er schon dort und muss beim 2.ten mal nicht mehr
ausgegeben werden.
Hallo Karl Heinz
soweit klar. Nehme ich die Berechnung raus, habe ich mit dem Display und
der Darstellung keinerlei Problem. Habe in anderen Teilen des Programms
noch andere Display Befehle. Die Zeit stimmt super. Sind die
Berechnungen drin, geht es langsam. Habe hier auch keine Laufschrift
drin. Alle Versuche ergaben, das es an der Bechnung liegt. Wie kann ich
das anders lösen?
achim
Hallo Karl Heinz
habe , so wie es aussieht, in den Griff bekommen. An den Display
Befehlen liegt es nicht. Ob ich noch einige nehme oder nicht, fällt kaum
auf.
Habe folgendes gemacht
- Umstellung der Formeln von Fliesskomma auf Festkomma (soweit möglich)
- vereinfachung der Rechnungen (einsparen wo es geht)
- Begrenzung der Abfragen
Der Abruf der Funktion erfolgt über Taster und Menu. Dadurch wird die
Rechnung nur einmal ausgeführt. Weiterer Abruf wird über einen Flag
gesperrt. Begrenzung der Anzeigdauer
Damit wird die gesamte Zeit nur unwesentlich beeinflusst. Die
Eigentliche Rechnung und Aufruf der Unterfunktion verursacht nur eine
einzige Verzögerung bei einem Durchlauf.
Damit geht das auch. Auf zum nächsten Problem
achim