Forum: Mikrocontroller und Digitale Elektronik AVR: High Pin einlesen


von Kurty (Gast)


Lesenswert?

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

von Daniel K. (kurty)


Lesenswert?

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.

von Winfried (Gast)


Lesenswert?

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.

von crazy horse (Gast)


Lesenswert?

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

von Sebastian (Gast)


Lesenswert?

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

von Hansi L. (fabian87)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

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.