Forum: Mikrocontroller und Digitale Elektronik Würde dies Funktionieren?


von Martin (Gast)


Lesenswert?

Hi ihr,

es tut mir leid das ich euch mit dieser Kleinigkeit, für mich
aber eine Herrausforderung belästige.

Ich muss ein kleines Programm für einen ATMEL ATMege16 in Assembler 
schreiben, das auf Knopfdruck des Tasters 1 auf der ATMEL STK500 Platine
die LED 1,2,3 und 4 zum leuchten bringt.

Wenn man die Taste 2 Drückt soll LED 5,6,7 und 8 angehen.

Würde dies so funktionieren wie ich es unten geschrieben habe?

Würde mich sehr freuen wenn ihr mir weiterhelfen könntet, ich muss mir 
den Einstieg selbst erarbeiten, und dies ist mein Ergebnis...

Mit freundlichen Grüßen und voller hoffen! ;-)







;*********************************************************************** 
*******
;*********************************************************************** 
*******

;Geschrieben von    Martin
;Datum        2008-04-13
;version      1.0
;file safe as:
;for AVR:      ATMega16
;clock frequency    8MHz

;*********************************************************************** 
*******
;Program function
;
;
;
;*********************************************************************** 
*******

.device ATmega16          ;teilt dem Compiler den Prozessortyp mit
.nolist        ;Programmcode nicht in Logfile aufnehmen
.include "m16def.inc"    ;include file ist die Atmel Mega Definition

;===============
;Declarations:

.def  temp = r16

;===============
;===============
;Start Programm

  rjmp Init         ;Erste Zeile vom Programm

;==============
Init:

ldi    temp, 0b00000000  ;konfiguriert als Input(da 0-7 alles 0)
out    DDRD,temp

ldi    temp, 0b11111111  ;konfiguriert als Output(da 0-7 alles 1)
out    DDRA, temp
out    DDRB, temp
out    DDRC, temp

out    PortD, temp       ;PullUp`s für PortD
out    PortA, temp
out    PortB, temp
out    PortC, temp

;=============
;Hauptprogramm beginnt hier:

Start:
sbis  PIND,0      ;Springe, wenn Bit 0 im Port D Eins ist
rcall  Lampe14   ;Wenn Gedrückt,also oben Null,SpringeProgramm Lampe14

sbis  PIND,1      ;Springe, wenn Bit 1 im Port D Eins ist
rcall   Lampe48  ;Wenn Gedrückt, also oben Null,Springe Programm Lampe48



Lampe14:
  in      temp,PortA  ;Lese aktuellen Zustand von Port B
  andi  temp, 0b11110000   ;Lösche Bit 0 bis 3 mit UND Befehl
  out  PORTA, temp  ;Schreibe ergebnis zurück
  ret      ;Springe zurück von dort wo du kommst.

Lampe48:
  in  temp, PortA
  andi  temp, 0b00001111 ;Lösche Bit 4 bis 7 mit UND Befehl
  out  PORTA,temp   ;Schreibe ergebnis zurück
  ret      ;Springe zurück von dort wo du kommst.





rjmp START      ;springt wieder an den Start

von Karl H. (kbuchegg)


Lesenswert?

Nein das würde so nicht funktionieren.

* Du verwendest rcall, also einen Unterprogrammaufruf.
  Du initialisierst aber nie den Stackpointer

* Wie geht deine Programmausführung weiter, wenn die beiden sbis
  ihre jeweils nächste Anweisung nicht überspringen?
  Genau, dann gehts bei Lampe14 weiter.
  -> Die Hauptschleife ist an dieser Stelle zu Ende und der rjmp Start
     muss genau dort hin.
     Deine Hauptschleife sieht tatsächlich nur so aus
1
Start:
2
       sbis  PIND,0     ; Springe, wenn Bit 0 im Port D Eins ist
3
       rcall  Lampe14   ; Wenn Gedrückt,also oben Null,SpringeProgramm Lampe14
4
5
       sbis  PIND,1     ; Springe, wenn Bit 1 im Port D Eins ist
6
       rcall   Lampe48  ; Wenn Gedrückt, also oben Null,Springe Programm Lampe48
7
8
       rjmp Start       ; und wieder von vorne

Tip: Wenn du wissen möchtest, ob ein Programm funktioniert und
du die reale Hardware zum Testen nicht verfügbar hast, dann kannst
du immer noch dein Programm im Simulator des AVR-Studios laufen
lassen. Für Programme in diesem Schwierigkeitsgrad geht das noch
einigermassen vernünftig.

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

Vielen Dank für die Schnelle Antwort, hat mich wirklich sehr gefreut.
hmm muss gleich mal schauen wie der Simulator funktioniert.

Also hab das Programm nun abgeändert, so müsste es eigentlich klappen?
Würde die Aufgabe gern hinter mir haben... ;-)

Die Hardware, ist schon bestellt, muss aber noch leider zwei
Wochen drauf warten.


************************************************************************ 
******

;Geschrieben von    Martin Wimmer
;Datum          2008-04-13
;version        1.0
;file safe as:
;for AVR:        ATMega16
;clock frequency    8MHz

;*********************************************************************** 
*******
;Program function
;
;
;
;*********************************************************************** 
*******

.device ATmega16  ;teilt dem Compiler den Prozessortyp mit
.nolist      ;Programmcode nicht in Logfile aufnehmen
.include "m16def.inc"   ;include file ist die Atmel Mega Definition

;===============
;Declarations:

.def  temp = r16

;===============
;===============
;Start Programm

  rjmp Init       ;Erste Zeile vom Programm

;==============
Init:

ldi    temp, 0b00000000 ;stellt PortD als Input(da 0-7 alles 0)
out    DDRD,temp

ldi    temp, 0b11111111 ;stellt Port A,B und C als Out(da alles 1)
out    DDRA, temp
out    DDRB, temp
out    DDRC, temp

out    PortD, temp    ;PullUp`s für PortD
out    PortA, temp
out    PortB, temp
out    PortC, temp

