Hallo
bin beim Einarbeiten. Folgendes kl. Programm wundert mich.
Es soll mit Taster (PB2) eine Led (PB1) ausgeschaltet werden, solange
der Taster gedrückt ist.
Wird der Taster gerückt wird die LED aber heller obwohl der PortB1 doch
gelöscht wird.
Wo mache ich etwas falsch?
.include "tn13def.inc"
Start:
sbi DDRB,0b00000001 ;PortB1 soll Ausgang sein, Rest ist als Eingang
konfig.
sbi PortB,1 ;PortB1 wird gesetzt
sbi PortB,2 ;Pullup einschalten, hier ist der Taster dran
sbic PinB,2 ;überspringe nächsten Befehl, wenn Taster gedückt
ist.
cbi PortB,1 ;PortB,1 ausschalten
rjmp Start
Es handelt sich um keine Schulaufgabe und ist nur von privaten
Interesse.
Mit freundlichen Grüßen
Fred.
Fred schrieb:> Folgendes kl. Programm wundert mich.
Dann laß es dochmal im Simulator laufen.
Allgemein hat ein Programm ein Init, was nur einmal durchlaufen wird und
danach folgt die Mainloop.
Fred schrieb:> sbi DDRB,0b00000001 ;PortB1 soll Ausgang sein, Rest ist als Eingang> konfig.
Tu dir selbst einen Gefallen.
sbi will die Nummer des Bits haben, das es setzen soll.
Es gibt keinen Grund da Binärzahlen anzugeben. Wenn du das Bit 1 im DDRB
gesetzt haben willst, dann schreib ganz einfach
1
sbi DDRB, 1
An dieser Stelle ist eine Deziamlschreibweise das einfachste. Willst du
das Bit 5 auf 1 haben, dann eben
1
sbi DDRB, 5
Da muss man nicht mit Binärzahlen künsteln. Deine Freundin wird auch so
beeindruckt sein, ohne dass du maximale Komplexität mit Binärzahlen an
allen möglichen unangebrachten Stellen vortäuscht.
Deine grundsätzliche Programm-Idee ist zwar recht naheliegenden, aber
sie äussert sich genau so wie du das siehst.
Wenn du die LED ausschalten willst, dann musst du sie auch wirklich
ausschalten. Eine LED zuvor dauernd einzuschalten und gleich wieder
auszuschalten weil ein Taster gedrückt ist, ist eben nicht dasselbe. Der
Portpin wechselt, so wie du das programmiert hast dadurch ja ständig
zwischen 0 und 1. Das geht so schnell, dass du das Blinken nicht als
Blinken siehst, sonder als halbhell leuchtende LED. Lässt du das
ausschalten dann weg, dann brennt die LED natüclich mit voller Kraft.
Was du programmiert hast, ist
1
+--------->
2
| LED einschalten
3
| wenn Taste gedrückt
4
| dann LED ausschalten
5
| |
6
+----------+
und das schaltet die LED eben nicht komplett aus, weil sie ja am Beginn
der Schleife erst mal eingeschaltet wird.
Was du zum Beispiel programmieren müsstest, ist
1
+--------->
2
| wenn Taste nicht gedrückt
3
| dann LED einschalten
4
| wenn Taste gedrückt
5
| dann LED ausschalten
6
| |
7
+----------+
Das sorgt dafür, dass die LED entweder ein oder aus geschaltet wird, je
nach Tasterstellung. Aber nicht in einem Durchlauf durch die Schleife
beides. Das ist ein entweder oder. Weil ja die Taste auch entweder
gedrückt oder nicht gedrückt sein kann. Aber immer nur eines von beiden
und nicht erst mal einschalten und dann bei Bedarf ausschalten. Auf die
Art ist die LED nie komplett aus.
Hallo ,
recht herzlichen Dank für die sehr ausführliche und bisher in keinem
anderen TUT gelesenen Erläuterungen.
mein 2.Versuch:
sbi DDRB,1 ; Led
Sbi PORTB,2 ; Taster- Pullup
Start:
sbic PinB,2 ; springe wenn Taster gedrückt zu "cbi...."
rjmp aus
cbi PortB,1 ; Led ist an
rjmp Start
aus: ; wenn Taster nicht gedrückt, Led aus
sbi PortB,1
rjmp Schleife
Ich habe es am lebenden Objekt getestet, es geht tatsächlich die Led
aus!
Es geht aber nicht ohne Unterprogramm.
Ich halte die Lösung nicht für sonderich elegant.
Wäre es vl. besser Register mit entsprechendem Muster zu laden und diese
dann aufzurufen?
Vl. Grüße und nochmals vl. Dank Fred.
Fred schrieb:> Es geht aber nicht ohne Unterprogramm.
Na ja. Ein Unterprogramm ist schon noch was anderes. Nur weil du da ein
paar Sprünge drinn hast, hast du noch lange kein Unterprogramm.
> Ich halte die Lösung nicht für sonderich elegant.> Wäre es vl. besser Register mit entsprechendem Muster zu laden und diese> dann aufzurufen?
Besser wäre es, seinen Befehlssatz zu kennen.
So wie es ein SBIC als Befehl gibt, gibt es auch ein SBIS als Befehl.
SBIC 'Skip if Bit is Clear'
SBIS 'Skip if Bit is Set'
und damit sind die beiden Operationen 'Wenn Taste gedrückt' bzw. 'Wenn
Taste nicht gedrückt' ja trivial umzusetzen. Und da die eigentliche
Oepration, die eine LED zu schalten, lediglich 1 Befehl lang ist,
braucht man auch nicht mit einem RJMP durch die Gegend springen, sondern
es reicht die jeweilige Schaltoperation einfach durch den Skip
überspringen zu lassen. Das einemal 'wenn gedrückt', das andere mal
'wenn nicht gedrückt'
1
Loop:
2
sbic PINB, 2
3
sbi PORTB, 1
4
sbis PINB, 2
5
cbi PORTB, 1
6
7
rjmp Loop
Sobald mehrere Operationen abhängig vom Zustand des Pins am PINB
abhängig sind, muss man dann allerdings mit einem RJMP aus der normalen
linearen Abarbeitung ausbrechen und den zugehörigen Code anspringen, so
wie du das gemacht hast. Hier allerdings geht es noch ohne.
Fred schrieb:> Es geht aber nicht ohne Unterprogramm.
Ein Unterprogramm hast du auch nicht! Das sind nur wilde Sprünge.
Schreibe dir mal Schritt für Schritt auf, was du machen willst. Dann
siehst du, dass es da es auch einfacher geht. (in dieser Beschreibung
kommt sicher nicht 'springe zu aus' vor ;-) )
Fred schrieb:> Ich halte die Lösung nicht für sonderich elegant.
Die Lösung ist schon elegant, da sie funktional richtig ist und keine
Nebeneffekte hat.
Karl Heinz schrieb:> Loop:> sbic PINB, 2> sbi PORTB, 1> sbis PINB, 2> cbi PORTB, 1>> rjmp Loop
Sparlösungen haben oft Einschränkungen.
Z.B. darf die Aktion nur einen Befehl lang sein.
Und wenn ein Eingang 2-mal abgefragt wird, dann muß man prüfen, ob eine
Änderung dazwischen keine unerwünschten Resultate liefert.
Bei Assembler muß man sich damit abfinden, daß man einen beträchtlichen
Overhead hat. Will man das nicht, muß man eine Hochsprache verwenden (C
ist sehr weit verbreitet).