Hallo,
ich bastle derzeit an einem Testgerät für Kabelbäume und versuche damit
auch erst mal in die Assemblerprogrammierung rein zu kommen.
Ich habe einen Draht (später eine Ader des Kabelbaums) zwischen PA0 und
PB0. PA0 möchte ich nun auf High schalten und an PB0 wieder einlesen. So
kann ich nach und nach die Ports durchschalten damit ich sichergehen
kann dass die einzelnen Adern auch in der richtigen reihenfolge auf den
Steckern sitzt...
Nur irgendwie schaffe ich es nicht das Programm richtig zu schreiben.
PB0 gegen Masse lässt meine LED (ende:) schon mal leuchten.
Hier nun mein bisheriger Code, der Controller ist ein atmega32.
.include "m32def.inc"
.def temp = r16
taster_lesen: ldi temp,0b11111111
out DDRD,temp
in temp,PIND
cpi temp,0b00010000 ; taster für start
breq start
rcall taster_lesen
rjmp start
start: ldi temp,0b00000000
out DDRA,temp
ldi temp,0b11111111
out DDRB,temp
rjmp check1
check1: ldi temp,0b00000001
out PORTA,temp
in temp,PINB
cpi temp,0b00000001
breq ende
rcall fehler
fehler: ldi temp,0b00100000
out PORTD,temp
rjmp check1
ende: ldi temp,0b01000000
out PORTD,temp
rjmp ende
vielleicht hat ja einer von euch eine Idee,
bedanke mich schonmal!!
MfG
Daniel
Sorry, habe mich oben vertan:
> Nur irgendwie schaffe ich es nicht das Programm richtig zu schreiben.> PB0 gegen Masse lässt meine LED (ende:) schon mal leuchten.
Es ist natürlich PB0 gegen 5V.
Am besten, du schreibst ganz konkret, was nicht so funktioniert, wie
vorgestellt. Dann muss man nicht erst deinen ganzen Code verstehen,
sondern kann gezielt suchen.
.include "m32def.inc"
.def temp = r16
auch wenn du den stack im Moment nicht unbedingt brauchst, solltest du
ihn initialisieren.
taster_lesen: ldi temp,0b11111111
out DDRD,temp
Das ist ja wohl Mist! Das solltest du schon als Eingang schalten, mit
internem pullup, falls nicht extern einer dranhängt.
in temp,PIND
cpi temp,0b00010000 ; taster für start
Ob das so richtig ist, kann dir keiner ohne deine Schaltung sagen, eher
nicht. Besser ist es sowieso, nur auf die entsprechenden einzelnen Pins
zu reagieren, nicht auf den ganzen Port. Also entweder maskieren oder
direkt sbis/sbic verwenden. Irgendwann bastelst du was an den PortD
dran, dann funktionierts so wie du es machst nicht mehr.
breq start
rcall taster_lesen
Das ist ein dicker Hund, rcall ist hier ganz fehl am Platz. Der SP macht
nicht halt am Ende des Rams, sondern überschreibt dir auch den
I/O-Bereich und die Register.
brne taster lesen würde reichen
rjmp start
wozu dieses?
start: ldi temp,0b00000000
out DDRA,temp
ldi temp,0b11111111
out DDRB,temp
rjmp check1
und dieses?
check1: ldi temp,0b00000001
out PORTA,temp
in temp,PINB
cpi temp,0b00000001
das kann bei längeren Leitungen schon zum Problem werden, kleine
Warteschleife einfügen.
breq ende
Und dasselbe Problem wie oben, du setzt stillschweigend voraus, dass die
anderen Pins l-Pegel haben, warum?
rcall fehler
und wieder ein unmotivierter rcall...
fehler: ldi temp,0b00100000
out PORTD,temp
rjmp check1
ende: ldi temp,0b01000000
out PORTD,temp
rjmp ende
Das Ganze ist kein Programm, sondern Murks...:-)
Hast du schon jemals ein funktionierendes Programm für einen AVR
geschrieben? Ich glaube nicht.
Aber lass dich nicht entmutigen, dass wird schon.
Hi Kurty
Am besten ist es, man definiert am Anfang einmal welcher Pin Eingang und
welcher Ausgang wird, und nicht irgendwo nach Lust und Laune im
Programm. Das bleibt übersichtlicher:
ldi temp, 0b11111111
out DDRD, temp
Wichtig: Eingänge werden mit 0 definiert, Ausgänge mit 1
>taster_lesen:> ldi temp,0b11111111> out DDRD,temp> in temp,PIND
Hier definierst du den Port D als Ausgang, versuchst dann aber einen
Schalter einzulesen. Dass das nicht ganz funktionieren kann ist ja klar.
(Pin auf Ausgang + Pin gewaltsam auf ein Potential zeihen...)
> cpi temp, 0b00010000 ; taster für start> breq start
bedenke, dass nur zu "start" gesprungen wird, wenn AUSSCHLIESSLICH PinD,
4 ein ist. Alle anderen Pins müssen Null sein, sonst wird nicht
gesprungen.
Besser wäre für sich wohl SBIS (Skip if Bit in I/O Register Set)
> rcall taster_lesen> rjmp start
Wenn an deinem Pin keine eins anliegt wird das ausgefürht. Dabei
springst du mit dem rcall wieder an den Anfang.
rcall ist eigentlich so gedacht: Man ruft eine Unterroutine auf, und
beendet diese mit ret. Dadurch macht dann der Controller beim nächsten
befehl nach dem rcall weiter. Die Adresse wo er weiter machen muss
speichert er natürlich bevor er zum Unterprogramm springt.
Dein Programm lässt den Controller jetzt wieder an den Anfang springen,
wieder überprüfen ob der Taster gedrückt ist und dann wieder an den
Anfang springen. Das gibt binnen kürzester Zeit probleme im Speicher.
Was mir gerade einfällt: Du hast den Stackpointer garnicht
initialisiert. D.h. dass du sowieso probleme bekommst.
Das beste ist wohl, wenn du dir mal das AVR-Tutorial anschaust. Link ist
oben Links.
>start: ldi temp,0b00000000> out DDRA,temp>> ldi temp,0b11111111> out DDRB,temp>rjmp check1
Zum ein/Ausgänge definieren hab ich ja schon was gesagt. Du hasts halt
wieder falschrum definiert.
>check1: ldi temp,0b00000001> out PORTA,temp>> in temp,PINB> cpi temp,0b00000001> breq ende> rcall fehler
Der Teil sollte soweit funktionieren wie ich denke dass du es wolltest.
>fehler: ldi temp,0b00100000> out PORTD,temp> rjmp check1
Wenn du im Port D einen Pin als Ausgang statt als eingang haben willst,
dann musst du das am anfang so definieren. Also z.B.
ldi temp, 0b10011111
macht alle pins von PortD zu Ausgängen ausser Pin5 und Pin6
>ende: ldi temp,0b01000000> out PORTD,temp> rjmp ende
Wieder das gleiche. Port D richtig definieren.
Ganz nebenbei: Man kann Ausgänge auch einzeln setzten und löschen.
Viel Spass mit dem Tutorial
Sebastian
Also meine ersten Assembleranfänge vor einem Jahr sahen auch so ähnlich
aus und kann ich nen t6963 mit assembler zu steuern, also das wird
schon. Wichtig ist nur das du verstehst, was du codest, d.h. schleife
für schleife durchgehen und verstehen.
Wie ich sehe hast du große Probleme mit den Sprüngen:
1) lerne den unterschied zwischen rcall und rjmp.
Dazu ist es notwenig den stack zu verstehen und die ram adressierung.
Ohne dieses Know how kann man etwas fortgeschrittenere Assemblercodes
nicht verstehen!
2) rcall und rjmp sind nur die befehle zum springen, nicht um an diesen
ort hinzukommen.
beispie
rjmp start
start:
ldi temp,0b00000000 entspricht clr temp
ldi temp,0b11111111 entspricht ser temp
ist völlig für die Katz, der Programmcounter wird nach jedem Command um
eins inkrementiert (+1), wenn es kein sprung ist.
Ganzzz primitiv erklärt:
du sagst dem PC wenn er sich bei rjmp start bei z.b. 1 befindet er soll
zu 2 springen, obwohl er sich ja eh nach dem Befehl um eins
inkrementieren würde.
Ende des liedes: rjmp start kannst du dir hier sparen.
Habe mir jetzt dein Programm nicht weiter angesehen nur so viel:
es empfiehlt sich active low zu schalten.
D.h. standartmäßig den Pin auf 5v halten und sobald der taster gedrückt
ist diesen pin auf gnd zu ziehen (pullup widerstand nicht vergessen, da
du sonst nen kurzen hast).
Außerdem prellen taster gewöhnlich aber dazu gibts genug im Internet zu
lesen :)
Ich kann dir das Buch Mikrocomputertechnik mit Controllern der Atmel
AVR-RISC-Familie ans Herz legen. Wenn du das durchgearbeitet hast (die
35 euro sind wirklich gut investiert) bist du auch für andere controller
gewappnet.
Wenn das wirklich ein Leitungstester werden soll, dann mußt Du auch mit
Kurzschlüssen rechnen.
Also immer nur einen Ausgang auf low und die anderen auf inaktiv
(Eingang), sonst kommt es zu Datenkämpfen (Low gegen High) und das ist
ungesund für den AVR.
Und die Eingänge mit internen oder externen Pullups, damit offen = High.
Peter
P.S.:
Ich hab mal nen Leitungstester für 40-pol. Kabel in C geschrieben mit 3
Stück AT89S8252 um auf die Pinzahl zu kommen. Verbunden sind sie über
die UART.