;=============
;Hauptprogramm beginnt hier:

Start:
sbis  PIND,0     ;Springe, wenn Bit 0 im Port D Eins ist
rcall  Lampe14     ;Wenn Gedrückt,also oben Null, dann zu Programm 
Lampe14

sbis  PIND,1     ;Springe, wenn Bit 1 im Port D Eins ist
rcall   Lampe48     ;Wenn Gedrückt, also oben Null, dann zu Programm 
Lampe48

rjmp START     ;springt wieder an den Start



Lampe14:
  in  temp,PortA        ;Lese aktuellen Zustand von Port B
  andi  temp, 0b11110000  ;Lösche Bit 0 bis 3 mit UND Befehl
  out  PORTA, temp    ;Schreibe ergebnis zurück
  ret        ;Springe zurück von dort wo du kommst.

Lampe48:
  in  temp, PortA
  andi  temp, 0b00001111 ;Lösche Bit 4 bis 7 mit UND Befehl
  out  PORTA,temp   ;Schreibe ergebnis zurück
  ret      ;Springe zurück von dort wo du kommst.

von Matthias L. (Gast)


Lesenswert?

Und wie gehen die LEDs wieder aus?

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

;-) Soweit hab ich gerade garnicht gedacht!
Danke Matthias!

Hab jetzt noch was hinzugefügt, wäre jetzt alles in Ordnung?

Danke noch einmal für eure Bemühungen



;*********************************************************************** 
*******
;*********************************************************************** 
*******

;Geschrieben von    Martin
;Datum        2008-04-13
;version      1.0
;file safe as:
;for AVR:      ATMega16
;clock frequency    8MHz

;*********************************************************************** 
*******
;Program function
;
;
;
;*********************************************************************** 
*******

.device ATmega16   ;teilt dem Compiler den Prozessortyp mit
.nolist       ;Programmcode nicht in Logfile aufnehmen
.include "m16def.inc"  ;include file ist die Atmel Mega Definition

;===============
;Declarations:

.def  temp = r16

;===============
;===============
;Start Programm

  rjmp Init  ;Erste Zeile vom Programm

;==============
Init:

ldi    temp, 0b00000000 ;konfi. PortD als Input(da 0-7 alles 0)
out    DDRD,temp

