Forum: Mikrocontroller und Digitale Elektronik ASM code problem


von Tobias L. (bolle87)


Lesenswert?

Hallo Forengemeinde

Gleich vorweg ich bin ganz frisch mit Assembler (24h)
und gleich das erste problem... ich hoffe ich hab halbwegs das richtige 
forum erwischt :)

Hier mein Quelltext:
Meine Frage ist wieso das unten erwähnte bit bei erneutem Prog. 
Durchlauf immer wieder abfällt



.nolist
.include "m8def.inc"
.list

  ldi r16, 0b11111111    ; PortB = Ausgangsport
  out DDRB, r16

  ldi r16, 0b00000000    ; PortA = Eingangsport
  out DDRD, r16

; Wenn BIT0 am PIND = 0 ist soll BIT0 am PORT B = 1 sein
; Wenn BIT0 am PIND = 1 ist soll BIT0 am PORT B = 0 sein
; ----------------- soweit funktioniert es ------------------
; Wenn BIT0 am PIND = 1 ist soll BIT1 am PORTB = 1 sein
; was bis Zeile 6 auch funktioniert dann fällt es jedoch wieder ab ???

label1:

;1  in r16, PIND      ; Bitwerte Port D einlesen
;2  ldi r17, 0b00000001
;3  eor r17, r16      ; BIT0 PORTB aktiv solange PIND     BIT0 inaktiv
;4  out PORTB, r17      ; Ausgabe an PORTB
;5  ldi r18, 0b00000010    ; BIT1 in Register 18 laden
;6  sbic PIND, 0
;7  out PORTB, r18      ; BIT1 an PORTB übergeben
;8  rjmp label1

von Mönsch (Gast)


Lesenswert?

Weil Du hier,

;5  ldi r18, 0b00000010    ; BIT1 in Register 18 laden

wo Du das Bit1 für die mögliche Ausgabe hier

;7  out PORTB, r18      ; BIT1 an PORTB übergeben

lädst, nicht berücksichtigst, dass Bit0 möglicherweise 1 sein muss, wie 
es hier

;3  eor r17, r16      ; BIT0 PORTB aktiv solange PIND     BIT0 inaktiv

bestimmt worden ist. Du kannst da nicht einen konstanten Wert ausgeben, 
denn Bit0 ist eben nicht konstant.

Du brauchst also noch eine Oder-Operation. Klar?

von Mönsch (Gast)


Lesenswert?

Da Bit1 und Bit0 identisch ausgegeben werden sollen, gibt es mindestens 
noch zwei andere Wege das zu programmieren. Eine gute Übung, denke ich.

1. Spar Dir das sbic. Die Information über Bit0 hast Du ja schon. Warum 
die nochmal ermitteln? Wie kannst Du also Bit1 aus Bit0 der Ausgabe, wie 
sie in Zeile 3 ermittelt wird, nach Bit1 kopieren?

2. Nimm gleich vorne ein sbic (sbis) um den Ausgabewert direkt auf 
0b00000011 oder 0x0 zu setzen.

von Martin (Gast)


Lesenswert?

Deinem Programm fehlt am Ende eine geschlossene Schleife, in der der 
Prozessor nach dem "out DDRD"-Befehl geordnet hängt. So wird 
irgendetwas, was dahinter im Speicher steht, als Programm ausgeführt.

von Markus G. (thechief)


Lesenswert?

Hallo Martin,

Du schreibst:

Martin schrieb:
> Deinem Programm fehlt am Ende eine geschlossene Schleife, in der der
> Prozessor nach dem "out DDRD"-Befehl geordnet hängt. So wird
> irgendetwas, was dahinter im Speicher steht, als Programm ausgeführt.

Das Programm ist nach dem "out DDRD" Befehl aber eigentlich nicht zu 
Ende.
Der untere Teil, ab dem Befehl "in r16, PIND", welcher als Kommentar 
dargestellt ist, gehört auch noch dazu und somit läuft das Programm 
durch den "rjmp label1" Befehl in einer Endlosschleife.


