www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage ATmega8 I/O Verständnisproblem


Autor: Patrick Berninghaus (patricck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,
Bin seid heute neu hier und hoffe ich hab den richtigen Forumsteil 
erwischt =).
Ich beschäftige mich erst ein paar tage mit Microcontrollern und habe 
mir zu Lernzwecken das "my AVR Lehrbuch" mit dazugehörigen blauen koffer 
gekauft.
Vorkenntnisse hab ich in assembler leider nicht, programmiere sonst nur 
SPS und das meistens im kop.

Ich beschäftige mich nun seid 2 abenden mit dem selben Programmteil. Es 
geht darum mit 2 tastern 2 leds zum leuchten zu bringen.
(taster 1-> led1 , taster 2 ->led2).

Wäre super nett wenn sich das mal einer von euch anschauen könnte, das 
ich Verständnisprobleme mit der zuweisung der pinbelegungen hab.

main:    ldi    r16,hi8(RAMEND)
      out    SPH,r16
      ldi    r16,lo8(RAMEND)
      out    SPL,r16
      cbi DDRB , 0
      sbi PORTB , 0
      sbi DDRD ,1
      ldi    r18,hi8(RAMEND)
      out    SPH,r18
      ldi    r18,lo8(RAMEND)
      out    SPL,r18
      cbi DDRB ,0
      sbi PORTB ,0
      sbi DDRB , 1
;----------------------------------------------------------------------- 
-------
mainloop:  wdr
      ldi r16,0x01 ;    1 okay
      in r17 ,PINB
      sbrs r17 , 0
      ldi r16 , 0x03;    3?? wieso muss(!) hier eine 3 stehen?
      out PORTB , r16
      ldi r16 ,0x01



      ldi r18,0b00000100
      in r19 ,PINB
      sbrs r19 , 0
      ldi r18,0b00001100
      out PORTB , r18
      ldi r18  ,0b00000100

      rjmp  mainloop
;----------------------------------------------------------------------- 
-----

Meine Frage, was ist eigentlich r16? kann ich das als interne Adresse 
betrachten oder ist es eine feste zuweisung? Wie kann man weitere 
logische ausgange festlegen und benutzen?

Hab schon diverse Veränderungen an den zuweisungen (zb 0b00000100) 
vorgenommen, aber keine hat mich leider zum erfolg geführt.

Es wäre sehr nett wenn mir da vielleicht jemand kurz helfen würde!
Danke schonmal im vorraus!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick Berninghaus schrieb:

> main:    ldi    r16,hi8(RAMEND)
>       out    SPH,r16
>       ldi    r16,lo8(RAMEND)
>       out    SPL,r16
>       cbi DDRB , 0
>       sbi PORTB , 0
>       sbi DDRD ,1


>       ldi    r18,hi8(RAMEND)
>       out    SPH,r18
>       ldi    r18,lo8(RAMEND)
>       out    SPL,r18
>       cbi DDRB ,0
>       sbi PORTB ,0
>       sbi DDRB , 1

Warum doppelt?
Der zweite Abschnitt ist komplett identisch mit dem ersten.

> ;----------------------------------------------------------------------- -------
> mainloop:  wdr
>       ldi r16,0x01 ;    1 okay
>       in r17 ,PINB
>       sbrs r17 , 0
>       ldi r16 , 0x03;    3?? wieso muss(!) hier eine 3 stehen?

Weil das Bitmuster für 0x03 dieses hier ist
    0000 0011

und höchst wahrscheinlich hängt an deinem Port an den beiden Pins 
irgendwas dran (zb 2 LED) die auf diese 1 Bits reagieren.


> Meine Frage, was ist eigentlich r16?

Ein sog. 'Register'

> kann ich das als interne Adresse
> betrachten oder ist es eine feste zuweisung?

Das kannst du dir wie eine Speicherzelle vorstellen, die in die CPU 
eingebaut ist und die von diversen Befehlen benutzt werden kann.

