Datum:
Hallo zusammen, ich arbeite mich gerade in die Thematik Microcontroler ein. Ich nutze das AVR Studio und Programmiere in Assembler. Ich möchte gerne 2 Eingänge "Verunden" und anschließend einen Ausgang setzen. Also, hier mein Code:
//Ausgang im PORTB,7 auf "1" setzen wenn Alle Eingänge (0,2,3,5,6) auf "1" in r16,PINB ldi r17,0b01101101 and r16,r17 CP r16,r17 BREQ _B7_AN //Ausgang im PORTB,7 auf "0" setzen wenn Mindestens 1 Eingang (0,2,3,5,6) auf "0" rjmp _B7_AUS //Rücksprungmarke _B7_DONE: |
In den Routinen "_B7_AN" bzw "_B7_AUS" wird zum Schluss zur Marke "_B7_DONE" gesprungen. Die Frage ist nun, gibt es eine "bessere" Lösung ? mfg
Datum:
Hi
>Die Frage ist nun, gibt es eine "bessere" Lösung ?
Zumindest eine etwas kürzere:
in r16,PINB andi r16,0b01101101 cpi r16, 0b01101101 BREQ _B7_AN ... |
MfG Spess
Datum:
Besten Dank für die Antwort. Für mich war relevant das es funktionell Fehlerfrei ist. Da ich mich gerade noch einlese werde ich, der Übersichtlichkeit wegen die "längere" variante nehmen. Danke aber für die Kurzfassung. mfg
Datum:
leMe schrieb: > Für mich war relevant das es funktionell Fehlerfrei ist. Warum hast du das dann nicht gefragt? leMe schrieb: >>> Die Frage ist nun, gibt es eine "bessere" Lösung ? Und ja, Spess hat eindeutig die bessere Lösung durch die Verwendung der immediate Befehle andi und cpi. Er spart dadurch die Verwendung des Registers 17 (Ressourcen) und einen Taktzyklus (Zeit). > Da ich mich gerade noch einlese werde ich, der Übersichtlichkeit wegen > die "längere" variante nehmen. Es wäre toll, wenn man das am Anfang schon richtig lernen würde und sich nicht erst einen umständlichen Stil aneignet und hinterher umlernen muss. Und übersichtlicher ist die kürzere Variante allemal... Und ich hatte die selbe Variante auch schon da stehen, nur war Spess schneller... ;-)
Datum:
Hi, ich komme Hobbymäsig aus der Programmierecke (c#). Daher habe ich nicht den Blick für übermäßig Resourcen sparende Programme. Ich habe es bisher so verstanden das die Register (in diesem Fall r17) so oder so vorhanden sind, und entsprechend genutzt werden könnnen, also würde ich doch eigentlich keine Resourcen sparen wenn ich es nicht nutze oder? Und zum Thema Zeit: Gibt es wirklich fälle in denen 1-Zyklus Relevant ist? Ich meine mal gelesen zu haben das die Zykluszeit eine µC (Atmega8) ~60nSec beträgt. Gibt es da Fälle in denen +-60nSec den Unterschied machen? mfg
Datum:
leMe schrieb: > Ich meine mal gelesen zu haben das die Zykluszeit eine µC (Atmega8) > ~60nSec beträgt. Bei 16MHz 62,5ns pro Takt, richtig.
Datum:
leMe schrieb: > Ich habe es bisher so verstanden das die Register (in diesem Fall r17) > so oder so vorhanden sind, und entsprechend genutzt werden könnnen Richtig, es ist aber nur 1 mal vorhanden. Und wenn du es jedesmal neu laden musst, weil jeder damit herumfroscht, kostet das Zeit und Speicherplatz... > Und zum Thema Zeit: > Gibt es wirklich fälle in denen 1-Zyklus Relevant ist? Das schon auch. > Ich meine mal gelesen zu haben das die Zykluszeit eine µC (Atmega8) > ~60nSec beträgt. Hängt vom Takt ab. > Gibt es da Fälle in denen +-60nSec den Unterschied machen? Es ist nicht dieser eine Befehl. Sondern du kannst alles elegant oder umständlich machen (so wie man es gelernt hat, eben). Und dann mach den Fehler mal 1000 mal hintereinander. Mein Rechner hier hat ein paar GHz, und trotzdem ist der manchmal langsam. Das liegt u.A. daran, dass zuviel unnötiges Zeug gemacht wird...
Datum:
leMe schrieb: > Hi, > > ich komme Hobbymäsig aus der Programmierecke (c#). > Daher habe ich nicht den Blick für übermäßig Resourcen sparende > Programme. > Ich habe es bisher so verstanden das die Register (in diesem Fall r17) > so oder so vorhanden sind, und entsprechend genutzt werden könnnen, also > würde ich doch eigentlich keine Resourcen sparen wenn ich es nicht nutze > oder? Das kommt drauf an. Dein komplettes Programm wird ja nicht nur aus diesen 5 Zeilen Code bestehen. Natürlich gibt es für nicht benutzte Register kein Geld zurück. Aber jedes Register, welches irgendwo benutzt wird, beeinflusst unter Umständen Code an anderen Stellen. Dort muss dann beachtet werden, dass genau dieses Register eben nicht unbedingt zur Verfügung steht. Benutzt du kein Register, weil du es nicht wirklich benötigst, musst du dich daher an anderen Programmstellen nicht daran erinnern, dass r17 genau an dieser Stelle 'verbraucht' wurde. Möglichen Problemen dadurch aus dem Weg zu gehen, indem man sie erst gar nicht entstehen lässt ist meistens auf lange Sicht gesehen eine ziemlich gute Strategie :-) > Und zum Thema Zeit: > Gibt es wirklich fälle in denen 1-Zyklus Relevant ist? > Ich meine mal gelesen zu haben das die Zykluszeit eine µC (Atmega8) > ~60nSec beträgt. > Gibt es da Fälle in denen +-60nSec den Unterschied machen? Klar. Wenn ich die Laufzeit eines Lichtstrahls auf 30 Zentimeter messen will, kommt es auf jede Nanosekunde an. D.h. Du musst wissen, anhand deiner Aufgabenstellung, ob du die Zeitreserve hast oder nicht! Das kann dir keiner abnehmen, solange er die Aufgabenstellung nicht kennt. Aber hier geht es eigenntlich um was anderes. Auch wenn die allgemeine Direktive lautet: Optimiere erst, wenn alles fertig ist, und feststeht wo du überhaupt Optimierungsbedarf hast (wenn überhaupt), bedeutet das noch lange nicht, dass man wie wild drauflosprogrammieren kann/sollte. Die eigentliche Frage lautet an dieser Stelle: gewinnst du durch die Verwendung des Registers irgendetwas? Vielleicht Übersicht oder Zeit oder Programmspeicher? Und die Antwort lautet in allen 3 Fällen: Nein. Warum willst du dann diese Variante verwenden? Der einzige Grund scheint der zu sein, dass du bisher die entsprechenden Immediate-Befehle nicht kanntest. Das wäre dann zwar verständlich, ist aber trotzdem ein schlechtes Argument.
Datum:
Hi, besten Dank für die viellen Erlkärungen! Jetzt ist mir das ganze etwas deutlicher geworden warum die von spess53 gepostete Lösung klar favoriert wird. Ursprünglich fand ich meine gepostete Lösung leichter verständlich, aber durch eure Erklärungen finde ich die gepostete Lösung klar besser, das liegt vor allem daran das ich jetzt weis warum genau diese Lösung so funktioniert, wie sie funktioniert, bzw was der Unterschied zw AND / ANDI ist. Besten Dank! mfg
Datum:
HI >Ich habe es bisher so verstanden das die Register (in diesem Fall r17) >so oder so vorhanden sind, und entsprechend genutzt werden könnnen, also >würde ich doch eigentlich keine Resourcen sparen wenn ich es nicht nutze >oder? Ist richtig. Aber z.B. in einem Interrupt muss man das zusatzlich Register extra sichern. >Gibt es wirklich fälle in denen 1-Zyklus Relevant ist? >Ich meine mal gelesen zu haben das die Zykluszeit eine µC (Atmega8) >~60nSec beträgt. Aber nur bei 16MHz. Der kann beliebig langsam getaktet werden. Bei 32768kHz sind es 30,5µs. Und bei dem obigen Beispiel, Interrupt, werden mit dem push/pop aus einem zusätzlichen Takt schon fünf. >Gibt es da Fälle in denen +-60nSec den Unterschied machen? Auf die Schnelle fällt mit z.B. Videotiming ein. MfG Spess
Datum:
spess53 schrieb: > Auf die Schnelle fällt mit z.B. Videotiming ein. Bei Software-USB (VUSB) werden die Takte auch von Hand abgezählt...
Datum:
leMe schrieb: > Ursprünglich fand ich meine gepostete Lösung leichter verständlich, aber > durch eure Erklärungen finde ich die gepostete Lösung klar besser, das > liegt vor allem daran das ich jetzt weis warum genau diese Lösung so > funktioniert, wie sie funktioniert, bzw was der Unterschied zw AND / > ANDI ist. Eine kleine Zutat fehlt noch. In diesem Code kommt die Binärkonstante (die wohl die inetressierenden Eingänge darstellst) 2 mal vor.
andi r16,0b01101101 cpi r16, 0b01101101 |
Beide Stellen müssen übereinstimmen, sonst gibt es Datensalat. Bei einer Änderung ist es daher wichtig, dass immer beide Stellen geändert werden. Und wenn dieselbe Konstante im Programm auch noch an anderen Stellen vorkommt, dann muss dort ebenfalls geändert werden. Das alles ist aufwändig und vor allen Dingen fehleranfällig. Geh niemals davon aus, dass du als Programmierer keine Flüchtigkeitsfehler begehst. Ganz im Gegenteil, frag dich immer welche Flüchtigkeitsfehler du machen kannst und dann frag dich "Was kann ich dagegen tun?" Im konkreten Fall ist es leicht, da Abhilfe zu schaffen: Schreib die Konstante einfach nicht 2-mal hin. Wie kannst du das machen? Ganz einfach, in dem du für diese spezielle Binärkonstante einen Namen einführst, der nach Möglichkeit irgendwas mit der Aufgabenstellung zu tun hat. Bei dir reräsentiert diese Binärzahl eine Maske, die alle Eingänge codiert, an denen Taster hängen. Also warum nicht einfach das ganze Dinge ALL_KEY_INPUTS nennen?
.equ ALL_KEY_INPUTS = 0b01101101 .... andi r16, ALL_KEY_INPUTS cpi r16, ALL_KEY_INPUTS ... |
Und wenn du dir die verwendende Stelle jetzt nochmal ansiehst und die Grundidee hinter der Sequenz ANDI/CPI erkannt hast (nämlich zu testen, ob irgendeines der in der Maske angegebenen Bits eine 0 aufweist), dann gewinnt dieser 2-Zeiler durch die Verwendung des Namens plötzlich eine neue Bedeutungsebene! Jetzt ist auch klar, was denn hier eigentlich konzeptionell gestestet wird: Nämlich die Eingabetaster! Noch ein kleiner Kommentar dazu, dass hier nach einem 0 Bit gefahndet wird
.... andi r16, ALL_KEY_INPUTS ; überprüfen ob irgendeiner auf 0 gegangen ist cpi r16, ALL_KEY_INPUTS ... |
und du hast vorgesorgt, dass du auch in 6 Monaten den Code aus dem Zusammenspiel von Code und Kommentar schnell erfassen kannst. Und als Nebeneffekt ist es nicht mehr möglich, dass dir die beiden Konstanten im ANDI/CPI auseinanderlaufen :-) Man könnte jetzt da noch weiter gehen und sich überlegen wie man die Binärkonstante wartungsfreundlicher gestalten kann, aber an dieser Stelle möchte ich es momentan damit belassen. Zuviel Information auf einmal kann auch kontraproduktiv sein.
Datum:
Lothar Miller schrieb: > Mein Rechner hier hat ein paar GHz, und trotzdem ist der manchmal > langsam. Das liegt u.A. daran, dass zuviel unnötiges Zeug gemacht > wird... Was zu einem Gutteil an solchen Leuten liegt: :) leMe schrieb: > ich komme Hobbymäsig aus der Programmierecke (c#). > Daher habe ich nicht den Blick für übermäßig Resourcen sparende > Programme.
Datum:
Karl Heinz Buchegger schrieb: > In diesem Code kommt die Binärkonstante (die wohl die inetressierenden > Eingänge darstellst) 2 mal vor. > andi r16,0b01101101 > cpi r16, 0b01101101 > > Beide Stellen müssen übereinstimmen, ... > Das alles ist aufwändig und vor allen Dingen fehleranfällig. > ... frag dich "Was kann ich dagegen tun?" > > Im konkreten Fall ist es leicht, da Abhilfe zu schaffen: > Schreib die Konstante einfach nicht 2-mal hin.
in r16,PINB com r16 ; mach eine '0' aus einer '1' andi r16,0b01101101 ; sieh nach, ob alle interessanten Stellen '0' sind breq nur_einsen |
;-)
Datum:
Bill Geht's? schrieb: > Was zu einem Gutteil an solchen Leuten liegt: :) Ich will hier keine Grundsatzdiskusion starten, aber wie ich hier gerade mitbekommen habe gibt es einen großen Unterschied zw Programmentwicklung auf µC und PC. Wer sollte denn schon Bits/Programmzyklen optimiert arbeiten wenn er ein 1000faches an Speicher / Leistung zur verfügung hat? Außerdem ging es um " übermäßig Resourcen sparende Programme" . Abgesehen davon bedeutet eine lange Lade/Rechendauer noch lange nicht das schlecht entwickelt wurde. Ein Algorithmus zum Sortieren von 1.000.000 Werten dauert nun mal seine Zeit. Wenn parallel noch weitere rechenintensive Prozesse laufen gibt es nunmal ein Nadelöhr. premature optimization is the root of all evil
