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:
1
//Ausgang im PORTB,7 auf "1" setzen wenn Alle Eingänge (0,2,3,5,6) auf "1"
2
in r16,PINB
3
ldi r17,0b01101101
4
and r16,r17
5
CP r16,r17
6
BREQ _B7_AN
7
8
//Ausgang im PORTB,7 auf "0" setzen wenn Mindestens 1 Eingang (0,2,3,5,6) auf "0"
9
rjmp _B7_AUS
10
11
//Rücksprungmarke
12
_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
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
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... ;-)
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
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...
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.
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
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
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.
1
andi r16,0b01101101
2
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?
1
.equ ALL_KEY_INPUTS = 0b01101101
2
3
....
4
5
andi r16, ALL_KEY_INPUTS
6
cpi r16, ALL_KEY_INPUTS
7
...
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
1
....
2
3
andi r16, ALL_KEY_INPUTS ; überprüfen ob irgendeiner auf 0 gegangen ist
4
cpi r16, ALL_KEY_INPUTS
5
...
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.
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.
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.
1
in r16,PINB
2
com r16 ; mach eine '0' aus einer '1'
3
andi r16,0b01101101 ; sieh nach, ob alle interessanten Stellen '0' sind
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