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
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.
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.
;-) 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
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
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?
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!
hmmm heiß übrigens auch Wimmer!
kann mir jemand helfen, hab schon versucht es selber rauszufinden, wie
man einen Stackpointer einbaut?
Wäre wirklich dankbar
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.
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....
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>
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.
@ 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>