Gruß

Markus

von Tobias L. (bolle87)


Lesenswert?

WOW das ging schnell... ich danke auf jeden fall schonmal für die 
Beiträge !
Und an MÖNCH ich ein interessanter Denkanstoß.... ich mach mir noch mal 
Gedanken !!!

von Markus G. (thechief)


Lesenswert?

Hallo Tobias,
hallo Mönsch,

Mönsch schrieb:
> Weil Du hier,
>
> ;5  ldi r18, 0b00000010    ; BIT1 in Register 18 laden
>
> wo Du das Bit1 für die mögliche Ausgabe hier
>
> ;7  out PORTB, r18      ; BIT1 an PORTB übergeben
>
> lädst, nicht berücksichtigst, dass Bit0 möglicherweise 1 sein muss, wie
> es hier
>
> ;3  eor r17, r16      ; BIT0 PORTB aktiv solange PIND     BIT0 inaktiv
>
> bestimmt worden ist. Du kannst da nicht einen konstanten Wert ausgeben,
> denn Bit0 ist eben nicht konstant.
>
> Du brauchst also noch eine Oder-Operation. Klar?

Die Erklärung von Mönsch ist richtig.

Allerdings bin ich der Meinung, dass man hier nicht eine zusätzliche 
Oder-Operation braucht sondern, dass die Oder-Operation den ldi Befehl 
ersetzt, die Lösung sieht dann wie folgt aus:
1
;ldi r18, 0b00000010    ; BIT1 in Register 18 laden
2
sbr r18, 0b00000010    ; BIT1 in Register 18 setzen, unabhängig vom Zustand aller anderen Bits in r18

Die Zeile mit dem ldi Befehl entfällt und wird durch die Zeile mit dem 
sbr Befehl für die bit-weise Manipulation des Registers r18 ersetzt.
Somit wird das Bit 1 in Register 18 unabhänig vom Zustand des Bit 0 in 
Register r18 gesetzt!


Gruß

Markus

von Tobias L. (bolle87)


Lesenswert?

hallo markus
ich habs eben auch noch mal ausprobiert... es funktioniert auch das 
Problem ist wenn das bit gesetzt ist bleibts auch gesetzt was aber 
passieren soll ist das in dem momenet wo pind bit0 = 0 portb bit0 =1
                                  0 = 1 portb bit0 =0 bit1 = 1
also die port bits sollen in abhängigkeit des pind bit 0 immer hin und 
herschalten. was mir fehlt ist sowas wie "if" "else"... hätte nie 
gedacht das mir so ein simples programm so zu schaffen macht :)

von Tobias L. (bolle87)


Lesenswert?

mir fehlt ne abhängigkeit bit 1 portb wird ja immer gesetzt unabhängig 
von pind bit 0.. oder hab ich mich jetzt total verannt ?

von Markus G. (thechief)


Lesenswert?

Hallo Tobias,

das mit dem "verrennen" kann schon mal passieren, dann will ich mal 
versuchen Dich wieder zu entwirren... :-)

Um das Ganze für mich und andere hier verständlich zu machen wäre eine 
sogenannte Wahrheitstabelle sinnvoll.

Hier ein Beispiel für die logische Und-Funktion:

A und B = X

A     B   X
-----------
0     0   0
1     0   0
0     1   0
1     1   1


Und zum Vergleich für die logische Oder-Funktion:

A oder B = X
------------
0      0   0
1      0   1
0      1   1
1      1   1


In meinen Beispielen sind A und B Eingänge und X der Ausgang.
Ein solche Tabelle kann aber natürlich auch nur einen Eingang und 
mehrere Ausgänge haben.
Wie bei Dir: Der Eingang ist PIND (Port D) Bit 0 und die Ausgänge sind 
PORTB Bit 0 und Bit 1.