ldi    temp, 0b11111111 ;konfi.PortABC als Output(da 0-7 alles 1)
out    DDRA, temp
out    DDRB, temp
out    DDRC, temp

out    PortD, temp     ;PullUp`s für PortD
out    PortA, temp
out    PortB, temp
out    PortC, temp

;=============
;Hauptprogramm beginnt hier:

Start:
sbis  PIND,0     ;Springe, wenn Bit 0 im Port D Eins ist
rcall  Lampe14     ;Wenn Gedrückt,also oben Null,Springe Programm 
Lampe14

sbis  PIND,1     ;Springe, wenn Bit 1 im Port D Eins ist
rcall   Lampe48     ;Wenn Gedrückt, also oben Null,Springe Programm 
Lampe48

sbis  PIND,2     ;Springe wenn Bit 2 im PortD Eins ist
rcall  LEDAUS     ;Wenn Gedrückt,also oben Null,Springe Programm LEDAUS

rjmp START     ;springt wieder an den Start



Lampe14:
  in   temp,PortA     ;Lese aktuellen Zustand von Port B
  andi temp, 0b11110000  ;Lösche Bit 0 bis 3 mit UND Befehl
  out  PORTA, temp  ;Schreibe ergebnis zurück
  ret            ;Springe zurück von dort wo du kommst.

Lampe48:
  in  temp, PortA
  andi temp, 0b00001111  ;Lösche Bit 4 bis 7 mit UND Befehl
  out  PORTA,temp   ;Schreibe ergebnis zurück
  ret           ;Springe zurück von dort wo du kommst.

LEDAUS:
  in temp, PortA   ;Lese aktuellen Zustand von Port B
  andi temp; 0b11111111  ;Lösche Bit 0 bis 7
  out  PORTA, temp     ;Springe zurück von dort wo du kommst.
  ret

von Karl H. (kbuchegg)


Lesenswert?

Martin W. wrote:

> LEDAUS:
>   in temp, PortA   ;Lese aktuellen Zustand von Port B
>   andi temp; 0b11111111  ;Lösche Bit 0 bis 7
>   out  PORTA, temp     ;Springe zurück von dort wo du kommst.
>   ret

Na ja. Es ist etwas sinnfrei, zuerst den aktuelle Zustand von
PortA einzulesen, nur um dann sowieso alle Bits auf 0 zu
setzen. Das kannst du doch auch einfacher mittels
1
LEDAUS:
2
   ldi   temp, 0
3
   out   PORTA, temp
4
   ret

erreichen. Des weiteren bezweifle ich, dass das die LED
wieder ausschalten würde. So wie dein Programm geschrieben
ist, sind die LED aus, wenn die entsprechenden Bits auf 1 sind.
Du willst zum Ausschalten, die Bits also nicht auf 0 haben,
sondern auf 1
1
LEDAUS:
2
   ldi   temp, 0b11111111
3
   out   PORTA, temp
4
   ret

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

also müsste ich einfach meinen:

LEDAUS:
  in temp, PortA         ;Lese aktuellen Zustand von Port B
  andi temp; 0b11111111  ;Lösche Bit 0 bis 7
  out  PORTA, temp       ;Springe zurück von dort wo du kommst.
  ret

durch den von kbuchegg ersetzen

LEDAUS:
   ldi   temp, 0b11111111
   out   PORTA, temp
   ret




 und schon würde es funktionieren?

von Stefan W. (wswbln)


Lesenswert?

Martin W. wrote:

>  und schon würde es funktionieren?

Nein: Du verwendest immer noch rcall bei uninitialisiertem Stackpointer 
(siehe den Beitrag von Karl Heinz). "Springe zurück von dort wo du 
kommst", wie in Deinen Kommentaren steht, findet damit nur zufällig 
statt!

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

hmmm heiß übrigens auch Wimmer!

kann mir jemand helfen, hab schon versucht es selber rauszufinden, wie 
man einen Stackpointer einbaut?
Wäre wirklich dankbar

von Thilo M. (Gast)


Lesenswert?

LEDAUS:
  in temp, PortA         ;Lese aktuellen Zustand von Port B
  andi temp; 0b11111111  ;Lösche Bit 0 bis 7
  out  PORTA, temp       ;Springe zurück von dort wo du kommst.
  ret

Bist du da in den Zeilen verrutscht, wegen den Kommentaren?

1. liest du den Ausgangszustand von PORTA, nichts von PORTB,
2. löschst du nix, diese Zeile ändert nix, ";" ist kein Trennzeichen
3. setzt du den PORTA in denselben Zustand wie vorher.

Macht irgendwie gar keinen Sinn.

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

danke Thilo,
aber ich glaube du hast den falschen Quellcode von mir erwischt...
hab diesen Teil durch eine Verbesserung von jemandem aus dem forum 
ersetzt
und dieser steht nun ganz unten....

von Karl H. (kbuchegg)


Lesenswert?

> kann mir jemand helfen, hab schon versucht es selber rauszufinden, wie
> man einen Stackpointer einbaut?
> Wäre wirklich dankbar

http://www.mikrocontroller.net/articles/AVR-Tutorial

von Lötkünstler (Gast)


Lesenswert?

Ich schlage mal vor eine etwas üblichere Schreibweise durch einrücken
vorzunehmen damit der Quelltext leichter zu lesen ist.


z.B.
Label     Memorics Operant          Kommentar

Lampe14:
          in    temp,PortA        ;Lese aktuellen Zustand von Port B
          andi  temp, 0b11110000  ;Lösche Bit 0 bis 3 mit UND Befehl
          out   PORTA, temp       ;Schreibe ergebnis zurück
          ret                     ;Springe zurück von dort wo du kommst.

Lampe48:
          in    temp, PortA
          andi  temp, 0b00001111  ;Lösche Bit 4 bis 7 mit UND Befehl
          out   PORTA,temp        ;Schreibe ergebnis zurück
          ret                     ;Springe zurück von dort wo du kommst.


Was den Stack angeht brauchst du dir darüber keine Gedanken machen weil
ein Stack grundsätzlich Bestandteil eines jeden Computersystems ist.
Dieser wird genutzt um die Adresse von der der Unterprogrammaufruf 
(rcall)stattgefunden hat,zu merken,um wieder nach Rücksprung(ret)und 
Adresswiederherstellung +1(Macht der Prozzessor automatisch)nach dem
Aufruf mit den folgenden Befehlen fortzufahren.
Schon seltsam das keiner der anderen das mal beschrieben hat.
Lötkünstler

<Mit der Lizenz zum löten>

von Karl H. (kbuchegg)


Lesenswert?

Lötkünstler wrote:

> Was den Stack angeht brauchst du dir darüber keine Gedanken machen weil
> ein Stack grundsätzlich Bestandteil eines jeden Computersystems ist.
> Dieser wird genutzt um die Adresse von der der Unterprogrammaufruf
> (rcall)stattgefunden hat,zu merken,um wieder nach Rücksprung(ret)und
> Adresswiederherstellung +1(Macht der Prozzessor automatisch)nach dem
> Aufruf mit den folgenden Befehlen fortzufahren.

Alles richtig.
Trotzdem muss der Stackpointer noch initialisiert werden.

von Lötkünstler (Gast)


Lesenswert?

@ Karl heinz Buchegger (kbuchegg) (Moderator)

>>>Trotzdem muss der Stackpointer noch initialisiert werden.
meinste das so?
         ldi temp, LOW(RAMEND)    ; LOW-Byte der obersten RAM-Adresse
         out SPL, temp
         ldi temp, HIGH(RAMEND)   ; HIGH-Byte der obersten RAM-Adresse
         out SPH, temp


Lötkünstler

<Mit der Lizenz zum löten>

von Karl H. (kbuchegg)


Lesenswert?

Lötkünstler wrote:
> @ Karl heinz Buchegger (kbuchegg) (Moderator)
>
>>>>Trotzdem muss der Stackpointer noch initialisiert werden.
> meinste das so?

Yep

von Martin W. (Firma: lernender) (martinnsu)


Lesenswert?

Vielen Dank für die Hilfe dir ihr mir geleistet habt!
;-)
Danke!

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.