Hallo an alle,
erstmal nachträglich noch ein schönes Weihnachtsfest, auch wenn es
mittlerweile schon fast vorbei ist ;-)
Nun zu meiner Frage: Ich habe mir gerade das AVR Tutorial-Tasten
(Entprellung) vorgenommen und diesen Code in meinem Atmega 8 geflasht:
.include "m8def.inc" ; Definitionsdatei
.def temp1 = r17
.def temp2 = r18
ldi temp1, $00 ; 0xFF ins Arbeitsregister schreiben
out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
ldi temp1, $00 ; $00 ins Arbeitsregister schreiben
out DDRD, temp1 ; r16 ins IO-Register PortB ausgeben
ldi temp1, $FF ; Pullup Widerstäde aktivieren
out PORTD, temp1
mov r3, temp1 ; temp1=$FF, d.h. keine Taste gedrückt
loop:
in r4, PIND ; den jetzigen Zustand der Taster holen
mov temp1, r4 ; und in temp1 sichern
eor r4, r3 ; mit dem vorhergehenden Zustand XOR
mov r3, temp1 ; den jetzigen Zustand für den nächsten
; Schleifendurchlauf als alten Zustand merken
breq loop ; Das Ergebnis XOR auswerten:
; Wenn keine Taste gedrückt war -> neue Schleife
and temp1, r4 ; war das ein 1->0 Übergang, wurde der Taster
; also gedrückt (in key_now steht das Ergebnis
; vom XOR)
brne loop
ldi temp1, $FF
wait1: ; Warten...
dec temp1
brne wait1
in temp1, PIND ; ...und nachsehen, ob Taste immer noch gedrückt
ist
and temp1, r4
brne loop ; wenn Taste nicht mehr gedrückt -> neue Scheife
in temp1, PORTB ; wenn Taste immer noch gedrückt ->
com temp1 ; den Zustand der LED umdrehen
out PORTB, temp1
rjmp loop
Die Entprellung funktioniert zwar reibungslos, was mir auffällt ist
aber, dass die angeschlossene LED relativ schwach brennt. Ich habe am
Port 1,8V gegen Vcc gemessen. Das sollten aber doch 5V sein, oder? (wenn
ich die LED direkt an GND anschliesse, dann brennt sie mit 'normaler'
Helligkeit.
board: Experimentierboard nach Roland Walter
mC: Atmega8 interner Takt
Betr.-spannung: 5,0V (stab.)
Kann mir da jemand einen Tipp geben?
Vielen Dank
1/ Kannst du mal diese Zeile kontrollieren, die ist fischig:
> in temp1, PORTB ; wenn Taste immer noch gedrückt ->
2/ Wie hast du die LED anegschlossen (einfaches Schaltbild reicht)?
Das du nur 1.8V über der LEd hast find ich ganz okey. Die
durchlassspannung dieser LED lioegt einfach bei 1.8 V. Wie bei Dioden
0.7V.
Ich denke der Restliche Spannnungsabfall wird sich über den internen
Widerständen (Transistoren) finden lassen.
Hoffe ich liege da nicht ganz falsch. Bin mir aber doch ziemlich sicher.
Hallo stefb,
> 1/ Kannst du mal diese Zeile kontrollieren, die ist fischig:
brne loop ; wenn Taste nicht mehr gedrückt -> neue Scheife
in temp1, PORTB ; wenn Taste immer noch gedrückt ->
com temp1 ; den Zustand der LED umdrehen
out PORTB, temp1
-Nachdem der Tastendruck erkannt wurde, wird in temp1 der aktuelle
Zustand der LED (PORTB) geschrieben (an oder aus)
-com invertiert dann die bits von temp1 (an->aus bzw aus->an)
-und anschl. invertierte Ausgabe (temp1->PORTB)
> 2/ Wie hast du die LED anegschlossen (einfaches Schaltbild reicht)?
Auf dem board sind 3 LEDs, die mit ihrer Kathode an GND hängen. An den
Anoden ist jeweils ein Widerstand 1,2k angeschlossen. Der PortPin Pb7
ist dann mit einer LED verbunden.
Axel Hüser wrote:
> Die Entprellung funktioniert zwar reibungslos, was mir auffällt ist> aber, dass die angeschlossene LED relativ schwach brennt. Ich habe am> Port 1,8V gegen Vcc gemessen. Das sollten aber doch 5V sein, oder? (wenn> ich die LED direkt an GND anschliesse, dann brennt sie mit 'normaler'> Helligkeit.
Wenn das bedeutet, das du die LEDs testweise ohne Vorwiderstand
betrieben hast, würde daß die schwache Lichtausbeute erklären: die LEDs
sind defekt.
LEDs niemals ohne Vorwiderstand betreiben. Auch nicht testweise...
Hallo an alle,
sorry hab' falsch geschriebenRichtig ist: (wenn
ich die LED direkt an Vcc anschliesse, dann brennt sie mit 'normaler'
Helligkeit). Ich habe die LED also mit Widerstand getestet - LEDs sind
OK
> Das du nur 1.8V über der LEd hast find ich ganz okey.
Wenn ich aber diesen Code flashe (LED leuchtet solange Taste
gedrückt-ohne Entprellung):
...
ldi r16, 0b00000000 ; alle LEDs aus
out PORTB, r16
loop:
in r16, PIND ; Zustand der Tasten ins Register r16 laden
com r16 ; alle Bits umkehren
out PORTB, r16 ; r16 ins IO-Register PortB ausgeben
rjmp loop ; Endlosschleife
...dann leuchtet die LED hell. Hier wird die LED doch auch über den
PORTB angesteuert!
Dann ist alles klar. Deine LED leuchtet mit dem ersten Code nicht
schwach, sondern sie blinkt! Und zwar mit einer sehr hohen Frequenz.
Vermutlich hast du einfach nur einen logischen Fehler im Code...
Warum liest Du eigentlich die Tutorial-Seite nicht zu Ende und benutzt
die clevere Lösung von PeDa? Gut, etwas schwer zu verstehen, aber
unschlagbar ressourcenschonend.
...
Hallo hannes,
> Warum liest Du eigentlich die Tutorial-Seite nicht zu Ende und benutzt> die clevere Lösung von PeDa? Gut, etwas schwer zu verstehen, aber> unschlagbar ressourcenschonend.
ich hab schon zu Ende gelesen. Ich will's mir auch anschliessend
vornehmen. Aber da ich gerade erst mit Assembler angefangen habe, will
ich erst mal etwas Syntax und Code der Reihe nach lernen, und nicht wie
mit meinem LCD den 3. Schritt vor dem 2. machen. Also nur Code kopieren,
aber nicht wissen warum's dann funktioniert, war nicht mein Ziel.
Aber trotzdem Danke für den Tip! Ich hab mir auch schon eine zusätzliche
Platine mit 8 Tastern und 8 LEDs gebaut, um den Code von PeDa
auszuprobieren.
Von PeDa gibt es auch einen cleveren Code für nur einen Taster. Er nutzt
nur 4 Bit eines Registers und ist hocheffizient. Er wird auch zyklisch
aufgerufen (am besten im Timer-Int. oder vom Timer synchronisiert). Hier
http://www.mikrocontroller.net/forum/read-1-140056.html#140946 wird
darüber diskutiert.
...
Hallo an alle,
ich hab den Fehler nun selbst gefunden :-)...nach langem Suchen und
Vergleichen mit anderen Codes.
falsch:
ldi temp1, $00 ; 0xFF ins Arbeitsregister schreiben
out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
richtig:
ldi temp1, 0xFF ; 0xFF ins Arbeitsregister schreiben
out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
Ich hab fälschlicherweise das DDRB als Eingang ($00) anstatt als Ausgang
(0xFF) deklariert. (aber Kommentierung war richtig)
Der Grund war, weil im Tutorial der Befehl steht:
.equ LED = 0
...
ldi temp1, 1<<LED
Da mir das '1<<LED' nicht klar war, was es exakt bedeutet, habe ich es
durch $00 (.equ LED = 0) ersetzt.
Also jetzt klappt's.
Danke an alle!
Axel Hüser wrote:
> falsch:> ldi temp1, $00 ; 0xFF ins Arbeitsregister schreiben> out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
Das ist das was ich mit "lesbarkeit des Quellcodes" meine. In C fallen
solche Flüchtigkeitsfehler einfach schneller auf.
Axel Hüser wrote:
> Hallo an alle,>> ich hab den Fehler nun selbst gefunden :-)...nach langem Suchen und> Vergleichen mit anderen Codes.>> falsch:> ldi temp1, $00 ; 0xFF ins Arbeitsregister schreiben> out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
Ja, falsch...
>> richtig:> ldi temp1, 0xFF ; 0xFF ins Arbeitsregister schreiben> out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
Nööö, immernoch falsch...
>> Ich hab fälschlicherweise das DDRB als Eingang ($00) anstatt als Ausgang> (0xFF) deklariert. (aber Kommentierung war richtig)
Du wolltest doch aber eigentlich nicht den ganzen Port als Ausgang
schalten, sondern nur den LED-Pin, oder???
>> Der Grund war, weil im Tutorial der Befehl steht:> .equ LED = 0> ...> ldi temp1, 1<<LED
Das bedeutet, dass Du nur das Bit mit dem Namen "LED" (und dem Bitwert
0) setzen (auf 1 setzen) willst und alle anderen Bits auf 0. Der
Zahlenwert in temp1 wäre demnach 1 ($01, 01h, 0x01, 0b00000001). hätte
"LED" den Bitwert 3, dann wäre der Wert in temp1 8.
>> Da mir das '1<<LED' nicht klar war, was es exakt bedeutet, habe ich es> durch $00 (.equ LED = 0) ersetzt.
Das war falsch. Stattdessen solltest Du Dich informieren, wie mit man
beim Namen genannten Bits umgeht. Dieses Wissen brauchst Du nicht nur in
Assembler, sondern auch in C.
>> Also jetzt klappt's.
Nein, es klappt nicht, es sieht nur so aus. Du hast nämlich Ports als
Ausgang konfiguriert, die Du gar nicht als Ausgang wolltest. Dass
dadurch kein Schaden entsteht, ist reiner Zufall.
>>> Danke an alle!
Nix zu danken
...
Hallo hannes,
du hast mir wirklich sehr geholfen! Ich habe meinen Code jetzt so
abgeändert:
...
.equ LED = 0 ; Das bit0 hat den Namen 'LED'
ldi temp1, 1<<LED ; Das bit0 wird 1 gesetzt, alle anderen 0
; und ins Arbeitsregister temp1 geschrieben
out DDRB, temp1 ; bit0 auf Ausgang
ldi temp1, $00 ; $00 ins Arbeitsregister schreiben
out DDRD, temp1 ; r16 ins IO-Register PortB ausgeben
; PORTD ist Eingang
...
Mit dem Taster verändere ich jetzt nur noch die LED am PB0 und nicht
mehr alle (PB1-PB7).
Hätte ich den Code aus dem Tutorial nur kopiert, hätte es zwar sofort
funktioniert. Jetzt weis ich aber, was es mit '<<' schieben auf sich hat
und was ich falsch gemacht habe.
Ist Kommentierung so OK?
hannes Danke nochmal.
Axel Hüser wrote:
> Ist Kommentierung so OK?
Nö. Zum Anfangen ist es noch ganz ok, alles etwas mehr zu kommentieren,
aber insbesondere Kommentare wie "out DDRD, temp1 ; r16 ins
IO-Register PortB ausgeben" sind nicht ganz ungefährlich. Vielleicht
kommst du mal auf die Idee, temp1 auf r17 zu legen, dann sagt der
Kommentar etwas anderes als dein Programm. Zeilen wie
1
ldi temp1, 1<<LED
2
out DDRB, temp1
3
4
ldi temp1, $00
5
out DDRD, temp1
braucht man eigentlich überhaupt nicht zu kommentieren, das ist einfach
selbsterklärend. Daher auch die benannten Bits, das vermeidet redundante
Informationen.
Die Namen für die Register, I/O-Register und Bits haben ja den Sinn,
dass man sich nicht mehr darum kümmern muss, welches Register (Nummer)
oder welches Bit (Nummer) man eigentlich meint. In den Kommentaren hat
daher die Nummer des Registers oder Bits nichts zu suchen. Wenn bei den
Deklarationen (.equ, .def) die Namen vergeben werden bzw. Portbits
verteilt werden, dann spricht man sie konsequenterweise im gesamten
Programm mit diesen Namen an. Das ermöglicht das Verändern der
Pinzuweisungen in den Deklarationen, ohne im Programm auch nur eine
Zeile ändern zu müssen.
Dabei kann es durchaus vorkommen, dass ein Port mehrere Namen bekommt,
weil an seinen Bits unterschiedliche Dinge angeschlossen sind. Je
nachdem, welches Teil man ansprechen will, wird der entsprechende Name
benutzt. Liegt z.B. an PortD Bit0 (PD0) eine LED, so bekommt PortD
zusätzlich den Namen LED_Port und PD0 den Namen LED_Bit. Will ich die
LED einschalten, schreibe ich im Programm sbi LED_Port,LED_Bit. Will ich
sie ausschalten, dann cbi statt sbi.
Du sagst, das Schieben mit << hast Du verstanden. Trotzdem solltest Du
nochmal den Unterschied zwischen Bitmaske (0..255) und Bitnummer (0..7)
ergründen, dazu solltest Du Dir die Beschreibung einiger Befehle
ansehen, die mit Konstanten oder Bitnummern arbeiten. Ergründe mal den
Unterschied der Bit-Auswahl zwischen ldi (andi, ori, sbr, cbr, ...) und
sbrs (sbrc). Das Eine braucht die Bitmaske, das andere die Bitnummer. Um
nun das Bit mit demselben Namen ansprechen zu können, wird es bei
benötigter Bitnummer direkt angegeben, bei benötigter Bitmaske als
Exponent zur Basis 2 benutzt, was dem Linksschieben einer Eins um n
(Bitnummer) Stellen entspricht. Aus den Bitnummern 0, 1, 2, 3, 4, 5, 6
und 7 werden dadurch die Bitmasken mit den Werten 1, 2, 4, 8, 16, 32, 64
und 128.
Schau Dir auch mal den Unterschied zwischen den (ähnlich klingenden)
Befehlen sbr/cbr und sbi/cbi an, das ist nämlich auch ein bekannter
Stolperstein für Anfänger.
...
Philipp Burch wrote:
> Axel Hüser wrote:>> Ist Kommentierung so OK?>> Nö. Zum Anfangen ist es noch ganz ok, alles etwas mehr zu kommentieren,> aber insbesondere Kommentare wie "out DDRD, temp1 ; r16 ins> IO-Register PortB ausgeben" sind nicht ganz ungefährlich. Vielleicht> kommst du mal auf die Idee, temp1 auf r17 zu legen, dann sagt der> Kommentar etwas anderes als dein Programm.
@Axel
Wie wahr, wie wahr
:-) :-)
1
out DDRD, temp1 ; r16 ins IO-Register PortB ausgeben
Fällt dir was auf? DDRD - PortB
Wenn ich noch meinen Senf dazu geben darf:
Kommentiere nicht was im Source Code sowieso schon dortsteht.
Nur so als Beispiel:
Aus deinem korrigierten Programm
1
ldi temp1, 0xFF ; 0xFF ins Arbeitsregister schreiben
2
out DDRB, temp1 ; Datenrichtungsregister auf Ausgang
Was erzählt mir der Kommentar, was nicht auch schon im Source
Code steht? Gar nichts!
Im Kommentar steht, dass du 0xFF ins Arbeitsregister schreibst.
Dassselbe steht auch im Source Code: ldi temp1, 0xFF
OK 'Datenrichtungsregister auf Ausgang' enthält ein Fitzelchen
Information, dass nicht so offensichtlich im Source Code steht.
Dazu muss man wissen, dass eine 1 einen Pin auf Ausgang schaltet.
Aber so wirklich weltbewegend Neues enthält der Kommentar nicht
wirklich.
Erzähl mir (dir, deinem Leser) in einem Kommentar nicht, was er
durch Lesen des Source Codes erfahren kann. Erzähl im lieber die
Dinge, die nicht im Source Code stehen. Sehr oft sind das die
Dinge, die sich auf die Frage: Warum? ergeben.
Also: Warum schaltest du den Port B auf Ausgang.
Antwort: Weil dort die Led hängen.
Das solltest du zb. kommentieren.
Hallo Karlheinz,
> Kommentiere nicht was im Source Code sowieso schon dortsteht.
Werde ich beherzigen. Als Anfänger war es für mich aber hilfreich. Aber
auch mehr Sorgfalt ist bei meiner Kommentierung noch nötig ;-)
hannes,
danke für die ausführlichen Hinweise und Erklärungen (und verwendete
Zeit) mit Bitmaske und Bitnummer.
Axel
> Kommentiere nicht was im Source Code sowieso schon dortsteht.
Es kommt auf die Situation an. Also darauf, für wen der Quelltext
geschrieben worden ist. Ist er für einen Anfänger als Hilfe zur
Selbsthilfe, dann finden sich auch in meinen Kommentaren
Befehlsbeschreibungen oder Hinweise auf das Datenblatt (Seitenzahl in
eckigen Klammern). Ist der Quelltext für Jemanden, der sich nicht mit
ASM auseinandersetzen will und der das Programm nur benutzen will, dann
enthalten meine Kommentare solche Erklärungen nicht.
...