Nun wäre es gut wenn Du Deine Funktion analog hierzu abbilden würdest.
Und wenn wir das haben bauen wir anschließend auf Grund der Tabelle den 
hierfür nötigen Assembler-Code!

Und wenn wir das dann auch noch haben und alles funktioniert, freuen wir 
uns... ;-)


Viele Grüße

Markus

PS: Hoffentlich habe ich Dich nun nicht noch mehr verwirrt... grübl

von Mönsch (Gast)


Lesenswert?

>Allerdings bin ich der Meinung, dass man hier nicht eine zusätzliche
>Oder-Operation braucht sondern, dass die Oder-Operation den ldi Befehl
>ersetzt, ...

Das ist sicherlich richtig, aber es war auch nicht meine Absicht mit dem 
"noch" auszusagen, das das restliche Programm so bleiben kann oder soll.
In dem vorliegenden Fall ist es sicherlich diskutabel, ob man einem 
blutigen Anfänger mit dem "noch" etwas Irreführendes suggeriert. Ich 
meinte aber natürlich, dass der Rest des Programmes entsprechend 
angepasst werden muss.

von spess53 (Gast)


Lesenswert?

Hi

>Hier mein Quelltext:

Das ist hoffentlich nicht der Quelltext, den du assemblierst?

MfG Spess

von Tobias L. (bolle87)


Lesenswert?

also was ich möchte ist... :)

eingang A   Ausgang 1    Ausgang 2

0              1             0
1              0             1

Und das ganze soll jederzeit in abhängigkeit von eingang A wechseln 
können
tschuldigung aber ich drück mich n bischen umständlich aus :(

wär addition der register ne möglichkeit... hab aus frust mal weiter im 
tutorial gestöbert !?

von Karl H. (kbuchegg)


Lesenswert?

Tobias L. schrieb:
> also was ich möchte ist... :)
>
> eingang A   Ausgang 1    Ausgang 2
>
> 0              1             0
> 1              0             1
>
> Und das ganze soll jederzeit in abhängigkeit von eingang A wechseln
> können
> tschuldigung aber ich drück mich n bischen umständlich aus :(
>
> wär addition der register ne möglichkeit... hab aus frust mal weiter im
> tutorial gestöbert !?

und warum liest du es dann nicht ordentlich von vorne weg durch?

Alles was du brauchst (in der Hauptschleife) sind die Befehle, SBIS 
(oder SBIC), CBI und SBI, und RJMP

gleich der erste Tutioriumsartikel, bei dem es mit der Programmierung 
los geht.

1
.include "m8def.inc"
2
3
  ldi r16, 0b11111111    ; PortB = Ausgangsport
4
  out DDRB, r16
5
6
  ldi r16, 0b00000000    ; PortA = Eingangsport
7
  out DDRD, r16
8
9
main:
10
  sbic PIND, 0           ; wenn Bit PIND - 0 auf 0 ist, dann überspringe den rjmp
11
  rjmp portb_one
12
13
  sbi  PORTB, 0          ; Bit 0 auf 1 setzen
14
  cbi  PORTB, 1          ; Bit 1 auf 0 setzen
15
16
  rjmp main
17
18
portb_one:
19
  cbi  PORTB, 0          ; Bit 0 auf 0 setzen
20
  sbi  PORTB, 1          ; Bit 1 auf 1 setzen
21
22
  rjmp main

von Tobias L. (bolle87)


Lesenswert?

hey spess wieso nich... also doch das ist er, naja ohne die ganzen 
komentare !?

von Tobias L. (bolle87)


Lesenswert?

ja da bin ich auch gerade wieder gelandet... ich machs irgendwie viel zu 
umständlich, sry

von Tobias L. (bolle87)


Lesenswert?

cool... danke Autor:  Karl Heinz Buchegger das war der anstoß den ich 
brauchte... und den anderen beteiligten natürlich auch besten dank !!!

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.