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
1 | LEDAUS: |
2 | ldi temp, 0b11111111 |
3 | out PORTA, temp |
4 | ret |
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....
> 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
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>
Lötkünstler wrote: > @ Karl heinz Buchegger (kbuchegg) (Moderator) > >>>>Trotzdem muss der Stackpointer noch initialisiert werden. > meinste das so? Yep
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.