robo_wolf,
meine Kommentare sind diesmal ein bisschen länglich ausgefallen ;-), deshalb hab' ich sie als .pdf angehängt.
Ciao,
mare_crisium
Druckbare Version
robo_wolf,
meine Kommentare sind diesmal ein bisschen länglich ausgefallen ;-), deshalb hab' ich sie als .pdf angehängt.
Ciao,
mare_crisium
Hallo mare_crisium,
was soll ich sagen...
Als ich heute Deine Kommentare gelesen habe, war ich so richtig "baff" und andererseits wahnsinnig froh, dass Du Dir so viel Zeit genommen hast, mir Erklaerungen und Beispiele fuer mein kleines Programm zu schreiben. Dafuer erst einmal vielen vielen Dank.
Die "ret" Erklaerung sehe ich nun auch von anderen Blickpunkt aus. Habe beim Erstellen des Codes an der Art nach sich ziehende Probleme nicht gedacht.
Man lernt halt nur aus solchen "Fehlern", wenn man sie bewusst gemacht hat.
Die Delays auf 1 zusetzen kam eigentlich nur aus dem Studio-Simulator.
Dort hatte ich gesehen, dass beim Ruechsprung aus der ISR(wenn ISR waehrend LED_BLINK ausgefuehrt wurde) erst noch die Tot_Zeit abgearbeitet wurde, bevor es zu TESTE zurueck "ret" geht.
Naja ich gebe es zu, da hatte ich schon gemerkt, dass der Code nicht ganz so war, wie ich es eigentlich wollte.
Sah aber zu dem Zeitpunkt keinen anderen Weg, das Runterzaehlen der Register zu beschleuigen oder gar zu unterbinden.
Seit meinem letzten Posting hatte ich leider nicht so viel Zeit, wie ich gern wollte.
Hatte mich aber schon an das naechste Programm, wie von Dir vorgeschlagen, die Tasten ohne Interrupt zu entprellen gemacht und da ein wenig probiert.
Das muss ich nun auch noch einmal gruendlich ueberdenken bzw ueberarbeiten.
Zuvor moechte ich mir Deine Codeaenderungen im Simulator genau anschauen.
Habe da sicher noch einige Fragen.... :-)
Buona sera, Silvio,
freut mich, dass Du Dich trotz allem nicht vom Assembler-Programmieren abbringen lässt ;-). Nur weiter so.
Ciao,
mare_crisium
Hallo mare_crisium,
habe den Code zum Tasten_3 nach Deinen Vorschlaegen angepasst.
Teil 1war ja im Prinzip nur das Sichern der Register in den Unterprogrammen.
Das Register 17 kann ich nicht mit Sichern, da ich es als Zaehlvariable in der ISR benutze.
Mit R16 – temp kein Problem. Funktioniert:
Der 2. Tipp macht mir jedoch Kopfzerbrechen(Seite 5- TESTE_02 bzw. TESTE_03)Code:;***** STK500 Lernprogramm Nr.3c
;*** Aufgabe: alle LEDs mit einem Taster auf dem STK500 schalten
;*** 1. Tastendruck: LEDs einschalten
;*** 2. Tastendruck: LEDs blinken
;*** 3. Tastendruck: LEDs ausschalten
;*** zum Entprellen soll ein Interrupt(Int0) benutzt werden
;***
.include "m8515def.inc"
.def Temp = r16 ; Temporary register
.def Tast_Stat = r17 ; Zaehler fuer Taste in ISR
.def Delay = R18 ; Wartezeit
.def Delay2 = R19 ; Wartezeit
;*****
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp RESET ;1 POWER ON RESET
rjmp INT0_ISR ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC1 Capture
reti ;5 TC1 Compare Match A TC2 Overflow
reti ;6 TC1 Compare Match B TC1 Capture
reti ;7 TC1 Overflow TC1 Compare Match A
reti ;8 TC0 Overflow TC1 Compare Match B
reti ;9 SPI, STC Serial Transfer Complete TC1 Overflow
reti ;10 UART Rx Complete TC0 Overflow
reti ;11 UART Data Register Empty SPI, STC Serial Transfer Complete
reti ;12 UART Tx Complete UART Rx Complete
reti ;13 Analog Comparator
reti ;14 Int2-Interrupt
reti ;15 Timer 0 Compare Match
reti ;16 EEPROM Ready
reti ;17 Store Program Memory Ready
RESET:
ldi r16, LOW(RAMEND) ;Stack initialisieren
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
ldi temp, (1<<ISC00)|(1<<ISC01)
out MCUCR, temp ;Interrupt INT0 konfiguriert
ldi temp, 1 << INTF0 ;InterruptFlagregister geloescht
out GIFR, temp
ldi temp, 1 << INT0 ;Interrupt INT0 aktiviert
out GICR, temp
clr Temp ;Temp mit 0b00000000 bzw. 0x00 laden
out DDRD, Temp ;PORTD als Eingang
ser Temp ;Temp mit 0b11111111 bzw. 0xFF laden
out PORTD, temp ;PullUp an PortD einschalten
out DDRB,Temp ;PORTB als Ausgang
out PORTB, temp ;PORTB (LEDs) aus
sei ;Interrupts zulassen
MAIN:
rcall TESTE
rjmp MAIN
TESTE:
push r16
in r16,SREG
push r16
clr temp ;loesche temp
inc temp ;increment von temp - "1"
cp Tast_Stat,temp ;ist TastStat = 1 dann Rufe Sub LED_AN auf, sonst ueberspringe naechsten Befehl
breq LED_AN
inc temp ;increment von temp - "2"
cp Tast_Stat,temp ;ist TastStat = 2 dann Rufe Sub LED_BLINK auf, sonst ueberspringe naechsten Befehl
breq LED_BLINK
inc temp ;increment von temp - "3"
cp Tast_Stat,temp ;ist TastStat = 3 dann Rufe Sub LED_AUS auf, sonst ueberspringe naechsten Befehl
breq LED_AUS
rjmp TESTE_EXIT
LED_AN: ;loesche temp
clr temp ;setze alle Bit in temp (0b00000000 bzw. 0x00)
out PORTB, temp ;Ausgabe an PortB
rjmp TESTE_EXIT
LED_BLINK:
in temp,PORTB ;lese PORTB in temp
com temp ;Einercomplement von temp (ist 0b00000000 > 0b11111111 oder umgekehrt)
out PORTB,temp ;Ausgabe an PortB
Tot_Zeit:
dec Delay ;zaehle ein Register R18 - 0b0000000 runter und springe danach aus der Schleife
brne Tot_Zeit
;dec Delay2 ;zaehle ein Register R19 - 0b0000000 runter und springe danach aus der Schleife
;brne Tot_Zeit
rjmp TESTE_EXIT
LED_AUS:
ser temp ;setze alle Bits in temp (0b11111111 bzw. 0xFF)
out PORTB,temp ;Ausgabe an PORTB
clr Tast_Stat ;Loesche Tast_Stat
sleep
rjmp TESTE_EXIT
TESTE_EXIT:
pop r16
out SREG,r16
pop r16
ret
INT0_ISR:
push R16 ;Inhalt von R16 auf Stack ablegen
in R16, SREG ;Statusregister in R16 lesen
push R16 ;Inhalt von R16(SREG) auf den Stack ablegen
inc Tast_Stat
pop R16 ;Ruecksichern von R16(SREG)
out SREG, R16 ;Ruecksichern von SREG
pop R16 ;Ruecksichern von R16
reti
Beim Simulieren im AVR-Studio bekomme ich Speicherfehler, da das Programm den STACK durcheinander bringt...?)
eventuell habe ich auch einen Bug mit eingebaut.Code:;***** STK500 Lernprogramm Nr.3b
;*** Aufgabe: alle LEDs mit einem Taster auf dem STK500 schalten
;*** 1. Tastendruck: LEDs einschalten
;*** 2. Tastendruck: LEDs blinken
;*** 3. Tastendruck: LEDs ausschalten
;*** zum Entprellen soll ein Interrupt(Int0) benutzt werden
;***
.include "m8515def.inc"
.def Temp = r16 ; Temporary register
.def Tast_Stat = r17 ; Zaehler fuer Taste
.def Delay = R18 ; Wartezeit
.def Delay2 = R19 ; Wartezeit
;*****
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp RESET ;1 POWER ON RESET
rjmp INT0_ISR ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC1 Capture
reti ;5 TC1 Compare Match A TC2 Overflow
reti ;6 TC1 Compare Match B TC1 Capture
reti ;7 TC1 Overflow TC1 Compare Match A
reti ;8 TC0 Overflow TC1 Compare Match B
reti ;9 SPI, STC Serial Transfer Complete TC1 Overflow
reti ;10 UART Rx Complete TC0 Overflow
reti ;11 UART Data Register Empty SPI, STC Serial Transfer Complete
reti ;12 UART Tx Complete UART Rx Complete
reti ;13 Analog Comparator
reti ;14 Int2-Interrupt
reti ;15 Timer 0 Compare Match
reti ;16 EEPROM Ready
reti ;17 Store Program Memory Ready
RESET:
ldi r16, LOW(RAMEND) ;Stack initialisieren
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
ldi temp, (1<<ISC00)|(1<<ISC01)
out MCUCR, temp ;Interrupt INT0 konfiguriert
ldi temp, 1 << INTF0 ;InterruptFlagregister geloescht
out GIFR, temp
ldi temp, 1 << INT0 ;Interrupt INT0 aktiviert
out GICR, temp
clr Temp ;Temp mit 0b00000000 bzw. 0x00 laden
out DDRD, Temp ;PORTD als Eingang
ser Temp ;Temp mit 0b11111111 bzw. 0xFF laden
out PORTD, temp ;PullUp an PortD einschalten
out DDRB,Temp ;PORTB als Ausgang
out PORTB, temp ;PORTB (LEDs) aus
sei ;Interrupts zulassen
MAIN:
rcall TESTE
rjmp MAIN
TESTE:
push r16
in r16,SREG
push r16
; In Abhängigkeit von Tast_Stat Aktivität auswählen
clr temp ;
inc temp ; temp := Vergleichszahl; Anfangswert Eins
cp Tast_Stat,temp
brne TESTE_02 ; Sprung, wenn TastStat <> 1
rcall LED_EIN
rjmp TESTE_EXIT
TESTE_02:
; Tast_Stat > 1
inc temp
cp Tast_Stat,temp ; Vergleichszahl := 2
brne TESTE_03 ; Sprung, wenn TastStat <> 2
rcall LED_BLINK
rjmp TESTE_EXIT
TESTE_03:
; Tast_Stat > 3
inc temp ; Vergleichszahl := 3
cp Tast_Stat,temp
brne TESTE_EXIT ; Sprung, wenn TastStat <> 3
rcall LED_AUS
LED_EIN: ;loesche temp
clr temp ;setze alle Bit in temp (0b00000000 bzw. 0x00)
out PORTB, temp ;Ausgabe an PortB
rjmp TESTE_EXIT
LED_BLINK:
in temp,PORTB ;lese PORTB in temp
com temp ;Einercomplement von temp (ist 0b00000000 > 0b11111111 oder umgekehrt)
out PORTB,temp ;Ausgabe an PortB
;Tot_Zeit:
;dec Delay ;zaehle ein Register R18 - 0b0000000 runter und springe danach aus der Schleife
;brne Tot_Zeit
;dec Delay2 ;zaehle ein Register R19 - 0b0000000 runter und springe danach aus der Schleife
;brne Tot_Zeit
rjmp TESTE_EXIT
LED_AUS:
ser temp ;setze alle Bits in temp (0b11111111 bzw. 0xFF)
out PORTB,temp ;Ausgabe an PORTB
clr Tast_Stat ;Loesche Tast_Stat
rjmp TESTE_EXIT
TESTE_EXIT:
pop r16
out SREG,r16
pop r16
ret
INT0_ISR:
push R16 ;Inhalt von R16 auf Stack ablegen
in R16, SREG ;Statusregister in R16 lesen
push R16 ;Inhalt von R16(SREG) auf den Stack ablegen
inc Tast_Stat
pop R16 ;Ruecksichern von R16(SREG)
out SREG, R16 ;Ruecksichern von SREG
pop R16 ;Ruecksichern von R16
reti
Nach dem 1. Abarbeiten der ISR kommt das LED_EIN.
Hier wird wieder durch das rjmp der Programmzaehler auf den Stack abgelegt.
Danach der Sprung zum TESTE_EXIT.
Dabei wird ins SREG 0X00 (ein Teil vom Programmzaehler - rjmp LED_EIN) rein geschrieben.
-muesste da nicht doch LED_EIN mit „ret“ beendet werden?
Das sichern des SREG und ggf, anderer register braucht man nur für ISRs.
Wenn man es trotzdem macht, verschwendet man erstmal Platz auf den Stack, und man kann leicht Fehler machen sodass es dann den Stack richtig durcheinander bringt.
Dann ist da noch ein Fehler dirn: Unterprogramme die man mir Rcall aufruft, bendet man mit RET, nicht mit einem RJMP nach teste_exit.
Silvio,
ich habe mir das Lernprogramm 3c ungeändert aus Deinem Posting in den Simulator des AVRStudio geladen und durch alle Zustände von "Tast_Stat" durchlaufen lassen. Es hat einwandfrei funktioniert :-) . Nur die "sleep"-Anweisung war wirkungslos, weil Du im MCUCR-Register das Bit SE nicht auf "1" gesetzt hast. Aber selbst, wenn ich im Simulator SE in MCUCR auf "1" setze, läuft das Programm völlig richtig weiter.
Lernprogramm 3b muss noch korrigiert werden. Zweck der Übung war ja, die einzelnen Funktionen "LED_EIN", "LED_AUS" und "LED_BLINK" in je eine selbstständige Prozedur auszulagern. Wenn man das tut, muss man jede dieser Prozeduren auch mit einer eigenen "ret"-Anweisung abschliessen, sonst kommt der Stack tatsächlich durcheinander.
So könnte das aussehen
So müsste es jetzt funktionieren.Code:;***** STK500 Lernprogramm Nr.3bb
;*** Aufgabe: alle LEDs mit einem Taster auf dem STK500 schalten
;*** 1. Tastendruck: LEDs einschalten
;*** 2. Tastendruck: LEDs blinken
;*** 3. Tastendruck: LEDs ausschalten
;*** zum Entprellen soll ein Interrupt(Int0) benutzt werden
;***
.include "m8515def.inc"
.def Temp = r16 ; Temporary register
.def Tast_Stat = r17 ; Zaehler fuer Taste
.def Delay = R18 ; Wartezeit
.def Delay2 = R19 ; Wartezeit
;*****
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp RESET ;1 POWER ON RESET
rjmp INT0_ISR ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC1 Capture
reti ;5 TC1 Compare Match A TC2 Overflow
reti ;6 TC1 Compare Match B TC1 Capture
reti ;7 TC1 Overflow TC1 Compare Match A
reti ;8 TC0 Overflow TC1 Compare Match B
reti ;9 SPI, STC Serial Transfer Complete TC1 Overflow
reti ;10 UART Rx Complete TC0 Overflow
reti ;11 UART Data Register Empty SPI, STC Serial Transfer Complete
reti ;12 UART Tx Complete UART Rx Complete
reti ;13 Analog Comparator
reti ;14 Int2-Interrupt
reti ;15 Timer 0 Compare Match
reti ;16 EEPROM Ready
reti ;17 Store Program Memory Ready
RESET:
ldi r16, LOW(RAMEND) ;Stack initialisieren
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
ldi temp, (1<<ISC00)|(1<<ISC01)
out MCUCR, temp ;Interrupt INT0 konfiguriert
ldi temp, 1 << INTF0 ;InterruptFlagregister geloescht
out GIFR, temp
ldi temp, 1 << INT0 ;Interrupt INT0 aktiviert
out GICR, temp
clr Temp ;Temp mit 0b00000000 bzw. 0x00 laden
out DDRD, Temp ;PORTD als Eingang
ser Temp ;Temp mit 0b11111111 bzw. 0xFF laden
out PORTD, temp ;PullUp an PortD einschalten
out DDRB,Temp ;PORTB als Ausgang
out PORTB, temp ;PORTB (LEDs) aus
sei ;Interrupts zulassen
MAIN:
rcall TESTE
rjmp MAIN
TESTE:
push r16
in r16,SREG
push r16
; In Abhängigkeit von Tast_Stat Aktivität auswählen
clr temp ;
inc temp ; temp := Vergleichszahl; Anfangswert Eins
cp Tast_Stat,temp
brne TESTE_02 ; Sprung, wenn TastStat <> 1
rcall LED_EIN
rjmp TESTE_EXIT
TESTE_02:
; Tast_Stat > 1
inc temp
cp Tast_Stat,temp ; Vergleichszahl := 2
brne TESTE_03 ; Sprung, wenn TastStat <> 2
rcall LED_BLINK
rjmp TESTE_EXIT
TESTE_03:
; Tast_Stat > 3
inc temp ; Vergleichszahl := 3
cp Tast_Stat,temp
brne TESTE_EXIT ; Sprung, wenn TastStat <> 3
rcall LED_AUS
TESTE_EXIT:
pop r16
out SREG,r16
pop r16
ret
/*-----------------------
PROZEDUR LED_EIN
Die Prozedur LED_EIN setzt im Register "temp" alle Bits auf 0 und
gibt "temp" an PORTB aus.
Eingangsgrössen
temp enthält den aktuellen LED-Zustand
Ausgangsgrössen
temp enthält den LED-Zustand 0x00 = alle LEDs eingeschaltet
geänderte Register
temp
geänderte Ports
PORTB
*/
LED_EIN:
push r19
in r19,SREG
clr temp ;setze alle Bit in temp (0b00000000 bzw. 0x00)
out PORTB, temp ;Ausgabe an PortB
out SREG,r19
pop r19
ret
/*-----------------------
PROZEDUR LED_AUS
Die Prozedur LED_AUS setzt im Register "temp" alle Bits auf 1 und
gibt "temp" an PORTB aus.
Eingangsgrössen
temp enthält den aktuellen LED-Zustand
Ausgangsgrössen
temp enthält den LED-Zustand 0xFF = alle LEDs ausgeschaltet
geänderte Register
temp
geänderte Ports
PORTB
*/
LED_AUS:
push r19
in r19,SREG
ser temp ;setze alle Bits in temp (0b11111111 bzw. 0xFF)
out PORTB,temp ;Ausgabe an PORTB
clr Tast_Stat ;Loesche Tast_Stat
out SREG,r19
pop r19
ret
/*-----------------------
PROZEDUR LED_BLINK
Die Prozedur LED_BLINK invertiert im Register "temp" alle Bits und
gibt den neuen Inhalt von "temp" an PORTB aus.
Eingangsgrössen
temp enthält den aktuellen LED-Zustand
Ausgangsgrössen
temp enthält den invertierten LED-Zustand = alle LEDs umgeschaltet
geänderte Register
temp
geänderte Ports
PORTB
*/
LED_BLINK:
push r19
in r19,SREG
in temp,PORTB ;lese PORTB in temp
com temp ;Einercomplement von temp (ist 0b00000000 > 0b11111111 oder umgekehrt)
out PORTB,temp ;Ausgabe an PortB
;Tot_Zeit:
;dec Delay ;zaehle ein Register R18 - 0b0000000 runter und springe danach aus der Schleife
;brne Tot_Zeit
;dec Delay2 ;zaehle ein Register R19 - 0b0000000 runter und springe danach aus der Schleife
;brne Tot_Zeit
out SREG,r19
pop r19
ret
INT0_ISR:
push R19 ;Inhalt von R19 auf Stack ablegen
in R19, SREG ;Statusregister in R19 lesen
inc Tast_Stat
out SREG, R19 ;Ruecksichern von SREG
pop R19 ;Ruecksichern von R19
reti
Ciao,
mare_crisium
so mal wieder was von mir ....
Wie schon angekuendigt, wollte ich ohne Interrupt ein Programmcode schreiben.
Dabei sollen die LEDs mit dem jeweils auf dem STK500 befindlichen Taster geschaltet werden.
Also druecke Taste - jeweilige LED wird je nach vorherigen Zustand umgeschaltet.
LED an wird LED aus
LED aus wird LED an
Ablauf:
Im Programm selbst frage ich in der MAIN den TastenPort ab und lese den Inhalt in ein 1 Register,
invertiere dieses und schiebe den Inhalt in ein 2. Register.
Teste dann ob Taste gedrueckt ist, wenn ja springe in Warte und zaehle dort ein Register runter,
danach(RE_TEST) lese erneut den TastenPort in das 1. Register aus invertiere den Inhalt,
vergleiche dann mit Inhalt des 2. Registers(erstes Auslesen), wenn gleich springe zu LED_TOGGLE.
In LED_TOGGLE wird der LED_PORT in das LED_Stat-Register gelesen.
Nun wird mittels Exklusiv-ODER das LED_Stat-Register mit dem TAST_Stat-Register umgeschrieben.
LED=1 Tast=1 == LED=0
LED=0 Tast=0 == LED=0
LED=0 Tast=1 == LED=1
LED=1 Tast=0 == LED=1
Dann wird der Inhalt des LED_Stat an den LED_PORT ausgegeben.
Als naechstes wird nun ueberprueft, ob die gedrueckte Taste noch immer gedrueckt ist.
Falls das sein sollte kommt der Sprung in eine Schleife, die permanent die Tasten abfragt, bis die urspruenglich gedrueckte Taste losgelassen wurde.
Wenn das passiert kommt der Sprung zurueck in die MAIN, wo das Spiel wieder von vorn beginnen kann.
Hier nun der Code...
PS.Code:;***** STK500 Lernprogramm Nr.4
;*** Aufgabe: die der jeweiligen Taste zugeordnete LED auf dem STK500 schalten
;*** 1. Tastendruck: LEDs einschalten
;*** 2. Tastendruck: LEDs ausschalten
;*** zum Entprellen soll kein Interrupt werden
;***
.include "m8515def.inc"
.def Temp = r16 ; Temporary register
.def Tast_Stat = r17 ; Tasten Status
.def Tast_Stat1 = r18
.def LED_Stat = R19 ; LED Status
;
.equ LED_PORT = PORTB ; LEDs
.equ LED_DDR = PORTB-1 ; DataDirectory fuer LEDs
.equ TAST_PORT= PORTD ; Tasten
.equ TAST_DDR = PORTD-1 ; DataDirectory fuer TastenEingang
.equ TAST_PIN = PORTD-2 ; TastenEingang
;
;*****
;Reset and Interrupt vector ;VNr. Beschreibung
rjmp RESET ;1 POWER ON RESET
reti ;2 Int0-Interrupt
reti ;3 Int1-Interrupt
reti ;4 TC1 Capture
reti ;5 TC1 Compare Match A TC2 Overflow
reti ;6 TC1 Compare Match B TC1 Capture
reti ;7 TC1 Overflow TC1 Compare Match A
reti ;8 TC0 Overflow TC1 Compare Match B
reti ;9 SPI, STC Serial Transfer Complete TC1 Overflow
reti ;10 UART Rx Complete TC0 Overflow
reti ;11 UART Data Register Empty SPI, STC Serial Transfer Complete
reti ;12 UART Tx Complete UART Rx Complete
reti ;13 Analog Comparator
reti ;14 Int2-Interrupt
reti ;15 Timer 0 Compare Match
reti ;16 EEPROM Ready
reti ;17 Store Program Memory Ready
;*****
RESET:
ldi r16, LOW(RAMEND) ;Stack initialisieren
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16
clr Temp ;Temp mit 0b00000000 bzw. 0x00 laden
out TAST_DDR, Temp ;PORTD als Eingang
ser Temp ;Temp mit 0b11111111 bzw. 0xFF laden
out TAST_PIN, temp ;STK500 schaltet gegen GND - Taste gedreuckt (Pin==0)
out TAST_PORT, temp ;PullUp an PortD einschalten
out LED_DDR,Temp ;PORTB als Ausgang
out LED_PORT, temp ;PORTB (LEDs) aus
MAIN:
in Tast_Stat, TAST_PIN ; lese von PinD und speicher den Inhalt in Tast_Stat
com Tast_Stat ; invertiert fuer spaetere EOR-Berechnung
mov Tast_Stat1, Tast_Stat ; schiebe den Inhalt von Tast_Stat in Tast_Stat2
cpi Tast_Stat, 0b00000000 ; vergleiche Tast_Stat mit 0b00000000, wenn ungleich (Taste gedrueckt) springe zu
WARTE
brne WARTE
rjmp MAIN
WARTE:
push r25 ; Register auf Stack sichern
in r25, SREG
push r25
WARTE_0: ; Wartezeit zum Entprellen
dec r25 ; Schleife decrement Register 25
cpi r25, 0b00000000
breq WARTE_ZEIT_EXIT
rjmp WARTE_0
WARTE_ZEIT_EXIT: ; Ausgang aus Warteschleife
pop r25 ; Register vom Stack holen
out SREG, r25
pop r25
RE_TEST: ; 2. Test - Vergleich ob Taste noch immer gedrueckt
in Tast_Stat, TAST_PIN ; erneute Abfrage von Tasten und Vergleich mit erster Abfrage
com Tast_Stat ; invertiert fuer spaetere EOR-Berechnung
cp Tast_Stat, Tast_Stat1 ; wenn gleich, springe zu LED_TOGGLE
breq LED_TOGGLE
rjmp MAIN
LED_TOGGLE: ; schaltet LED um
in LED_Stat, LED_PORT ; lese LEDs aus und speichere in LED_Stat
eor LED_Stat, Tast_Stat ; ExclusivODER - schalte die Ausgaenge , wo Tasten gedrueckt werden um
; LED=1 Tast=1 == LED=0
; LED=0 Tast=0 == LED=0
; LED=0 Tast=1 == LED=1
; LED=1 Tast=0 == LED=1
out LED_PORT, LED_Stat
cp Tast_Stat, Tast_Stat1 ; vergleiche ob Taste losgelassen
breq WARTE2 ; wenn nicht losgelassen, springe in WARTE2
rjmp MAIN
; Abfrage von Tasten und Vergleich ob die urspruenglich gedrueckte Taste noch immer gedrueckt ist
; neu gedrueckte Taste wird waehrend die urspruenglich gedrueckte Taste noch gedrueckt ignoriert
; ist urspruenglich gedrueckte Taste gedrueckt wird die Schleife nicht verlassen
WARTE2:
RE_TEST_2:
in Tast_Stat, TAST_PIN
com Tast_Stat ; invertiert fuer spaetere EOR-Berechnung
and Tast_Stat, Tast_Stat1 ; Bitmaske - urspruenglich gedrueckte Taste
cp Tast_Stat, Tast_Stat1
breq WARTE2
rjmp MAIN
Einen Zustand habe ich nun noch nicht bedacht.
Es kann keine weitere Taste gedrueckt werden, solange die erste Taste nicht losgelassen wurde.
Das ist von mir in dem Programm zwar so gewollt, weil ich mir noch ueber die Ausfuehrung noch nicht Gedanken gemacht habe.
Haette ich das im jetzigen Code nicht verriegelt, wueder mir die weitere Taste, die erste LED wieder umschalten.
Eine Frage noch an die Experten:
Kann man im AVR-Studio die Zeilennummern aktivieren?
-> es macht die Fehlersuche leichter
robo_wolf,
als erstes fiel mir am Lernprogramm Nr. 4 auf, dass Du nach dem Label 'WARTE' diese "push"-Anweisungen eingebaut hast. Die brauchst Du gar nicht. Auf die Gefahr hin, Dir nichts Neues zu erzählen, habe ich trotzdem 'mal ein paar Erklärungen zum Stack und zu den "call"-, "ret"-, "push"- und "pop"-Anweisungen aufgeschrieben. Es kann ja nicht schaden ... ;-).
Den Rest Deines Programms kommentiere ich später.
mare_crisium
P.S.: Ich hab's bisher noch nicht hingekriegt, die Zeilennummern anzeigen zu lassen. Ich habe mich bisher immer mit der kleinen Anzeige unten rechts beholfen, die die Zeilennummer beim Cursor angibt.
Hallo mare_crisium,
vielen Dank für doch sehr ausfuehrliche Erlaeuterung des Stacks.
Sicher war mir die Funktion und Arbeitsweise schon vertraut.Trotzdem fand ich die Erklaerungen noch vertiefend und leicht verstaendlich.
Aber auch andere User lesen unsere Zeilen und werden sicher ueber so manche verstaendlich geschriebene Erlaeuterung dankbar sein.
Jetzt wo Du mich darauf aufmerksam gemacht hast, sehe ich auch, dass keine Subs im Programm 4 vorhanden sind. Will das Programm eh noch erweitern und eventuell etwas umstellen... Da werde ich doch wieder Unterprogramme mit verwenden.
Danke für Deinen freundlichen Kommentar, robo_wolf. Leider interessieren sich nicht mehr sehr viele für Assemblerprogrammierung, wie man an der Anzahl downloads sieht. C und Konsorten führen halt viel schneller zu sichtbaren Erfolgen; Assembler erfordert Geduld und Übung. Beides ist hierzulande jüngst etwas aus der Mode gekommen ;-) .
Wenn Du sowieso noch einmal Hand an Dein Programm Nr. 4 legen willst, wie wär's, wenn Du versuchtest, die Tasten von einem Dienstprogramm ablesen zu lassen, dass in regelmässigen Abständen von einem Timer-Interrupt ausgelöst wird? Die Timer wirst Du noch sehr häufig brauchen. Je früher Du Dich mit denen anfreundest, desto besser ;-) !
Ciao,
mare_crisium