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