So ähnlich, wie auch die billigen Taschenrechner immer so eine 'M' Taste 
haben. Man kann dann auf dieses M-Register etwas addieren, subtrahieren 
und wieder ausgeben lassen.
Nur dass dein AVR
  mehr von diesen Registern hat
  viel mehr Operationen damit machen kann.


Also ein Register ist einfach nur eine Speicherzelle im innersten Kern 
deines µC, der zum Speichern von Werten benutzt werden kann und wo es 
Operationen gibt, die mit diesen Registern etwas tun können. Auch wenn 
es nicht ganz korrekt ist, kann man aber doch sagen: Ein Wert muss aus 
dem normalen Speicher zunächst einmal in ein Register geladen werden, 
damit man ihn manipulieren kann.

> Es wäre sehr nett wenn mir da vielleicht jemand kurz helfen würde!

Hast du dir das
AVR-Tutorial
schon angesehen?
Das sollte eigentlich eine ganz gute Ergänzung zu deinen Lehrunterlagen 
sein.

Autor: Patrick Berninghaus (patricck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
erstmal danke für die schnelle Antwort!

Ja das Tutorial hab ich mir angesehn werd da aber leider nicht wirklich 
schlau draus, da so gut wie alles für mich da neu ist :P der Vorsprung 
den ich mir durch die SPS programmierung versprochen hab ist doch 
seeeehr minimal.

Aber das mit dem register hab ich jetzt glaub ich verstanden.
Aber ich muss doch trotzdem wenn ich von Port B den Pin 2 als eingang 
belegen will sagen, dass er einen pull down haben muss und das er ein 
eingang ist... warum ist das dann oben doppelt? wie wäre es denn 
richtig?

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Der zweite Abschnitt ist komplett identisch mit dem ersten.

die letzte zeile ist anders...

Autor: Ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt fängst du am besten nochmal ganz von vorn an.
Die Stackpointer-Initialisierung brauchst du überhaupt nicht.
Den Watchdog genauso wenig.

Du hast 32 Register (kleine Speicher für 8bit).

ldi r16, 0b00000011 ; Die Zahl 3 ins Register r16
out DDRB, r16 ; Hier schaltest du von Port B die untersten beiden Bits 
auf Ausgang
out PORTB, r16 ; Jetzt schaltest du die zwei Ausgänge ein.

Verstanden?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Die Stackpointer-Initialisierung brauchst du überhaupt nicht.

Über diese Brücke würde ich nicht gehen.

MfG Spess

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Etwas Assembler zu lernen ist sicherlich der beste Weg für die Zukunft, 
da man internes Verständnis erlangt und später beim debuggen sich mal 
das zugehörige Assemblerlisting anschauen kann (was manchmal wirklich 
sehr hilfreich ist). Auf weitere Sicht solltest Du aber unbedingt mit C 
als Hochsprache "anbändeln", das ist bei etwas größeren Programmen der 
reine Segen! Ich habe damals hiermit angefangen 
http://www.avr-asm-tutorial.net/avr_de/index.html , war super und 
entsprach voll meiner damaligen Vorstellung => Kontrolle über jeden 
einzelnen Takt, was passiert wie wo etc.. Als dann aber irgendwann das 
Thema "Rechnen mit Assembler" drankam, habe ich mit Assembler aufgehört. 
Aber das Basiswissen ist Gold wert!
Mit C geht es später dann hier los: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
Ist natürlich meine ganz persönliche Meinung.

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
>>Die Stackpointer-Initialisierung brauchst du überhaupt nicht.
>
> Über diese Brücke würde ich nicht gehen.
>
> MfG Spess

Bei seinem Programm braucht er den Stack wohl nicht. Wichtig ist aber zu 
wissen, was es alles mit dem Stack so auf sich hat und was mann alles 
berücksichtigen muß. Und das man ihn beim überübernächsten Programm dann 
auch zwingend benötigen wird. Als guten Programmierstil kann man es 
daher aber schon ansehen, ihn immer zu initialisieren. Und sei es, 
weil ein Programm irgendwann erweitert wird ...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Hi
>
>>Die Stackpointer-Initialisierung brauchst du überhaupt nicht.
>
> Über diese Brücke würde ich nicht gehen.

Für den Anfang schon.
Das sind Initialisierungen die er zur Zeit nicht braucht, die ihn aber 
verwirren und von dem was er tun will ablenken.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Justus Skorps schrieb:
> Karl heinz Buchegger schrieb:
>> Der zweite Abschnitt ist komplett identisch mit dem ersten.
>
> die letzte zeile ist anders...

tatsächlich.
Hab ich nicht gesehen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick Berninghaus schrieb:

> schlau draus, da so gut wie alles für mich da neu ist :P der Vorsprung
> den ich mir durch die SPS programmierung versprochen hab ist doch
> seeeehr minimal.

Das vergisst du am besten alles gleich wieder.

> Aber das mit dem register hab ich jetzt glaub ich verstanden.
> Aber ich muss doch trotzdem wenn ich von Port B den Pin 2 als eingang
> belegen will sagen, dass er einen pull down haben muss

Nur dann wenn du einen brauchst.
Brauchst du einen?

> und das er ein
> eingang ist...

ja klar

> warum ist das dann oben doppelt?

vergleich doch mal die beiden Sequenzen. Bis auf die letzte anweisung 
ist alles identisch. Man könnte sagen, dein Programm hat hier gestottert


OK.

> Ich beschäftige mich nun seid 2 abenden mit dem selben Programmteil.
> Es geht darum mit 2 tastern 2 leds zum leuchten zu bringen.
> (taster 1-> led1 , taster 2 ->led2).

Gut.

Dann klären wir doch erst mal die Rahmenbedingungen.

Deine LED hängen wo?
Geraten:   Am Port B
Dort sind die an welchen Anschlüssen?
An den Anschlüssen für Bit 0 und Bit 1

gut.

Deine Taster hängen wo?
Geraten: Am Port D
Dort sind sie an welchen Anschlüssen?
An den Anschlüssen für Bit 0 und Bit 1

Gut.

Nachdem diese Dinge grundsätzlich geklärt sind: Das bedeutet jetzt was 
für deine physikalischen Ports:
Am Port B müssen die Anschlüsse 0 und 1 auf Ausgang geschaltet werden
Am Port D müssen die Auschlüsse 0 und 1 auf Eingang geschaltet werden.

Das wiederrum bedeutet:
Im DDR Register für Port B müssen die Bits 0 und 1 auf 1 gesetzt werden
IM DDR Register für Port D müssen die Bits 0 und 1 auf 0 gesetzt werden

Weiters. WEnn deine Tasten so wie im Tutorial unterer Abschnitt 
angeschlossen sind, dann schalten sie nach Masse und haben keinen 
eigenen PullUp-Widerstand. Wir brauchen also den internen Pullup 
Widerstand an beiden Pins.

Pullup Widerstand an einem Eingang bedeutet, dass du im Port Register 
die beiden Bits auf 1 stellen musst. Dann sind die Pullup eingeschaltet.

Um das System also erstmal in seinen Ausgangs-Konfigurationszustand zu 
bringen, genügt es also
    LDI   R16, 0b00000011
    OUT   DDRB, R16

    LDI   R16, 0b00000000
    OUT   DDRD, R16
    LDI   R16, 0b00000011
    OUT   PORTD, R16

zu machen. Das konfiguriert den Port B und den Port D so wie das oben 
festgestellt wurde. Das ich da jetzt R16 genommen habe, hat keine 
spezielle Bedeutung. Ich hätte auch jedes andere Register nehmen können. 
Der springende Punkt ist: man kann nicht direkt mit einem OUT Befehl an 
das DDRDB oder an das PORTD etwas zuweisen. Man muss immer den Umweg 
über eines der R-Register gehen.

Übrigens ist das nicht die einzige Möglichkeit um das DDRB bzw DDRD und 
PORTD Register ín den gewünschten Zustand zu bringen. Wie so oft gibt es 
viele Möglichkeiten. Beim gezeigten ist es zb so, dass ich durch das OUT 
alle 8 Bit des DDRD Registers beeinflusse. Das möchte ich in diesem Fall 
sogar haben, denn ich will gerne alles kontrollieren. Nicht das mir ein 
nicht beachtetes Bit da irgendwelchen Unfug treibt.

Aber so ...
     SBI   DDRB, 0
     SBI   DDRB, 1

     CBI   DDRD, 0
     CBI   DDRD, 1
     SBI   PORTD, 0
     SBI   PORTD, 1

... wärs natürlich auch gegangen. Wichtig ist ja nur, dass die beiden 
Bits 0 und 1 im DDR bzw. PORT Register danach so stehen wie das weiter 
oben ausgeknobelt wurde.

Und das tun sie ja in beiden Fällen


<Fortsetzung folgt>

Autor: Patrick Berninghaus (patricck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
puh erstmal danke für die geduld!
Ich hatte zwar ursprünglich alles auf port B, aber da ich ein steck 
board habe ist es egal. Ich habe die Eingangs / Ausgangszuweisung nun 
einmal übernommen und versuche die Ausgänge anzusteuern.

Fortsetzung folgt =)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachdem jetzt geklärt ist, mit welchen Anweisungen zunächst mal die 
Umgebung des Programms eingestellt wird, gehts zur Logik

Dazu ist es vorteilhaft, sich erst mal in eigenen Worten einen etwas 
detaqilierteren Überblick über die Aufgabe zu verschaffen. Was war das 
noch mal?

> Es geht darum mit 2 tastern 2 leds zum leuchten zu bringen.
> (taster 1-> led1 , taster 2 ->led2).

Etwas ausführlicher gesagt:
Das Programm muss in einer Schleife ständig seine Arbeit verrichten. 
Praktisch alle Programme auf einem µC arbeiten so: Innerhalb einer 
Schleife stexckt die komplette Logik.
Die Logik sieht jetzt wie aus?

Na ganz einfach
  mache

    wenn Taste0 gedrückt ist
       dann Led 0 einschalten
    andernfalls
       Led 0 ausschalten


    wenn Taste1 gedrückt ist
       dann Led 1 einschalten
    andernfalls
       Led 1 ausschalten

 für immer

das ist der grundsätzliche Plan, den wir umsetzen wollen

dazu überlegen wir uns gleich mal ein paar Dinge:
Wie fragt man ab, ob eine Taste gedrückt ist. Im Tutorial (und 
hoffentlich auch bei dir) ist es so, das das entsprechende Bit im 
zugehörigen PIN Register (in diesem Fall PIND, weil die Tasten ja am 
Port D hängen) auf 0 geht, wenn die Taste gedrückt wird. Dafür gibt es 
aber verschiedene Befehle.
SBIC ist so einer. In Langform bedeutet er _S_kip _I_f _B_it _I_s 
_C_leared
Also: Überspringe den nächsten Befehl, wenn das angegebene Bit im 
Register gelöscht (also 0) ist.

D.h. der Plan wird etwas verfeinert. Nur für 1 Taste und 1 Led

 Hauptschleife:

    Skip if Bit 0 in PIND is cleared
      gehe zu: Led 0 einschalten

    Led 0 ausschalten
    gehe zu: weiter

    Led 0 einschalten

   weiter:

    ....

   gehe zu Hauptschleife

Mach dir klar, dass das immer noch dieselbe Logik ist wie vorhin, nur 
diesmal schon etwas näher an dem, was wir mit unseren Befehlen 
realisieren können. Dadruch das der Skip nur 1 Befehl überspringt, wenn 
die Bedingung zutrifft, ist es notwendig da mit Sprungbefehlen die 
Abarbeitungsreihenfolge zu verändern.

Noch näher am tatsächlichen Programm
HAUPT:

           SBIC   PIND, 0       ; Skip if Bit 0 in PIND is cleared
           RJMP   LED0_ON       ;   gehe zu: Led 0 einschalten
           SBI    PORTB, 0      ; Led 0 ausschalten
           RJMP   WEITER0       ; gehe zu: weiter
LED0_ON:   CBI    PORTB, 0      ; Led 0 einschalten
WEITER0:

...

Das ist genau dasselbe. Aber diesmal in den Anweisungen geschrieben, die 
auch der Assembler versteht. Um die LED ein oder aus zu schalten, setzte 
oder lösche ich am Port B das entsprechende Bit mittels SBI bzw. CBI so 
wie ich das brauche. Der entscheidende Punkt ist aber immer noch das 
SBIC. Mit ihm wird entweder der Sprung zu LED0_ON übersprungen oder er 
wird nicht übersprungen. Je nachdem gehts einmal mit dem SBI und das 
andere mal mit dem CBI weiter. Aber egal wie es weitergeht, beim Label 
WEITER0 treffen sich die Aszuführuungspfade wieder. Dort beginnt dann 
auch die Behandlung der anderen Led und das anderen Tasters
HAUPT:

           SBIC   PIND, 0       ; Skip if Bit 0 in PIND is cleared
           RJMP   LED0_ON       ;   gehe zu: Led 0 einschalten
           SBI    PORTB, 0      ; Led 0 ausschalten
           RJMP   WEITER0       ; gehe zu: weiter
LED0_ON:   CBI    PORTB, 0      ; Led 0 einschalten
WEITER0:

           SBIC   PIND, 1       ; Skip if Bit 1 in PIND is cleared
           RJMP   LED1_ON       ;   gehe zu: Led 1 einschalten
           SBI    PORTB, 1      ; Led 1 ausschalten
           RJMP   WEITER1       ; gehe zu: weiter
LED1_ON:   CBI    PORTB, 1      ; Led 1 einschalten
WEITER1:

           RJMP   HAUPT

und es wird dann ganz zum Abschluss wieder nach HAUPT, also an den 
Anfang der Bearbeitung gesprungen, um die Schleife zu schliessen, die 
dafür sorgt, dass die Abfrage der Tasten viele tausend mal in der 
Sekunde gemacht wird.

Das ganze Programm ist dann

.include "m8def.inc"

           LDI   R16, 0b00000011   ; Am Port B, 0 und 1 auf Ausgang schalten
           OUT   DDRB, R16

           LDI   R16, 0b00000000   ; Am Port D, 0 und 1 auf Eingang
           OUT   DDRD, R16
           LDI   R16, 0b00000011   ; und die Pullups an den beiden Pins
           OUT   PORTD, R16        ; aktivieren

HAUPT:

           SBIC   PIND, 0       ; Skip if Bit 0 in PIND is cleared
           RJMP   LED0_ON       ;   gehe zu: Led 0 einschalten
           SBI    PORTB, 0      ; Led 0 ausschalten
           RJMP   WEITER0       ; gehe zu: weiter
LED0_ON:   CBI    PORTB, 0      ; Led 0 einschalten
WEITER0:

           SBIC   PIND, 1       ; Skip if Bit 1 in PIND is cleared
           RJMP   LED1_ON       ;   gehe zu: Led 1 einschalten
           SBI    PORTB, 1      ; Led 1 ausschalten
           RJMP   WEITER1       ; gehe zu: weiter
LED1_ON:   CBI    PORTB, 1      ; Led 1 einschalten
WEITER1:

           RJMP   HAUPT


(Und jetzt kann ich nur noch hoffen, dass es auch wirklich funktioniert. 
Ich habs nämlich nicht getestet :-)

Autor: Patrick Berninghaus (patricck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super =) an Port D hat es zwar nicht geklappt aber an Port C machen 
meine LEDs nun was sie sollen (Jubelgewitter^^).

Ich werde mich nun mal weiter durch meine Lektüre kauen und aufs beste 
hoffen =)

Vielen dank für die Hilfe! Gestern war ich wirklich kurz davor die lust 
zu verliehren ;)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick Berninghaus schrieb:
> Super =) an Port D hat es zwar nicht geklappt

PORTD D0 und D1 sind die Anschlüsse für die RS232.
Wenn da was dran hängt (MAX232 ?) dann ist klar, das das nicht gehen 
kann.
Die anderen Pins müssten aber funktionieren.

> aber an Port C machen
> meine LEDs nun was sie sollen (Jubelgewitter^^).

Super

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.