Hallo, ich versuche mich gerade etwas in Assembler einzuarbeiten.
Als ersten Schritt habe ich versucht ein kleines Programm zu schreiben,
für einen ATmega8 mit 2 Tastern und 2 LEDs angeschlossen. Ziel ist es
einfach nur den ATmega8 dazu zu bringen pro Taster eine LED
einzuschalten.
Das sind meine ersten Gehversuche, ich hoffe ich habe alles richtig
verstanden bisher.
1
#include "avr/io.h"
2
3
#define click R16
4
5
init:
6
SER click
7
OUT DDRC, click ; DDRC mit 0xFF beschreiben: Ausgänge
8
CLR click
9
OUT DDRB, click ; DDRB mit 0x00 beschrieben: Eingänge
10
OUT PORTC, click ; LEDs ausschalten
11
OUT PORTB, click ; und PullUps deaktivieren
12
13
14
loop:
15
IN click, PINB ; die Taster auslesen und
16
OUT PORTD, click ; und auf die LEDs spiegeln
17
RJMP loop ; und nochmal...
Das ganze funktioniert allerdings leider gar nicht. Ich habe mir dann
mal mit objdump das ganze nochmal disassembliert angesehen:
1
00000000 <init>:
2
0: 0f ef ldi r16, 0xFF ; 255
3
2: 04 bf out 0x34, r16 ; 52
4
4: 00 27 eor r16, r16
5
6: 07 bf out 0x37, r16 ; 55
6
8: 05 bf out 0x35, r16 ; 53
7
a: 08 bf out 0x38, r16 ; 56
8
9
0000000c <loop>:
10
c: 06 b7 in r16, 0x36 ; 54
11
e: 02 bf out 0x32, r16 ; 50
12
10: 00 c0 rjmp .+0 ; 0x12 <loop+0x6>
Was micht jetzt sehr wundert ist das der rjmp nach 0x12 geht, und nicht
nach 0xC.
Wäre sehr froh wenn mir eben jemand aufzeigen könnte, wo mein Fehler
ist.
Die Taster hängen mit 10k Ohm als PullDown-Widerstand und
Entprellkondensator an PB0 und PB1. Die LEDs and PC0 und PC1.
Du schaltest die pullups weg, wie sollen da gegen Masse schaltende
Taster funktionieren?
also Zeile out portb,click nach oben schieben, wo click noch ff enthält.
und mit pullups an den Tastern arbeiten.
Peter R. schrieb:> Du schaltest die pullups weg, wie sollen da gegen Masse schaltende> Taster funktionieren?Benedikt W. schrieb:> Die Taster hängen mit 10k Ohm als PullDown-Widerstand
wo steht was von "gegen Masse schaltende Taster"?
Pull downs? Muss das sein?
Maches doch richtig: Interne und/oder externe Pull Ups an den Eingängen,
LED mit Rv an +Ub hängen.
Dann gehts auch.
Ist natürlich nicht verboten, Pull Downs zu benutzen. Aber bitte miss
die Pegel an den Eingängen nach.
Wenn ich ein ähnliches Programm in C schreiben funktioniert die ganze
Sache, also meine Schaltung ist richtig. Allerdings ist mir aufgefallen
das ab einer bestimmten größe der Hex-Datei das überspielen nicht mehr
funktioniert. Entweder ist der Programmer oder der ATmega hinüber.
Außerdem macht er lustige sachen wenn ich ihn berühre. Ich melde mich
nochmal wenn ich Sicher funktionierende Hardware habe...
Benedikt W. schrieb:> Außerdem macht er lustige sachen wenn ich ihn berühre.
Vielleicht weil Du so schön offene Eingänge ohne definierten Pegel hast,
aber abfragst? Mach die Pullups bei den unbenutzen Eingängen wenigstens
an ...
Gruß
Jobst
Stefan E. schrieb:> Das ist vermutlich ungelinkter Code.
An der Stelle muss nichts gelinkt werden. Der muss dort 3
Speicherstellen zurück springen. (Der PC steht bei der Ausführung von
RJMP schon auf der nächsten Stelle) Dort sollte immer -3 stehen!
BTW:
Benedikt W. schrieb:> #include "avr/io.h"
Wozu soll das sein?
Mir fehlt ehr sowas wie
.include "m8def.inc"
DA steht drin, wo sich die Ports befinden.
Worin programmierst Du Deinen Code?
Edit: Musste gerade nochmal die Werte editieren, weil ich den
Schwachsinn aus Deinem Debuger geglaubt habe.
Der gibt vorne nicht die Adresse, sondern die Bytes an. **kopfschüttel*
Gruß
Jobst
Hi
Benedikt W. schrieb:> loop:> IN click, PINB ; die Taster auslesen und> OUT PORTD, click ; und auf die LEDs spiegeln> RJMP loop ; und nochmal...
Nun, Assembler ist genauso funktionstüchtig wie C und vermutlich
funktioniert deine kleine Übung, wenn du auch dem Port C die Taster
zuweist. Und nicht Port D!
Gruß oldmax
OUT DDRC, click ; DDRC mit 0xFF beschreiben: Ausgänge
3
CLR click
Es kommt hier nicht darauf an, in einem Register alle Bits zu setzen,
sondern es soll danach ein Port konfiguriert werden. Okay, hier betrifft
es zuuufällig alle Bits.
Übersichtlicher:
1
.equ config 0b11111111
2
3
ldi click, config
4
OUT DDRC, click ; 'kann weg': DDRC mit 0xFF beschreiben: Ausgänge
5
ldi click, ~config
Jetzt erklärt sich der Quellcode fast von selbst. Außerdem muss zum
Ändern der Konfiguration nur eine Konstante geändert werden.
Jobst M. schrieb:> An der Stelle muss nichts gelinkt werden. Der muss dort 3> Speicherstellen zurück springen. (Der PC steht bei der Ausführung von> RJMP schon auf der nächsten Stelle) Dort sollte immer -3 stehen!
Dass es im konkreten Fall eigentlich nicht nötig wäre, ist irrelevant.
Da der Linker durchaus auch Änderungen am Code vornehmen kann, ist
selbst im Fall eines relativen Sprungs zu einem für den Assembler
sichtbaren Label die Distanz dem Assembler nicht immer eindeutig
bekannt. Warum sollte er also versuchen, eine Fallunterscheidung (kann
Adresse/Distanz selber eintragen oder muss vom Linker gemacht werden) zu
machen, wenn es der einfachere und sichere Weg ist, es immer dem Linker
zu überlassen.
Jobst M. schrieb:> Benedikt W. schrieb:>> #include "avr/io.h">> Wozu soll das sein?
Das ist korrekt so (abgesehen davon, dass <> statt "" angebracht wäre).
Jobst M. schrieb:> Worin programmierst Du Deinen Code?
Steht doch im Titel.
Jobst M. schrieb:> BTW:>> Benedikt W. schrieb:>> #include "avr/io.h">> Wozu soll das sein?> Mir fehlt ehr sowas wie>> .include "m8def.inc">> DA steht drin, wo sich die Ports befinden.
avr/io.h ist eine allgemeine io header-Datei für gcc-avr oder avr-as.
Beim Aufruf von gcc-avr oder avr-as gibt man mit der Option
-mmcu=atmega8
an, aus welcher header-Datei die controller-spezifischen Parameter
gelesen werden.
Oben in der Datei io.h wird beschrieben, wie das funktioniert:
...
This header file includes the apropriate IO definitions for the
device that has been specified by the <tt>-mmcu=</tt> compiler
command-line switch.
...
Ich hab den Fehler gefunden. Wer lesen kann ist klar im Vorteil ;)
Falls es jemanden Interessiert:
AVR-GCC sieht vor bei Schlüsselwörtern wie PORTB oder DDRA nicht die
Port-Adresse, sondern die Adresse im Speicher anzusprechen. Sprich das
funktioniert mit IN/OUT nicht. Um das zum laufen zu bekommen muss man
_SFR_IO_ADDR(Port) verwenden, welches die Portadresse ausspuckt.
Hier der funktionierende Code:
1
#include <avr/io.h>
2
3
#define click R16
4
#define input 0b11111100
5
#define output 0b11111111
6
7
init:
8
LDI click, output
9
OUT _SFR_IO_ADDR(DDRC), click ; Ausgänge
10
LDI click, input
11
OUT _SFR_IO_ADDR(DDRB), click ; Eingänge
12
LDI click, 0x00
13
OUT PORTC, click ; LEDs ausschalten
14
OUT PORTB, click ; und PullUps deaktivieren
15
16
17
loop:
18
IN click, _SFR_IO_ADDR(PINB) ; die Taster auslesen und
19
OUT _SFR_IO_ADDR(PORTC), click ; und auf die LEDs spiegeln
20
RJMP loop ; und nochmal...
Falls es noch jemanden interessiert wie ich das in die ihex-Form
gebracht habe:
Ich hab mir da ein mini-Shellscript geschrieben.
Danach hat man (wenn alles geklappt hat) eine flash.hex die man dem
avrdude füttern kann.
-----
Alternativ könnte man Das programm auch ohne _SFR_IO_ADDR schreiben, was
dann so aussehen würde:
Benedikt W. schrieb:> AVR-GCC sieht vor bei Schlüsselwörtern wie PORTB oder DDRA nicht die> Port-Adresse, sondern die Adresse im Speicher anzusprechen.
Dazu noch eine Bemerkung: Wie Du richtig schreibst, ist es wichtig
das hier der avr-gcc bzw. indirekt der (gnu) avr-as verwendet wird.
Mit dem Atmel Assembler oder auch avra kann man die Befehle
"in" und "out" in der "loop" verwenden.
Z.B. (nicht von mir)
1
; Atmel Assembler oder avra!
2
; Port C: Ausgabe PC7 .. PC0 acht LEDs über 150R an 5 V
3
; Port B: Eingabe PB7 .. PB0 acht Taster gedrückt an Masse
4
; Beschaltung LEDs und Taster z.B. wie Atmel STK500