Forum: Mikrocontroller und Digitale Elektronik ATTiny13 soll gedrückten Schalter abfragen


von Fred (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Fred (Gast)


Lesenswert?

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.

von Fred (Gast)


Lesenswert?

sorry, (Alzheimer)das letzte Sprungziel muss auch "Schleife" heißen.

von Fred (Gast)


Lesenswert?

Fred schrieb:
> sorry, (Alzheimer)das letzte Sprungziel muss auch "Start"
> heißen.

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Ralf G. (ralg)


Lesenswert?

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 ;-) )

von Peter D. (peda)


Lesenswert?

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).

von Ralf G. (ralg)


Lesenswert?

Peter Dannegger schrieb:
> Sparlösungen haben oft Einschränkungen.
> Z.B. darf die Aktion nur einen Befehl lang sein.
... *)
1
Loop:
2
   sbic PINB, 2
3
   rcall up_an
4
   sbis PINB, 2
5
   rcall up_aus
6
   rjmp Loop
7
8
up_an:
9
   sbi  PORTB, 1
10
; viiieeel Code
11
   ret
12
up_aus:
13
   cbi  PORTB, 1
14
; noch mehr Code
15
   ret

*) macht doch nichts ;-)

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
Noch kein Account? Hier anmelden.