- LiFePO4 Speicher Test         
Seite 5 von 14 ErsteErste ... 34567 ... LetzteLetzte
Ergebnis 41 bis 50 von 136

Thema: Anfänger mit STK500 und Assembler

  1. #41
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    Anzeige

    LiFePo4 Akku selber bauen - Video
    Guten Abend, robo_wolf!

    Zitat Zitat von robo_wolf
    Ich glaub, ich steh hier schon wieder auf der Leitung.
    nee, stehst Du nicht: Du bist nur über die Gemeinheiten der Speicherorganisation bei ATMELs MCs gestolpert.

    Guck' mal:
    Zitat Zitat von robo_wolf
    0x0019 CD AB
    Offenbar ist im Flash-Speicher unter jeder Adresse je ein 2-Byte-Wort gespeichert.
    Deshalb ist der Programmzähler (PC) so aufgebaut, dass PC+1 auf das nächste 2-Byte-Wort nach PC zeigt. Beim Inkrementieren springt der PC um zwei Bytes weiter. So sind auch die Adresse 0x0019 aus Deinem Beispiel zu verstehen: Es ist die Adresse eines 2-Byte-Wortes.

    Im Gegensatz dazu ist im RAM unter jeder Adresse je ein 1-Byte-Wort gespeichert.
    Deshalb sind die Zeigerregister zh:zl, yh:yl und xhl so aufgebaut, dass sie beim Inkrementieren um ein 1-Byte-Wort weiterspringen.

    Beim Auslesen des Flash-Speichers mit der „lpm“-Anweisung muss man zh:zl als Zeigerregister verwenden. Das führt zu Schwierigkeiten: zh:zl kann nur auf einzelne Bytes zeigen, die Flashspeicher-Adressen beziehen sich aber immer auf ein 2-Byte-Wort. Also muss man die Flashadresse in zh:zl verdoppeln, dann zeigt zh:zl auf das LSB des gespeicherten Doppelbytes.

    Beispiel: Das MSB des unter 0x0019 im Flash gespeicherten Wortes soll ausgelesen werden

    Code:
         ldi zh,HIGH(0x0019)
         ldi zl,LOW(0x0019)
         add zl,zl                 ;  Zeiger verdoppeln
         adc zh,zh                ; jetzt zeigt er auf das LSB
    ;     lpm r16,z               ; diese Anweisung würde jetzt das LSB (0xCD) nach r16 befördern
         adiw zh:zl,0x0001        ; wir wollen ans MSB kommen, also noch eins draufaddieren
         lpm r16,z                ; so, jetzt landet das MSB (0xAB) in r16.
    Du hast also recht: Der PC zeigt auf gerade wie ungerade Adressen im Flashspeicher. Ich bezog mich auf die Verwendung von zh:zl im Flashspeicher. Da steht das LSB immer unter der geraden Adresse und das MSB unter der ungeraden.

    Am Besten, Du probierst's direkt im Simulator und mit einem Glas Wein gleich 'mal aus .

    Ciao,

    mare_crisium

  2. #42
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310

    noch immer Verstaendnisprobleme

    Hallo mare_crisium,
    leider habe ich noch immer Verstaendnisprobleme.
    - Das Lesen der Tabellenwerte mit Zeigern und deren Verarbeitung -

    Ich habe Deinen Code mit einfliessen lassen und habe ihn nun so einge Male durch den Simulator getickert.
    Aber es hat leider bei mir noch immer nicht klick gemacht...
    Selbst mit den Wein nicht.
    Den Code dokumentierten Zeile haenge ich diesmal an.
    Dokumentiert sind 3 Durchlaeufe.
    Vielleicht kannst Du mir noch ein paar Erlaeuterungen ergaenzen ?
    Angehängte Dateien Angehängte Dateien
    ### Silvio ###

  3. #43
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    nicht locker lassen! Das mit der Tabelle konnte nicht klappen, weil Du zh:zl nicht mit dem Zeiger auf den Tabellenanfang geladen hattest .

    Versuch' mal das hier:

    Code:
    ;***** STK500 Lernprogramm Nr.4e
    ;*** Aufgabe: die Taste an PinD0 schaltet die zugeordnete LED auf dem STK500
    ;*** 1. Tastendruck: LEDs einschalten
    ;*** 2. Tastendruck: LEDs ausschalten
    ;*** eine Timerroutine liest den TastenStatus ein
    ;*** zum Entprellen - muss die TimerRoutine 3mal hintereinander den gleichen Wert,
    ;*** einlesen um einen Tastzustand zu erkennen, Zst_Var 0x03 bzw. 0x00
    ;*** Taste nicht gedrueckt >>> log 0 in Tast_Stat(r17)
    ;*** Taste gedrueckt       >>> log 1 in Tast_Stat(r17)
    ;
    ;
    .include "m8515def.inc" 
    .def Temp        = r16			; Temporary Register 
    .def Tast_Stat   = r17			; Tasten Status
    .def Tast_Stat0	 = r18
    .def LED_Stat    = r19			; LED Status
    .def Zst_Var     = r20			; Zustandsvariable - beinhaltet eine 2Bit-Zahl zur Tastzustandserkennung
    .def LED_Update_SPRR = r21		; Sperrt die Ausfuehrung von TastenTest wenn, keine neuer TIMER1_OVL voran gegangen	
    ;
    .equ Timerwert   = 255 ;-1562     	; Timerschritte bis zum Überlauf
    
    .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
    
    
    ; Bit-Definitionen für Z-Wert
    .equ bZWERT_FLANKE = 3		; Bit3 speichert das "Flankenbit"
    							; 0 = "keine Flanke"
    							; 1 = "Flanke steht an"
    .equ bZWERT_BETAETIGT = 0	; Bit0 speichert den Tastenzustand 
    							; 0 = "nicht betätigt"
    							; 1 = "betätigt"
    
    ; Pinzuordnung für div. Tasten
    .equ TASTE0_PIN	= 0
    .equ TASTE1_PIN = 1
    .equ TASTE2_PIN = 3			; die Zuordnung der PINs muss ja nicht mit der TastenNr übereinstimmen!
    .equ TASTE3_PIN = 2
    
    ; jetzt kommen die Register, die die Z-Werte der Tasten enthalten. Im Prinzip 
    ; braucht man nur jeweils nur ein Nibble pro Taste. Um die Sache erstmal einfach
    ; zu halten wird für jede Taste ein ganzes Byte verbraucht.
    .def rTASTE0_ZST = r15	; enthält Zustand Taste0 
    .def rTASTE1_ZST = r14	; enthält Zustand Taste1
    .def rTASTE2_ZST = r13	; enthält Zustand Taste2
    .def rTASTE3_ZST = r12	; enthält Zustand Taste3
    
    
    
    ;
    ;	Vektortabelle
    ;
       rjmp RESET		        	;  1 - $000 RESET      External Pin, Power-on Reset, Brown-out, Reset and Watchdog Reset
       reti				        	;  2 - $001 INT0       External Interrupt Request 0
       reti				        	;  3 - $002 INT1       External Interrupt Request 1
       reti        					;  4 - $003 TIMER1 CAPT Timer/Counter1 Capture Event
       rjmp TIMER1_COMPA_ISR        ;  5 - $004 TIMER1 COMPA Timer/Counter1 Compare Match A
       reti        					;  6 - $005 TIMER1 COMPB Timer/Counter1 Compare Match B
       reti        					;  7 - $006 TIMER1 OVF Timer/Counter1 Overflow
       reti        					;  8 - $007 TIMER0 OVF Timer/Counter0 Overflow
       reti        					;  9 - $008 SPI,       STC   Serial Transfer Complete
       reti        					; 10 - $009 USART,     RXC USART, Rx Complete
       reti        					; 11 - $00A USART,     UDRE USART Data Register Empty
       reti        					; 12 - $00B USART,     TXC USART, Tx Complete
       reti        					; 13 - $00C ANA_COMP   Analog Comparator
       reti        					; 14 - $00D INT2       External Interrupt Request 2
       reti        					; 15 - $00E TIMER0     COMP Timer/Counter0 Compare Match
       reti        					; 16 - $00F EE_RDY     EEPROM Ready
       reti        					; 17 - $010 SPM_RDY    Store Program memory Ready
    ;
    TBL_UEBERGANG_01:
    .dw 0x0008  ; Tabellenlänge
    ;								T = 0					T = 1
    .dw 0x0200  ;     Z=0 ->      Z=0,Flanke=0     /     Z=2,Flanke=0
    .dw 0x0308  ;     Z=1 ->      Z=0,Flanke=1     /     Z=3,Flanke=0
    .dw 0x0400  ;     Z=2 ->      Z=0,Flanke=0     /     Z=4,Flanke=0
    .dw 0x0501  ;     Z=3 ->      Z=1,Flanke=0     /     Z=5,Flanke=0
    .dw 0x0602  ;     Z=4 ->      Z=2,Flanke=0     /     Z=6,Flanke=0
    .dw 0x0703  ;     Z=5 ->      Z=3,Flanke=0     /     Z=7,Flanke=0
    .dw 0x0F04  ;     Z=6 ->      Z=4,Flanke=0     /     Z=7,Flanke=1
    .dw 0x0705  ;     Z=7 ->      Z=5,Flanke=0     /     Z=7,Flanke=0
    
    ; verweist auf den Programmspeicher und zeigt dort im ersten Wort auf den ersten 
    ; definierten Wert(Tabellenlaenge), 
    ; anschliessende Worte beinhalten die festgelegten Werte fortlaufend
    ; bedeutet in meinem Fall Verweis auf 0x0011 mit 08 00 (.dw 0x0008)
    ;									  0x0012 mit 02 00 (.dw 0x0200)
    ;									  0x0013 mit 00 00 (.dw 0x0000)
    ;									  0x0014 mit 04 00 (.dw 0x0400)
    ;									  0x0015 mit 08 50 (.dw 0x0580)
    ;									  0x0016	mit 02 87 (.dw 0x8702)
    ; 									  0x0017 mit 03 07 (.dw 0x0703)
    ;									  0x0018 mit 00 00 (.dw 0x0000)
    ;									  0x0019	mit 05 07 (.dw 0x0705)
    ;			 ->>>
    ;			 Der Wert(Tabellenlaenge) ist auch nur ein festgelegter Wert und fuer Programmoperationen wichtig. 
    ;			 
    RESET: 
    ;
    	ldi r16, LOW(RAMEND)        	;Stack initialisieren 
    	out SPL, r16 
    	ldi r16, HIGH(RAMEND) 
    	out SPH, r16 
    ;
    	ldi temp,(1<<CS10)|(1<<WGM12)				; Taktfrequenz Vorteiler 1 gewaehlt (fuer Simaulatortest)          
    ;	ldi temp,(1<<CS10)|(1<<CS12)|(1<<WGM12)	; Taktfrequenz mit Vorteiler 1024 gewaehlt           
     	out TCCR1B,temp
    ;
     	ldi temp,HIGH(Timerwert) 
    	out OCR1AH,temp
     	ldi temp,LOW(Timerwert) 
    	out OCR1AL,temp
    ;
    	ldi temp,(1<<COM1A1)|(0<<COM1A0)
    	out	TCCR1A,temp
    	ldi temp,(1<<OCIE1A)				; Timer1 Overflow aktivieren
    	out TIMSK,temp          
    ;
    	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
    	 
    ; Tastenzustände aller Tasten auf Null setzen
    	clr r16					; 
    	mov rTASTE0_ZST,r16		; Taste0 und Taste1 zurücksetzen
    	mov rTASTE2_ZST,r16		; Taste2 und Taste3 zurücksetzen
    	clr Zst_Var
    ;
    	sei
    ;
    ;
    MAIN:
    	sbrc LED_Update_SPRR,0	; kein LED_Update, wenn Bit0 ==0
    	rcall LED_Update
    	rjmp MAIN
    ;
    LED_Update:
    	cbr LED_Update_SPRR,0	; loesche Bit0, um LED_Update bis zur naechsten TIMER1_ISR zu sperren
    	ret
    ;
    
    /*-------------------------------------
    
    INTERRUPTDIENST TIMER1_COMPA_ISR
    
    Die Interruptdienstprogramm TIMER1_COMPA_ISR wird vom Output-Match-Interrupt von
    Timer1 ausgelöst. Es liest die aktuellen Messwerte der Tasten vom TAST_PIN ab und
    berechnet für jede Taste den neuen Zustand (Z-Wert).
    
    Eingansgrössen:
    	keine
    
    Ausgangsgrössen:
    	keine
    
    geänderte Register
    	keine
    
    Anzahl Zyklen
    
    */
    
    TIMER1_COMPA_ISR:
    	push r25
    	in r25,SREG
    	push r16
    	push r17
    	push r18
    	push zl
    	push zh
    
    /*
    Das hier hattest Du übersehen:
    Der Zeiger auf die Übergangstabelle muss VOR (!!) dem Aufruf von NEXT0_TAST_ZST 
    in die Register zh:zl geladen werden !!
    */
    	ldi zl,LOW(TBL_UEBERGANG_01) ; zh:zl := Zeiger auf Übergangstabelle ...
    	ldi zh,HIGH(TBL_UEBERGANG_01) ; ...wird für NEXT0_TAST_ZST gebraucht
    
    ; Betätigungszustand der Tasten einlesen und der Reihe nach verarbeiten
    	in r18,TAST_PIN		; r18 := Messwerte aller Pins 
    
    ; Taste0 verarbeiten
    	bst r18,TASTE0_PIN	; überträgt den Messwert von TASTE0_PIN ins T-Flag von SREG
    	mov r16,rTASTE0_ZST  ; r16 := Z-Wert Taste0
    	andi r16,0x07		; "Flankenbit" löschen
    	rcall NEXT0_TAST_ZST ; Folgezustand für Taste0 in r16 berechnen
    	mov rTASTE0_ZST,r16	; neuen Z-Wert in TASTE0_ZST speichern
    
    ; Taste1 verarbeiten
    	bst r18,TASTE1_PIN	; überträgt den Messwert von TASTE1_PIN ins T-Flag von SREG
    	mov r16,rTASTE1_ZST  ; r16 := Z-Wert Taste1
    	andi r16,0x07		; "Flankenbit" löschen
    	rcall NEXT0_TAST_ZST ; Folgezustand für Taste1 in r16 berechnen
    	mov rTASTE1_ZST,r16	; neuen Z-Wert in TASTE1_ZST speichern
    
    ; usw...
    
    	sbr LED_Update_SPRR,0				; Status fuer LED_Update 1 - LED_Update  / 0 - kein LED_Update
    
    	pop zh
    	pop zl
    	pop r18
    	pop r17
    	pop r16
    	out SREG,r25
    	pop r25
    	reti
    ;
    /*-------------------------------------
    
    PROZEDUR NEXT0_TAST_ZST
    
    Die Prozedur NEXT0_TAST_ZST liest den Folgezustand der Tastenentprellung aus einer
    Übergangstabelle aus. Die Adresse der Tabelle wird in zh:zl übergeben. Der aktuelle
    Zustand (Z-Wert) wird in r16 übergeben. Der aktuelle Tastenzustand (betätigt/nicht
    betätigt) ist im T-Flag von SREG gespeichert. Das Ergebnis wird in r16 zurückgegeben.
    Die Tabelle, darf maximal 127 Einträge enthalten. Der erste Eintrag der Tabelle ist
    die Länge der Tabelle und dient der Bereichsüberprüfung.
    
    D.h. der Zeiger auf die Übergangstabelle muss zh:zl geladen werden BEVOR diese
    Prozedur aufgerufen wird!! In diesem Beispiel, bei dem nur eine einzige Übergangstabelle 
    im Spiel ist, könnte man zh:zl auch innerhalb von NEXT0_TAST_ZST laden. Um die 
    Prozedur auch in Programmen verwenden zu können, in denen mehrere Zustandsautomaten
    nebeneinanderherlaufen, ist es sinnvoll, den Zeiger vorher zu laden. Dann kann je
    nach Aufgabe eine andere Tabelle verwendet werden. Kommt in meinen Programmen öfters
    vor ;-). 
    
    Eingansgrössen:
    	r16		: enthält aktuellen Z-Wert der Taste
    	zh:zl	: enthält Zeiger auf die Übergangstabelle
    	SREG (T-Flag) : enthält den aktuellen Messwert der Taste
    		T = 0 : Taste nicht betätigt
    		T = 1 : Taste betätigt
    
    Ausgangsgrössen:
    	r16		: enthält den neuen Z-Wert für die Taste
    	zh:zl	unverändert
    	SREG	unverändert
    
    geänderte Register
    	r16
    
    Anzahl Zyklen
    
    */
    
    NEXT0_TAST_ZST:
    	push r17
    	in r17,SREG
    	push r17
    	push r18
    	push zl
    	push zh
    
    ; Zeiger auf Anfang der Übergangstabelle berechnen
    	add zl,zl        ; zh:zl verdoppeln, weil einer Adresse im...
    	adc zh,zh        ; .. Programmspeicher immer zwei Bytes entsprechen
    	; FRAGE: Wo wird die Information abgelegt -> im Flashspeicher
    	;
    	;
    ; Information in Bit7 löschen; Tabelle darf nicht länger als 127 Einträge sein
    	andi r16,0x7F    ; 
    
    ; Tabellenlänge einlesen (0-ter Eintrag in der Tabelle)
    	lpm r17,z+       ;  r17 := TBL_LNG einlesen
    	; 1.Durchgang
    	; es wird in R16 der Wert 0x19 eingetragen - ??? Die letzte Stelle in der Tabelle (0x0019)
    	; und in R30(ZL) die 0x01
    	;
    	; 2.Durchgang
    	; es wird in R16 der Wert 0x19 eingetragen - ??? Die letzte Stelle in der Tabelle (0x0019)
    	; und in R30(ZL) die 0x01
    	;
    	; KLAR; Du hattest den Zeiger nicht gesetzt!
    	;
    	;
    	lpm r18,z+       ;  zweites Byte überlesen, wird nicht gebraucht
    
    ; Bereichsprüfung ( r17 < TBL_LNG )
    	cp r16,r17       ; Tabellenindex mit TBL_LNG vergleichen
    	brlt NXT0ZST_00  ; Sprung, wenn Tabellenindex iO
    
    ; Fehler: Tabellenindex ist zu gross
    	clr r16 ; Zustand auf Null setzen
    	rjmp NXT0ZST_EXIT ; fertig
    
    NXT0ZST_00:
    ; Tabellenindex im zulässigen Bereich
    	clr r17 ; 
    	add zl,r16       ; Index zweimal zum Zeiger addieren, weil...
    	adc zh,r17       ; ... in der Tabelle...
    	add zl,r16       ; ... 2-Byte-Worte gespeichert sind.
    	adc zh,r17       ; zh:zl := Zeiger auf Tabelleneintrag	
    	lpm r16,z+       ; r16 := Folgezustand für T=0
    	lpm r17,z        ; r17 := Folgezustand für T=1
    	brtc NXT0ZST_EXIT ; fertig, wenn T = 0
    
    ; T = 1, d.h. Taste betätigt
    	mov r16,r17      ; zweiten Eintrag als Folgezustand verwenden
    
    NXT0ZST_EXIT:
    ;	sbr LED_Update_SPRR,0				; Status fuer LED_Update 1 - LED_Update  / 0 - kein LED_Update
    ; diese Zeile gehört in den Interruptdienst!
    
    	pop zh
    	pop zl
    	pop r18
    	pop r17
    	out SREG,r17
    	pop r17
    	ret
    ;
    Diese Version hat eine etwas geänderte Übergangstabelle. Sie macht es möglich, anhand der Bits "bZWERT_FLANKE" und "bZWERT_BETAETIGT" auf einfache Weise den aktuellen Zustand der Taste abzufragen.

    Macht Spass mit Dir durch die Geschichte durchzukriechen !

    Ciao,

    mare_crisium

    Edit: P.S.: Könnte es sein, dass Dir meine Art der Parameterübergabe an die Prozedur NEXT0_TAST_ZST fremd ist? Die Register zh:zl, r16 und das T-Flag werwende ich wie die Parameter bei einem Prozeduraufruf in einer Hochsprache, z.B. Pascal:

    Code:
    procedure NEXT0_TAST_ZST( var Taste_Zst : byte;
                                    Tabelle    : Pointer;
                                    betaetigt  : boolean );
    
    Hier ist zugeordnet
    Taste_Zst -> r16, Tabelle -> zh:zl, betaetigt -> T-Flag in SREG

  4. #44
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    Daaaanke und schon die naechste Frage, die ich mir hoffentlich selbst beantwortet habe.
    Meine Anmerkungen bzw. Gedanken dazu sind im Codesegment.

    Code:
    NEXT0_TAST_ZST: 
       push r17 
       in r17,SREG 
       push r17 
       push r18 
       push zl 
       push zh 
    // Bis hier hin kann ich es nachvollziehen. Aber nun wird der Eintrag der 0.Stelle von 0x0011 auf 0x0022 berechnet.
    // ...und was das schlimmste ist, hinterher auch noch richtig ausgelesen... :-()
    // Bei 0x0022 sind doch ganz andere Daten abgelegt, keine aus der Tabelle. Die enden bei 0x0019.
    // >>>Glaube, Du hast es mir schon einmal versucht in "Breiform" zu servieren? :-)
    ; Zeiger auf Anfang der Übergangstabelle berechnen 
       add zl,zl        ; zh:zl verdoppeln, weil einer Adresse im... 
       adc zh,zh        ; .. Programmspeicher immer zwei Bytes entsprechen 
    // Wenn ich den Kommentar von Dir nun richtig interpretiere, wird auf den Speicher 0x0011 - 0x0019 verwiesen und dort stehen die Daten zu je 16Bit.
    // Zumindest sehe ich sie so im Simulator. Dort kann ich sie aber nicht wirklich ansprechen, da der ATmega8515 ein 8Bit-Prozessor ist und somit auch nur 
    // 8Bit mit einmal verarbeiten kann.
    // Bedeutet das die 0. Stelle der Tabelle zwar bei 0x0011 abgelegt, ist aber fuer die CPU bei 0x0022 und 0x0023
    //					1. Stelle der Tabelle zwar bei 0x0012 abgelegt, ist aber fuer die CPU bei 0x0024 und 0x0025
    //					8. Stelle der Tabelle zwar bei 0x0019 abgelegt, ist aber fuer die CPU bei 0x0032 und 0x0033
    //																							"gerade" und "ungerade"
    // Ist es so??? Wenn ja, dann habe ich es doch verstanden. ...jedoch nicht warum Atmel keine 8Bit Speicherstruktur verwendet.
       ; 
       ; 
    ; Information in Bit7 löschen; Tabelle darf nicht länger als 127 Einträge sein 
       andi r16,0x7F    ; 
    
    ; Tabellenlänge einlesen (0-ter Eintrag in der Tabelle) 
       lpm r17,z+       ;  r17 := TBL_LNG einlesen 
    // Hier wird der Tabellenwert eingelesen und der Zeiger von 0x0022 auf die 2. "ungerade" Stelle 0x0023 addiert
       lpm r18,z+       ;  r18 := TBL_LNG einlesen 
    // Hier wird der Tabellenwert eingelesen und der Zeiger von 0x0023 auf die 2.  "gerade"  Stelle 0x0024 addiert - den naechsten Tabelleneintrag
    //
    // >>>Habe ich den "Brei" nun mit dem Laeufel oder mit der Gabel gegessen?
    //
    Edit: P.S.: Könnte es sein, dass Dir meine Art der Parameterübergabe an die Prozedur NEXT0_TAST_ZST fremd ist?
    Die Register zh:zl, r16 und das T-Flag werwende ich wie die Parameter bei einem Prozeduraufruf in einer Hochsprache, z.B. Pascal:
    Fremd? ganz klar... darueber musst Du aber nicht nachdenken. Wenn ich sie dann einmal verstanden habe.. ist sie nicht mehr fremd.
    Ich versuche an die Sache mit gesunden Menschenverstand ran zu gehen.
    Manchmal brauche ich vielleicht etwas laenger, um komplett hinter jedes Problem zukommen.
    Moechte aber auf keinen Fall Dinge, die ich beim ersten mal nicht gleich verstanden habe, ignorieren bzw. hinnehmen.
    Das waere Selbstbetrug und holt mich nur all zu schnell wieder ein.

    - Es ist ein Hobby und es macht Spass mit nur "1" und "0" zu spielen -

    Was ich damit sagen will:
    Es ist voll OK so. und bin wirklich froh, dass Du mich beim Lernen so tatkraeftig unterstuetzt.
    ### Silvio ###

  5. #45
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    genau das
    ... da der ATmega8515 ein 8Bit-Prozessor ist und somit auch nur 8 Bit mit einmal verarbeiten kann.
    ist der springende Punkt . Und das kommt so: Es gibt zwei gängige Arten von Computer-Architektur, die von-Neumann- und die Harvard-Architektur (In Wikipedia sind die beiden Architekturen ganz gut erläutert).

    Bei der v-Neumann-Variante werden Programm- und Datenspeicher über denselben Bus angesprochen. Klar, dass dann die Maschinenbefehle und die Daten im einfachsten Fall dieselbe Anzahl Bits haben. Beispiel: Die alten 8048 bis 8085, 6502, 6800 und Z80 usw. hatten alle eine von-Neumann-Struktur und einen Daten- und Programmbus mit 8Bit Breite. Wenn längere Maschinenbefehle nötig waren, mussten eben zwei Bytes eingelesen werden. Die 8086- und die 68000-Reihe waren auch vom von-Neumann Typ, aber mit 16 Bit-Bus.

    Bei der Harvard-Architektur sind Daten- und Programmspeicher voneinander getrennt, und es gibt separate Busse für Daten und Programm. Der Vorteil ist, dass man Programmbefehle und Daten gleichzeitig einlesen kann. Auch können die Maschinenbefehle mehr Bits haben als ein Datenwort - dadurch kann man auch längere Maschinenbefehle in nur einem Speicherzugriff einlesen. Beispiel: Die ATmega-Prozessoren.

    Also: Der Programmspeicher bei den ATmega-MCs ist in 16-Bit-Worten organisiert. Die Adresse, die einem Label zugeordnet wird, zeigt immer auf den Anfang eines Doppelbytes. Die "lpm"-Anweisung behandelt den Programmspeicher aber so, als wäre er in 8-Bit-Worten organisiert. Deshalb muss man die Labeladressen in zh:zl verdoppeln, um an die richtigen Daten zu kommen. Na? !

    Ciao,

    mare_crisium

  6. #46
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    dann werde ich das Programm mal komplettieren, 2 Zustaende in ein Register unterbringen und in mein naechsten Post setzen.
    ### Silvio ###

  7. #47
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    wollte eigentlich mit diesem Post das fertige Programm praesentieren.
    Leider bin ich da noch auf ein seltsames Problem gestossen:
    Ich habe deshalb den Code von Dir, ohne meine Erweiterungen, im Simulator laufen lassen.(Nur Deine Kommentare asm-konform veraendert)
    Beim 2. Anspringen der ISR(Simulator steht in Zeile 62 "rjmp TIMER1_COMPA_ISR") wird der Eingang PinD5 von High auf Low umgeschaltet.

    edit: Stimmt nicht ganz, das Umschalten passiert schon vorher bei Counter 269 - bevor die ISR angsprungen wird. Genau bei Ueberlauf des Timers auf 1.

    Leider kann ich mir nicht erklaeren, wie es dazu kommt...
    Koenntest Du den Code versuchsweise in Deinem Simulator laufen lassen?
    Code:
    ;***** STK500 Lernprogramm Nr.4e 
    ;*** Aufgabe: die Taste an PinD0 schaltet die zugeordnete LED auf dem STK500 
    ;*** 1. Tastendruck: LEDs einschalten 
    ;*** 2. Tastendruck: LEDs ausschalten 
    ;*** eine Timerroutine liest den TastenStatus ein 
    ;*** zum Entprellen - muss die TimerRoutine 3mal hintereinander den gleichen Wert, 
    ;*** einlesen um einen Tastzustand zu erkennen, Zst_Var 0x03 bzw. 0x00 
    ;*** Taste nicht gedrueckt >>> log 0 in Tast_Stat(r17) 
    ;*** Taste gedrueckt       >>> log 1 in Tast_Stat(r17) 
    ; 
    ; 
    .include "m8515def.inc" 
    .def Temp        = r16         ; Temporary Register 
    .def Tast_Stat   = r17         ; Tasten Status 
    .def Tast_Stat0    = r18 
    .def LED_Stat    = r19         ; LED Status 
    .def Zst_Var     = r20         ; Zustandsvariable - beinhaltet eine 2Bit-Zahl zur Tastzustandserkennung 
    .def LED_Update_SPRR = r21      ; Sperrt die Ausfuehrung von TastenTest wenn, keine neuer TIMER1_OVL voran gegangen    
    ; 
    .equ Timerwert   = 255 ;-1562        ; Timerschritte bis zum Überlauf 
    
    .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 
    
    
    ; Bit-Definitionen für Z-Wert 
    .equ bZWERT_FLANKE = 3      ; Bit3 speichert das "Flankenbit" 
                         ; 0 = "keine Flanke" 
                         ; 1 = "Flanke steht an" 
    .equ bZWERT_BETAETIGT = 0   ; Bit0 speichert den Tastenzustand 
                         ; 0 = "nicht betätigt" 
                         ; 1 = "betätigt" 
    
    ; Pinzuordnung für div. Tasten 
    .equ TASTE0_PIN   = 0 
    .equ TASTE1_PIN = 1 
    .equ TASTE2_PIN = 3         ; die Zuordnung der PINs muss ja nicht mit der TastenNr übereinstimmen! 
    .equ TASTE3_PIN = 2 
    
    ; jetzt kommen die Register, die die Z-Werte der Tasten enthalten. Im Prinzip 
    ; braucht man nur jeweils nur ein Nibble pro Taste. Um die Sache erstmal einfach 
    ; zu halten wird für jede Taste ein ganzes Byte verbraucht. 
    .def rTASTE0_ZST = r15   ; enthält Zustand Taste0 
    .def rTASTE1_ZST = r14   ; enthält Zustand Taste1 
    .def rTASTE2_ZST = r13   ; enthält Zustand Taste2 
    .def rTASTE3_ZST = r12   ; enthält Zustand Taste3 
    
    
    
    ; 
    ;   Vektortabelle 
    ; 
       rjmp RESET                 ;  1 - $000 RESET      External Pin, Power-on Reset, Brown-out, Reset and Watchdog Reset 
       reti                       ;  2 - $001 INT0       External Interrupt Request 0 
       reti                       ;  3 - $002 INT1       External Interrupt Request 1 
       reti                       ;  4 - $003 TIMER1 CAPT Timer/Counter1 Capture Event 
       rjmp TIMER1_COMPA_ISR        ;  5 - $004 TIMER1 COMPA Timer/Counter1 Compare Match A 
       reti                       ;  6 - $005 TIMER1 COMPB Timer/Counter1 Compare Match B 
       reti                       ;  7 - $006 TIMER1 OVF Timer/Counter1 Overflow 
       reti                       ;  8 - $007 TIMER0 OVF Timer/Counter0 Overflow 
       reti                       ;  9 - $008 SPI,       STC   Serial Transfer Complete 
       reti                       ; 10 - $009 USART,     RXC USART, Rx Complete 
       reti                       ; 11 - $00A USART,     UDRE USART Data Register Empty 
       reti                       ; 12 - $00B USART,     TXC USART, Tx Complete 
       reti                       ; 13 - $00C ANA_COMP   Analog Comparator 
       reti                       ; 14 - $00D INT2       External Interrupt Request 2 
       reti                       ; 15 - $00E TIMER0     COMP Timer/Counter0 Compare Match 
       reti                       ; 16 - $00F EE_RDY     EEPROM Ready 
       reti                       ; 17 - $010 SPM_RDY    Store Program memory Ready 
    ; 
    TBL_UEBERGANG_01: 
    .dw 0x0008  ; Tabellenlänge 
    ;                        T = 0               T = 1 
    .dw 0x0200  ;     Z=0 ->      Z=0,Flanke=0     /     Z=2,Flanke=0 
    .dw 0x0308  ;     Z=1 ->      Z=0,Flanke=1     /     Z=3,Flanke=0 
    .dw 0x0400  ;     Z=2 ->      Z=0,Flanke=0     /     Z=4,Flanke=0 
    .dw 0x0501  ;     Z=3 ->      Z=1,Flanke=0     /     Z=5,Flanke=0 
    .dw 0x0602  ;     Z=4 ->      Z=2,Flanke=0     /     Z=6,Flanke=0 
    .dw 0x0703  ;     Z=5 ->      Z=3,Flanke=0     /     Z=7,Flanke=0 
    .dw 0x0F04  ;     Z=6 ->      Z=4,Flanke=0     /     Z=7,Flanke=1 
    .dw 0x0705  ;     Z=7 ->      Z=5,Flanke=0     /     Z=7,Flanke=0 
    
    ; verweist auf den Programmspeicher und zeigt dort im ersten Wort auf den ersten 
    ; definierten Wert(Tabellenlaenge), 
    ; anschliessende Worte beinhalten die festgelegten Werte fortlaufend 
    ; bedeutet in meinem Fall Verweis auf 0x0011 mit 08 00 (.dw 0x0008) 
    ;                             0x0012 mit 02 00 (.dw 0x0200) 
    ;                             0x0013 mit 00 00 (.dw 0x0000) 
    ;                             0x0014 mit 04 00 (.dw 0x0400) 
    ;                             0x0015 mit 08 50 (.dw 0x0580) 
    ;                             0x0016   mit 02 87 (.dw 0x8702) 
    ;                              0x0017 mit 03 07 (.dw 0x0703) 
    ;                             0x0018 mit 00 00 (.dw 0x0000) 
    ;                             0x0019   mit 05 07 (.dw 0x0705) 
    ;          ->>> 
    ;          Der Wert(Tabellenlaenge) ist auch nur ein festgelegter Wert und fuer Programmoperationen wichtig. 
    ;          
    RESET: 
    ; 
       ldi r16, LOW(RAMEND)           ;Stack initialisieren 
       out SPL, r16 
       ldi r16, HIGH(RAMEND) 
       out SPH, r16 
    ; 
       ldi temp,(1<<CS10)|(1<<WGM12)            ; Taktfrequenz Vorteiler 1 gewaehlt (fuer Simaulatortest)          
    ;   ldi temp,(1<<CS10)|(1<<CS12)|(1<<WGM12)   ; Taktfrequenz mit Vorteiler 1024 gewaehlt            
        out TCCR1B,temp 
    ; 
        ldi temp,HIGH(Timerwert) 
       out OCR1AH,temp 
        ldi temp,LOW(Timerwert) 
       out OCR1AL,temp 
    ; 
       ldi temp,(1<<COM1A1)|(0<<COM1A0) 
       out   TCCR1A,temp 
       ldi temp,(1<<OCIE1A)            ; Timer1 Overflow aktivieren 
       out TIMSK,temp          
    ; 
       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 
        
    ; Tastenzustände aller Tasten auf Null setzen 
       clr r16               ; 
       mov rTASTE0_ZST,r16      ; Taste0 und Taste1 zurücksetzen 
       mov rTASTE2_ZST,r16      ; Taste2 und Taste3 zurücksetzen 
       clr Zst_Var 
    ; 
       sei 
    ; 
    ; 
    MAIN: 
       sbrc LED_Update_SPRR,0   ; kein LED_Update, wenn Bit0 ==0 
       rcall LED_Update 
       rjmp MAIN 
    ; 
    LED_Update: 
       cbr LED_Update_SPRR,0   ; loesche Bit0, um LED_Update bis zur naechsten TIMER1_ISR zu sperren 
       ret 
    ; 
    
    ;/*------------------------------------- 
    ;
    ;INTERRUPTDIENST TIMER1_COMPA_ISR 
    ;
    ;Die Interruptdienstprogramm TIMER1_COMPA_ISR wird vom Output-Match-Interrupt von 
    ;Timer1 ausgelöst. Es liest die aktuellen Messwerte der Tasten vom TAST_PIN ab und 
    ;berechnet für jede Taste den neuen Zustand (Z-Wert). 
    ;
    ;Eingansgrössen: 
    ;   keine 
    ;
    ;Ausgangsgrössen: 
    ;   keine 
    ;
    ;geänderte Register 
    ;   keine 
    ;
    ;Anzahl Zyklen 
    ;
    ;*/ 
    
    TIMER1_COMPA_ISR: 
       push r25 
       in r25,SREG 
       push r16 
       push r17 
       push r18 
       push zl 
       push zh 
    
    ;/* 
    ;Das hier hattest Du übersehen: 
    ;Der Zeiger auf die Übergangstabelle muss VOR (!!) dem Aufruf von NEXT0_TAST_ZST 
    ;in die Register zh:zl geladen werden !! 
    ;*/ 
       ldi zl,LOW(TBL_UEBERGANG_01) ; zh:zl := Zeiger auf Übergangstabelle ... 
       ldi zh,HIGH(TBL_UEBERGANG_01) ; ...wird für NEXT0_TAST_ZST gebraucht 
    
    ; Betätigungszustand der Tasten einlesen und der Reihe nach verarbeiten 
       in r18,TAST_PIN      ; r18 := Messwerte aller Pins 
    
    ; Taste0 verarbeiten 
       bst r18,TASTE0_PIN   ; überträgt den Messwert von TASTE0_PIN ins T-Flag von SREG 
       mov r16,rTASTE0_ZST  ; r16 := Z-Wert Taste0 
       andi r16,0x07      ; "Flankenbit" löschen 
       rcall NEXT0_TAST_ZST ; Folgezustand für Taste0 in r16 berechnen 
       mov rTASTE0_ZST,r16   ; neuen Z-Wert in TASTE0_ZST speichern 
    
    ; Taste1 verarbeiten 
       bst r18,TASTE1_PIN   ; überträgt den Messwert von TASTE1_PIN ins T-Flag von SREG 
       mov r16,rTASTE1_ZST  ; r16 := Z-Wert Taste1 
       andi r16,0x07      ; "Flankenbit" löschen 
       rcall NEXT0_TAST_ZST ; Folgezustand für Taste1 in r16 berechnen 
       mov rTASTE1_ZST,r16   ; neuen Z-Wert in TASTE1_ZST speichern 
    
    ; usw... 
    
       sbr LED_Update_SPRR,0            ; Status fuer LED_Update 1 - LED_Update  / 0 - kein LED_Update 
    
       pop zh 
       pop zl 
       pop r18 
       pop r17 
       pop r16 
       out SREG,r25 
       pop r25 
       reti 
    ; 
    ;/*------------------------------------- 
    ;PROZEDUR NEXT0_TAST_ZST 
    ;
    ;Die Prozedur NEXT0_TAST_ZST liest den Folgezustand der Tastenentprellung aus einer 
    ;Übergangstabelle aus. Die Adresse der Tabelle wird in zh:zl übergeben. Der aktuelle 
    ;Zustand (Z-Wert) wird in r16 übergeben. Der aktuelle Tastenzustand (betätigt/nicht 
    ;betätigt) ist im T-Flag von SREG gespeichert. Das Ergebnis wird in r16 zurückgegeben. 
    ;Die Tabelle, darf maximal 127 Einträge enthalten. Der erste Eintrag der Tabelle ist 
    ;die Länge der Tabelle und dient der Bereichsüberprüfung. 
    ;
    ;D.h. der Zeiger auf die Übergangstabelle muss zh:zl geladen werden BEVOR diese 
    ;Prozedur aufgerufen wird!! In diesem Beispiel, bei dem nur eine einzige Übergangstabelle 
    ;im Spiel ist, könnte man zh:zl auch innerhalb von NEXT0_TAST_ZST laden. Um die 
    ;Prozedur auch in Programmen verwenden zu können, in denen mehrere Zustandsautomaten 
    ;nebeneinanderherlaufen, ist es sinnvoll, den Zeiger vorher zu laden. Dann kann je 
    ;nach Aufgabe eine andere Tabelle verwendet werden. Kommt in meinen Programmen öfters 
    ;vor ;-). ;
    ;
    ;Eingansgrössen: 
    ;   r16      : enthält aktuellen Z-Wert der Taste 
    ;   zh:zl   : enthält Zeiger auf die Übergangstabelle 
    ;   SREG (T-Flag) : enthält den aktuellen Messwert der Taste 
    ;      T = 0 : Taste nicht betätigt 
    ;      T = 1 : Taste betätigt 
    ;
    ;Ausgangsgrössen: 
    ;   r16      : enthält den neuen Z-Wert für die Taste 
    ;   zh:zl   unverändert 
    ;   SREG   unverändert 
    ;
    ;geänderte Register 
    ;   r16 
    ;
    ;Anzahl Zyklen 
    ;
    ;*/ 
    
    NEXT0_TAST_ZST: 
       push r17 
       in r17,SREG 
       push r17 
       push r18 
       push zl 
       push zh 
    
    ; Zeiger auf Anfang der Übergangstabelle berechnen 
       add zl,zl        ; zh:zl verdoppeln, weil einer Adresse im... 
       adc zh,zh        ; .. Programmspeicher immer zwei Bytes entsprechen 
       ; FRAGE: Wo wird die Information abgelegt -> im Flashspeicher 
       ; 
       ; 
    ; Information in Bit7 löschen; Tabelle darf nicht länger als 127 Einträge sein 
       andi r16,0x7F    ; 
    
    ; Tabellenlänge einlesen (0-ter Eintrag in der Tabelle) 
       lpm r17,z+       ;  r17 := TBL_LNG einlesen 
       ; 1.Durchgang 
       ; es wird in R16 der Wert 0x19 eingetragen - ??? Die letzte Stelle in der Tabelle (0x0019) 
       ; und in R30(ZL) die 0x01 
       ; 
       ; 2.Durchgang 
       ; es wird in R16 der Wert 0x19 eingetragen - ??? Die letzte Stelle in der Tabelle (0x0019) 
       ; und in R30(ZL) die 0x01 
       ; 
       ; KLAR; Du hattest den Zeiger nicht gesetzt! 
       ; 
       ; 
       lpm r18,z+       ;  zweites Byte überlesen, wird nicht gebraucht 
    
    ; Bereichsprüfung ( r17 < TBL_LNG ) 
       cp r16,r17       ; Tabellenindex mit TBL_LNG vergleichen 
       brlt NXT0ZST_00  ; Sprung, wenn Tabellenindex iO 
    
    ; Fehler: Tabellenindex ist zu gross 
       clr r16 ; Zustand auf Null setzen 
       rjmp NXT0ZST_EXIT ; fertig 
    
    NXT0ZST_00: 
    ; Tabellenindex im zulässigen Bereich 
       clr r17 ; 
       add zl,r16       ; Index zweimal zum Zeiger addieren, weil... 
       adc zh,r17       ; ... in der Tabelle... 
       add zl,r16       ; ... 2-Byte-Worte gespeichert sind. 
       adc zh,r17       ; zh:zl := Zeiger auf Tabelleneintrag    
       lpm r16,z+       ; r16 := Folgezustand für T=0 
       lpm r17,z        ; r17 := Folgezustand für T=1 
       brtc NXT0ZST_EXIT ; fertig, wenn T = 0 
    
    ; T = 1, d.h. Taste betätigt 
       mov r16,r17      ; zweiten Eintrag als Folgezustand verwenden 
    
    NXT0ZST_EXIT: 
    ;   sbr LED_Update_SPRR,0            ; Status fuer LED_Update 1 - LED_Update  / 0 - kein LED_Update 
    ; diese Zeile gehört in den Interruptdienst! 
    
       pop zh 
       pop zl 
       pop r18 
       pop r17 
       out SREG,r17 
       pop r17 
       ret 
    ;
    ### Silvio ###

  8. #48
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    das liegt an diesen Zeilen
    Code:
      ldi temp,(1<<COM1A1)|(0<<COM1A0)
       out   TCCR1A,temp
    Laut Tabelle 50 auf Seite 119 des Datenblatts sagst Du Deinem 8515 damit, dass er beim Erreichen des Vergleichswortes den Pin OC1A auf "low" setzen soll ("Clear OC1A/OC1B on Compare Match (Set output to low level)").

    Der Pin OC1A ist identisch mit Pin PD5. Du kannst das Umschalten aber nur erkennen, wenn der Pin vorher auf "high" gesetzt war. Ich nehme an, das ist der Grund, weshalb Du die Funktion erst beim dritten Interrupt sehen kannst. - Diese Doppelbelegungen der Pins können manchmal ziemlich tückisch sein !

    Du kannst die Funktion abschalten, indem Du die Bits COM1A1 und COM1A0 beide auf Null stellst.

    Ciao,

    mare_crisium

  9. #49
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    super...
    Das wars. Mit den Timerfunktionen muss ich mich genauer auseinander setzen.
    ### Silvio ###

  10. #50
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    hatte heute mal wieder genuegend Zeit um mich den schoenen Dingen im Leben zu widmen...
    Hier nun das Ergebnis:
    Code:
    ;***** STK500 Lernprogramm Nr.4e 
    ;*** Aufgabe: die Taste an PinD0 schaltet die zugeordnete LED auf dem STK500 
    ;*** 1. Tastendruck: LEDs einschalten 
    ;*** 2. Tastendruck: LEDs ausschalten 
    ;*** eine Timerroutine liest den TastenStatus ein 
    ;*** zum Entprellen - muss die TimerRoutine 3mal hintereinander den gleichen Wert, 
    ;*** einlesen um einen Tastzustand zu erkennen
    ;*** die Flanken der Tastzustaende werden in rTastFlanken gesammelt und schalten die LEDs um
    ;*** Taste nicht gedrueckt >>> log 0  
    ;*** Taste gedrueckt       >>> log 1  
    ; 
    ; 
    .include "m8515def.inc" 
    .def Temp            = r16      ; Temporary Register 
    .def rTastFlanken     = r20     ; Zustandsvariable - beinhaltet eine 2Bit-Zahl zur Tastzustandserkennung 
    .def rLED_Update_SPRR = r21     ; Sperrt die Ausfuehrung von TastenTest wenn, keine neuer TIMER1_OVL voran gegangen    
    ; 
    .equ Timerwert   = 155 ;-24999       ; Timerschritte bis zum Überlauf 0,2 sec
    ;
    .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 
    ;                
    ; Pinzuordnung für div. Tasten 
    .equ TASTE0_PIN = 0 
    .equ TASTE1_PIN = 1 
    .equ TASTE2_PIN = 2             ; die Zuordnung der PINs muss ja nicht mit der TastenNr übereinstimmen! 
    .equ TASTE3_PIN = 3
    .equ TASTE4_PIN = 4
    .equ TASTE5_PIN = 5
    .equ TASTE6_PIN = 6
    .equ TASTE7_PIN = 7
    ;
    ; jetzt kommen die Register, die die Z-Werte der Tasten enthalten.. 
    .def rTASTE1_0_ZST = r15 ; enthält Zustand Taste1 im oberen Nibble und 0 im unteren Nibble
    .def rTASTE3_2_ZST = r14 ; enthält Zustand Taste3 im oberen Nibble und 2 im unteren Nibble 
    .def rTASTE5_4_ZST = r13 ; enthält Zustand Taste5 im oberen Nibble und 4 im unteren Nibble 
    .def rTASTE7_6_ZST = r12 ; enthält Zustand Taste7 im oberen Nibble und 6 im unteren Nibble 
    ; 
    ;   Vektortabelle 
    ; 
       rjmp RESET                 ;  1 - $000 RESET      External Pin, Power-on Reset, Brown-out, Reset and Watchdog Reset 
       reti                       ;  2 - $001 INT0       External Interrupt Request 0 
       reti                       ;  3 - $002 INT1       External Interrupt Request 1 
       reti                       ;  4 - $003 TIMER1 CAPT Timer/Counter1 Capture Event 
       rjmp TIMER1_COMPA_ISR      ;  5 - $004 TIMER1 COMPA Timer/Counter1 Compare Match A 
       reti                       ;  6 - $005 TIMER1 COMPB Timer/Counter1 Compare Match B 
       reti                       ;  7 - $006 TIMER1 OVF Timer/Counter1 Overflow 
       reti                       ;  8 - $007 TIMER0 OVF Timer/Counter0 Overflow 
       reti                       ;  9 - $008 SPI,       STC   Serial Transfer Complete 
       reti                       ; 10 - $009 USART,     RXC USART, Rx Complete 
       reti                       ; 11 - $00A USART,     UDRE USART Data Register Empty 
       reti                       ; 12 - $00B USART,     TXC USART, Tx Complete 
       reti                       ; 13 - $00C ANA_COMP   Analog Comparator 
       reti                       ; 14 - $00D INT2       External Interrupt Request 2 
       reti                       ; 15 - $00E TIMER0     COMP Timer/Counter0 Compare Match 
       reti                       ; 16 - $00F EE_RDY     EEPROM Ready 
       reti                       ; 17 - $010 SPM_RDY    Store Program memory Ready 
    ; 
    TBL_UEBERGANG_01: 
    .dw 0x0008  ; Tabellenlänge 
    ;                        T = 0               T = 1 
    .dw 0x0200  ;     Z=0 ->      Z=0,Flanke=0     /     Z=2,Flanke=0 
    .dw 0x0308  ;     Z=1 ->      Z=0,Flanke=1     /     Z=3,Flanke=0 
    .dw 0x0400  ;     Z=2 ->      Z=0,Flanke=0     /     Z=4,Flanke=0 
    .dw 0x0501  ;     Z=3 ->      Z=1,Flanke=0     /     Z=5,Flanke=0 
    .dw 0x0602  ;     Z=4 ->      Z=2,Flanke=0     /     Z=6,Flanke=0 
    .dw 0x0703  ;     Z=5 ->      Z=3,Flanke=0     /     Z=7,Flanke=0 
    .dw 0x0F04  ;     Z=6 ->      Z=4,Flanke=0     /     Z=F,Flanke=1 
    .dw 0x0705  ;     Z=7 ->      Z=5,Flanke=0     /     Z=7,Flanke=0 
    
    ;
    RESET: 
    ; 
       ldi r16, LOW(RAMEND)           ;Stack initialisieren 
       out SPL, r16 
       ldi r16, HIGH(RAMEND) 
       out SPH, r16 
    ; 
       ldi temp,(1<<CS10)|(1<<WGM12)            ; Taktfrequenz Vorteiler 1 gewaehlt (fuer Simaulatortest)          
    ;   ldi temp,(1<<CS10)|(1<<CS11)|(1<<WGM12)   ; Taktfrequenz mit Vorteiler 64 gewaehlt            
        out TCCR1B,temp 
    ; 
        ldi temp,HIGH(Timerwert) 
       out OCR1AH,temp 
        ldi temp,LOW(Timerwert) 
       out OCR1AL,temp 
    ; 
       ldi temp,(0<<COM1A1)|(0<<COM1A0) 
       out   TCCR1A,temp 
       ldi temp,(1<<OCIE1A)    ; Timer1 Overflow aktivieren 
       out TIMSK,temp          
    ; 
       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 
    ;    
    ; Tastenzustände aller Tasten auf Null setzen 
       clr r16               ; 
       mov rTASTE1_0_ZST,r16      ; Taste0 und Taste1 zurücksetzen 
       mov rTASTE5_4_ZST,r16      ; Taste2 und Taste3 zurücksetzen 
    ; 
       sei 
    ; 
    MAIN: 
       sbrc rLED_Update_SPRR,0   ; kein LED_Update, wenn Bit0 ==0 
       rcall LED_Update 
       rjmp MAIN 
    ; 
    LED_Update: 
    ;
    ; LED_PORT auslesen - mit TastenZustand verarbeiten - LED_PORT ausgeben
       push temp
       in temp, LED_PORT         ; LED_PORT einlesen
       eor temp, rTastFlanken    ; toggle das Bit im LED_PORT fuer das eine Flanke in rTastFlanken ansteht
       out LED_PORT,temp         ; LED_PORT augeben
       cbr rLED_Update_SPRR,1    ; loesche Bit0, um LED_Update bis zur naechsten TIMER1_ISR zu sperren 
       clr rTastFlanken          ; setze rTastFlanken zum erneuten Beschreiben auf 0x00
       pop temp
       ret 
    ; 
    
    /*------------------------------------- 
    
    INTERRUPTDIENST TIMER1_COMPA_ISR 
    
    Die Interruptdienstprogramm TIMER1_COMPA_ISR wird vom Output-Match-Interrupt von 
    Timer1 ausgelöst. Es liest die aktuellen Messwerte der Tasten vom TAST_PIN ab und 
    berechnet für jede Taste den neuen Zustand (Z-Wert). 
    
    Eingansgrössen: 
       keine 
    
    Ausgangsgrössen: 
       keine 
    
    geänderte Register 
       keine 
    
    Anzahl Zyklen 
    
    */ 
    
    TIMER1_COMPA_ISR: 
       push r25 
       in r25,SREG 
       push r16 
       push r17 
       push r18 
       push zl 
       push zh 
    
    /* 
    Das hier hattest Du übersehen: 
    Der Zeiger auf die Übergangstabelle muss VOR (!!) dem Aufruf von NEXT0_TAST_ZST 
    in die Register zh:zl geladen werden !! 
    */ 
       ldi zl,LOW(TBL_UEBERGANG_01)  ; zh:zl := Zeiger auf Übergangstabelle ... 
       ldi zh,HIGH(TBL_UEBERGANG_01) ; ...wird für NEXT0_TAST_ZST gebraucht 
    
    ; Betätigungszustand der Tasten einlesen und der Reihe nach verarbeiten 
       in r18,TAST_PIN         ; r18 := Messwerte aller Pins 
       com r18                 ; invertier r18
    ;
    ; Taste0 und Taste1 verarbeiten und in Register TASTE1_0_ZST 
    ;
    ; Taste0 verarbeiten (!!! Achtung unteres Nibble von rTASTE1_0_ZST 0bxxxx????)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE0_PIN      ; überträgt den Messwert von TASTE0_PIN ins T-Flag von SREG 
    ; lade TASTE1_0_ZST in R19 und loesche MSB (oberes Nibble)
       mov r16,rTASTE1_0_ZST   ; r16 := Z-Wert Taste0
       sbrc r16,3              ; wenn Flankenbit gesetzt setze Bit1 in rTastFlanken
       sbr rTastFlanken,0b00000001       ; 
       andi r16,0x07           ; "Flankenbit" und MSB löschen 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste0 in r16 berechnen 
       andi r16,0x0F           ; loesche MSB fuer or
    ; schiebe rTASTE1_0_ZST in R19 und loesche LSB fuer neues Z von Taste0
       mov r19, rTASTE1_0_ZST
       andi r19,0xF0           ; loesche altes Z (LSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE1_0_ZST
       mov rTASTE1_0_ZST,r16   ; neuen Z-Wert von Taste0 in TASTE1_0_ZST speichern 
    ;
    ; Taste1 verarbeiten (!!! Achtung oberes Nibble von rTASTE1_0_ZST 0b????xxxx)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE1_PIN      ; überträgt den Messwert von TASTE1_PIN ins T-Flag von SREG 
    ; lade TASTE1_0_ZST in R19 und loesche MSB (oberes Nibble)
       mov r19, rTASTE1_0_ZST
       swap r19                ; tausche MSB mit LSB
       sbrc r19,3              ; wenn Flankenbit gesetzt setze Bit2 in rTastFlanken
       sbr rTastFlanken,0b00000010       ; 
       andi r19,0x07           ; loesche MSB (eigentlichliches LSB) und "Flankenbit"
       mov r16,r19             ; r16 := Z-Wert Taste1 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste1 in r16 berechnen 
       swap r16                ; tausche MSB mit LSB
    ; schiebe rTASTE1_0_ZST in R19 und loesche MSB fuer neues Z von Taste1
       mov r19, rTASTE1_0_ZST
       andi r19,0x0F           ; loesche altes Z (MSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE1_0_ZST
       mov rTASTE1_0_ZST,r16   ; neuen Z-Wert von Taste1 in TASTE1_0_ZST speichern 
    ;
    ; Taste2 und Taste3 verarbeiten und in Register TASTE3_2_ZST 
    ;
    ; Taste2 verarbeiten (!!! Achtung unteres Nibble von rTASTE3_2_ZST 0bxxxx????)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE2_PIN      ; überträgt den Messwert von TASTE2_PIN ins T-Flag von SREG 
    ; lade TASTE3_2_ZST in R19 und loesche MSB (oberes Nibble)
       mov r16,rTASTE3_2_ZST   ; r16 := Z-Wert Taste0
       sbrc r16,3              ; wenn Flankenbit gesetzt setze Bit3 in rTastFlanken
       sbr rTastFlanken,0b00000100       ; 
       andi r16,0x07           ; "Flankenbit" und MSB löschen 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste2 in r16 berechnen 
       andi r16,0x0F           ; loesche MSB fuer or
    ; schiebe rTASTE3_2_ZST in R19 und loesche LSB fuer neues Z von Taste2
       mov r19, rTASTE3_2_ZST
       andi r19,0xF0           ; loesche altes Z (LSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE3_2_ZST
       mov rTASTE3_2_ZST,r16   ; neuen Z-Wert von Taste2 in TASTE3_2_ZST speichern 
    ;
    ; Taste3 verarbeiten (!!! Achtung oberes Nibble von rTASTE3_2_ZST 0b????xxxx)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE3_PIN      ; überträgt den Messwert von TASTE3_PIN ins T-Flag von SREG 
    ; lade TASTE3_2_ZST in R19 und loesche MSB (oberes Nibble)
       mov r19, rTASTE3_2_ZST
       swap r19                ; tausche MSB mit LSB
       sbrc r19,3              ; wenn Flankenbit gesetzt setze Bit4 in rTastFlanken
       sbr rTastFlanken,0b00001000       ; 
       andi r19,0x07           ; loesche MSB (eigentlichliches LSB) und "Flankenbit"
       mov r16,r19             ; r16 := Z-Wert Taste1 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste3 in r16 berechnen 
       swap r16                ; tausche MSB mit LSB
    ; schiebe rTASTE3_2_ZST in R19 und loesche MSB fuer neues Z von Taste1
       mov r19, rTASTE3_2_ZST
       andi r19,0x0F           ; loesche altes Z (MSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE3_2_ZST
       mov rTASTE3_2_ZST,r16   ; neuen Z-Wert von Taste3 in TASTE3_2_ZST speichern 
    ;
    ; Taste5 und Taste4 verarbeiten und in Register TASTE5_4_ZST 
    ;
    ; Taste4 verarbeiten (!!! Achtung unteres Nibble von rTASTE5_4_ZST 0bxxxx????)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE4_PIN      ; überträgt den Messwert von TASTE4_PIN ins T-Flag von SREG 
    ; lade TASTE5_4_ZST in R19 und loesche MSB (oberes Nibble)
       mov r16,rTASTE5_4_ZST   ; r16 := Z-Wert Taste0
       sbrc r16,3              ; wenn Flankenbit gesetzt setze Bit5 in rTastFlanken
       sbr rTastFlanken,0b00010000       ; 
       andi r16,0x07           ; "Flankenbit" und MSB löschen 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste4 in r16 berechnen 
       andi r16,0x0F           ; loesche MSB fuer or
    ; schiebe rTASTE5_4_ZST in R19 und loesche LSB fuer neues Z von Taste4
       mov r19, rTASTE5_4_ZST
       andi r19,0xF0           ; loesche altes Z (LSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE1_0_ZST
       mov rTASTE5_4_ZST,r16   ; neuen Z-Wert von Taste4 in TASTE5_4_ZST speichern 
    ;
    ; Taste5 verarbeiten (!!! Achtung oberes Nibble von rTASTE5_4_ZST 0b????xxxx)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE5_PIN      ; überträgt den Messwert von TASTE5_PIN ins T-Flag von SREG 
    ; lade TASTE5_4_ZST in R19 und loesche MSB (oberes Nibble)
       mov r19, rTASTE5_4_ZST
       swap r19                ; tausche MSB mit LSB
       sbrc r19,3              ; wenn Flankenbit gesetzt setze Bit6 in rTastFlanken
       sbr rTastFlanken,0b00100000       ; 
       andi r19,0x07           ; loesche MSB (eigentlichliches LSB) und "Flankenbit"
       mov r16,r19             ; r16 := Z-Wert Taste1 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste1 in r16 berechnen 
       swap r16                ; tausche MSB mit LSB
    ; schiebe rTASTE5_4_ZST in R19 und loesche MSB fuer neues Z von Taste5
       mov r19, rTASTE5_4_ZST
       andi r19,0x0F           ; loesche altes Z (MSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE5_4_ZST
       mov rTASTE5_4_ZST,r16   ; neuen Z-Wert von Taste5 in TASTE5_4_ZST speichern 
    ;
    ; Taste6 und Taste7 verarbeiten und in Register TASTE7_6_ZST 
    ;
    ; Taste6 verarbeiten (!!! Achtung unteres Nibble von rTASTE7_6_ZST 0bxxxx????)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE6_PIN      ; überträgt den Messwert von TASTE6_PIN ins T-Flag von SREG 
    ; lade TASTE7_6_ZST in R19 und loesche MSB (oberes Nibble)
       mov r16,rTASTE7_6_ZST   ; r16 := Z-Wert Taste0
       sbrc r16,3              ; wenn Flankenbit gesetzt setze Bit7 in rTastFlanken
       sbr rTastFlanken,0b01000000      ; 
       andi r16,0x07           ; "Flankenbit" und MSB löschen 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste6 in r16 berechnen 
       andi r16,0x0F           ; loesche MSB fuer or
    ; schiebe rTASTE7_6_ZST in R19 und loesche LSB fuer neues Z von Taste6
       mov r19, rTASTE7_6_ZST
       andi r19,0xF0           ; loesche altes Z (LSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE7_6_ZST
       mov rTASTE7_6_ZST,r16   ; neuen Z-Wert in TASTE6_ZST speichern 
    ;
    ; Taste7 verarbeiten (!!! Achtung oberes Nibble von rTASTE7_6_ZST 0b????xxxx)
       clr r19				   ; Register r19 fuer temporaeres Register fuer swap
       bst r18,TASTE7_PIN      ; überträgt den Messwert von TASTE7_PIN ins T-Flag von SREG 
    ; lade TASTE7_6_ZST in R19 und loesche MSB (oberes Nibble)
       mov r19, rTASTE7_6_ZST
       swap r19                ; tausche MSB mit LSB
       sbrc r19,3              ; wenn Flankenbit gesetzt setze Bit8 in rTastFlanken
       sbr rTastFlanken,0b10000000       ; 
       andi r19,0x07           ; loesche MSB (eigentlichliches LSB) und "Flankenbit"
       mov r16,r19             ; r16 := Z-Wert Taste1 
       rcall NEXT0_TAST_ZST    ; Folgezustand für Taste7 in r16 berechnen 
       swap r16                ; tausche MSB mit LSB
    ; schiebe rTASTE7_6_ZST in R19 und loesche MSB fuer neues Z von Taste7
       mov r19, rTASTE7_6_ZST
       andi r19,0x0F           ; loesche altes Z (MSB)
       or r16, r19             ; vereine MSB und LSB in rTASTE7_6_ZST
       mov rTASTE7_6_ZST,r16   ; neuen Z-Wert von Taste7 rTASTE7_6_ZST speichern 
    ;
    ;
    ;
       sbr rLED_Update_SPRR,1   ; Status fuer LED_Update 
    
       pop zh 
       pop zl 
       pop r18 
       pop r17 
       pop r16 
       out SREG,r25 
       pop r25 
       reti 
    ; 
    /*------------------------------------- 
    
    PROZEDUR NEXT0_TAST_ZST 
    
    Die Prozedur NEXT0_TAST_ZST liest den Folgezustand der Tastenentprellung aus einer 
    Übergangstabelle aus. Die Adresse der Tabelle wird in zh:zl übergeben. Der aktuelle 
    Zustand (Z-Wert) wird in r16 übergeben. Der aktuelle Tastenzustand (betätigt/nicht 
    betätigt) ist im T-Flag von SREG gespeichert. Das Ergebnis wird in r16 zurückgegeben. 
    Die Tabelle, darf maximal 127 Einträge enthalten. Der erste Eintrag der Tabelle ist 
    die Länge der Tabelle und dient der Bereichsüberprüfung. 
    
    D.h. der Zeiger auf die Übergangstabelle muss zh:zl geladen werden BEVOR diese 
    Prozedur aufgerufen wird!! In diesem Beispiel, bei dem nur eine einzige Übergangstabelle 
    im Spiel ist, könnte man zh:zl auch innerhalb von NEXT0_TAST_ZST laden. Um die 
    Prozedur auch in Programmen verwenden zu können, in denen mehrere Zustandsautomaten 
    nebeneinanderherlaufen, ist es sinnvoll, den Zeiger vorher zu laden. Dann kann je 
    nach Aufgabe eine andere Tabelle verwendet werden. Kommt in meinen Programmen öfters 
    vor ;-). 
    
    Eingansgrössen: 
       r16      : enthält aktuellen Z-Wert der Taste 
       zh:zl   : enthält Zeiger auf die Übergangstabelle 
       SREG (T-Flag) : enthält den aktuellen Messwert der Taste 
          T = 0 : Taste nicht betätigt 
          T = 1 : Taste betätigt 
    
    Ausgangsgrössen: 
       r16      : enthält den neuen Z-Wert für die Taste 
       zh:zl   unverändert 
       SREG   unverändert 
    
    geänderte Register 
       r16 
    
    Anzahl Zyklen 
    
    */ 
    
    NEXT0_TAST_ZST: 
       push r17 
       in r17,SREG 
       push r17 
       push r18 
       push zl 
       push zh 
    
    ; Zeiger auf Anfang der Übergangstabelle berechnen 
       add zl,zl        ; zh:zl verdoppeln, weil einer Adresse im... 
       adc zh,zh        ; .. Programmspeicher immer zwei Bytes entsprechen 
       ; 
       ; 
    ; Information in Bit7 löschen; Tabelle darf nicht länger als 127 Einträge sein 
       andi r16,0x7F    ; 
    
    ; Tabellenlänge einlesen (0-ter Eintrag in der Tabelle) 
       lpm r17,z+       ;  r17 := TBL_LNG einlesen 
       ; 
       lpm r18,z+       ;  zweites Byte überlesen, wird nicht gebraucht 
    
    ; Bereichsprüfung ( r17 < TBL_LNG ) 
       cp r16,r17       ; Tabellenindex mit TBL_LNG vergleichen 
       brlt NXT0ZST_00  ; Sprung, wenn Tabellenindex iO (wenn r16 kleiner r17)
    
    ; Fehler: Tabellenindex ist zu gross 
       clr r16 ; Zustand auf Null setzen 
       rjmp NXT0ZST_EXIT ; fertig 
    
    NXT0ZST_00: 
    ; Tabellenindex im zulässigen Bereich 
       clr r17 ; 
       add zl,r16       ; Index zweimal zum Zeiger addieren, weil... 
       adc zh,r17       ; ... in der Tabelle... 
       add zl,r16       ; ... 2-Byte-Worte gespeichert sind. 
       adc zh,r17       ; zh:zl := Zeiger auf Tabelleneintrag    
       lpm r16,z+       ; r16 := Folgezustand für T=0 
       lpm r17,z        ; r17 := Folgezustand für T=1 
       brtc NXT0ZST_EXIT ; fertig, wenn T = 0 
    
    ; T = 1, d.h. Taste betätigt 
       mov r16,r17      ; zweiten Eintrag als Folgezustand verwenden 
    
    NXT0ZST_EXIT: 
    
       pop zh 
       pop zl 
       pop r18 
       pop r17 
       out SREG,r17 
       pop r17 
       ret 
    ;
    Im Simulator schaut es eigentlich so aus, ich es erwartet habe.
    Aber als ich das Programm zum finalen Test in den µC uebertragen hatte, ging erst einaml gar nichts..
    Nach ein paar Veraenderungen am Timer, stellte sich dann aber doch ein wenig Freude ein.
    Leider konnte ich meinen Fehler bis jetzt noch nicht lokalisieren.
    Mit meinen 8MHz Quarz wollte ich alle 0,2 sec eine ISR ausloesen.
    Entweder meine Timerberechnung sind falsch, oder meine Timereinstellungen, oder mein STK500 betreibt den µC doch nicht mit dem Quarz..ODER?
    Den Vorteiler habe ich mit 64 fuer den Timer1 gewaehlt. und vorladen wollte ich ihn mit -24999 dmit ich ca. auf 0,2 sec komme.
    die Einstellungen habe ic hso gewaehlt:
    Code:
       ldi temp,(1<<CS10)|(1<<CS11)|(1<<WGM12)   ; Taktfrequenz mit Vorteiler 64 gewaehlt            
       out TCCR1B,temp 
    ; 
       ldi temp,HIGH(Timerwert) 
       out OCR1AH,temp 
       ldi temp,LOW(Timerwert) 
       out OCR1AL,temp
    Desweiteren wollte ich noch eine "Gedaechtnisfunktion" mit einbauen - den letzten LED-Stand ins EEPROM uebertragen. So soll der letzte Status nach dem
    Aus- und wieder Einschalten erhalten und geschalten werden.
    ????
    Wie spreche ich das EEPROM genau an?
    ### Silvio ###

Seite 5 von 14 ErsteErste ... 34567 ... LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests