;*******************************************************************************
;*
;*	Titel:	Beispiel zur Interrupt-Steuerung (B300_int_example.asm)
;*	Datum:	30/12/09		Version:	0.4 (03/01/13)
;*	Autor:	www.weigu.lu
;*
;*	Informationen zur Beschaltung:
;*	Prozessor:	ATmega32	Quarzfrequenz:	16MHz
;*	Eingaenge:	entprellter Taster an PORTD2 (INT0)
;*			entprellter Taster an PORTD3 (INT1)
;*	Ausgaenge:	LED an PORTC0
;*
;*	Informationen zur Funktionsweise:
;*	
;*	Eine steigende Flanke an INT0 soll LED einschalten.
;*	Eine fallende Flanke an INT1 soll die LED ausschalten.
;*	Im Hauptprogramm blinkt eine LED
;*			
;*******************************************************************************

;-------------------------------------------------------------------------------
;       Einbinden der controllerspezifischen Definitionsdatei
;-------------------------------------------------------------------------------
.NOLIST                         ;List-Output ausschalten
.INCLUDE "m32def.inc"           ;AVR-Definitionsdatei einbinden
.LIST                           ;List-Output wieder einschalten

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;       Programmspeicher (FLASH)     Programmstart nach RESET ab Adr. 0x0000
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.CSEG                           ;was ab hier folgt kommt in den FLASH-Speicher
.ORG    0x0000                  ;Programm beginnt an der FLASH-Adresse 0x0000
RESET:  rjmp    INIT            ;springe nach INIT (ueberspringe ISR Vektoren)

;-------------------------------------------------------------------------------
;       Sprungadressen fuer die Interrupts organisieren (ISR VECTORS)   
;-------------------------------------------------------------------------------
; Vektortabelle (im Flash-Speicher)
.ORG    INT0addr                ;interner Vektor für INT0 (alt.: .ORG 0x0002)
        rjmp    ISR_I0          ;Springe zur ISR von INT0
.ORG    INT1addr                ;interner Vektor für INT1 (alt.: .ORG 0x0004)
        rjmp    ISR_I1          ;Springe zur ISR von INT1

;-------------------------------------------------------------------------------
;       Initialisierungen und eigene Definitionen
;-------------------------------------------------------------------------------
.ORG    INT_VECTORS_SIZE        ;Platz fuer ISR Vektoren lassen
INIT:
.DEF	Zero = r15		;Register 1 wird zum Rechnen benoetigt
	clr	r15		;und mit Null belegt
.DEF	Tmp1 = r16		;Register 16 dient als erster Zwischenspeicher
.DEF	Tmp2 = r17		;Register 17 dient als zweiter Zwischenspeicher
.DEF	Cnt1 = r18              ;Register 18 dient als Zaehler
.DEF    WL = r24                ;Register 24 und 25 dienen als universelles
.DEF    WH = r25                ;Doppelregister W und zur Parameteruebergabe
.DEF    W = r24

.EQU    LEDI = 0                ;LED ISR wird an Pin 0 angeschlossen
.EQU    LEDM = 1                ;LED MAIN an Pin 1 angeschlossen

	;Stapel initialisieren (fuer Unterprogramme bzw. Interrupts)
	ldi	Tmp1,LOW(RAMEND) ;RAMEND (SRAM) ist in der Definitions-
	out	SPL,Tmp1         ;datei festgelegt
	ldi	Tmp1,HIGH(RAMEND)
	out	SPH,Tmp1

	;externe Interrupts initialisieren
        in      Tmp1,MCUCR              ;MCU Control Register einlesen
        andi    Tmp1,0b11111011         ;ISC11=1, ISC10=0 => fallende Flanke
        ori     Tmp1,0b00001011         ;ISC01=1, ISC00=1 => steigende Flanke
        out     MCUCR,Tmp1              ;Wert ins MCUCR zurückschreiben

        in      Tmp1,GICR               ;General Int. Control Reg. einlesen
        ori     Tmp1,0b11000000         ;INT1=1, INT0=1 => INT0+INT1 aktivieren
        out	GICR,Tmp1		;GICR setzen

        ;Port C und Port D konfigurieren
        cbi     DDRD,2                  ;INT0 = Eingang
        cbi     DDRD,3                  ;INT1 = Eingang
        sbi     DDRC,LEDI               ;Richtungsbit fuer LEDI auf Ausgang
        sbi     DDRC,LEDM               ;Richtungsbit fuer LEDM auf Ausgang

	;globales Interrupt-Flag setzen (Int. erlauben)
	sei

;-------------------------------------------------------------------------------
;	Hauptprogramm
;-------------------------------------------------------------------------------
MAIN:	sbi	PORTC,LEDM		;LED im Sekundentakt toggeln
	rcall	W500MS
	cbi	PORTC,LEDM
	rcall	W500MS
	rjmp	MAIN			;Endlosschleife

;-------------------------------------------------------------------------------
;	Unterprogramme und Interrupt-Behandlungsroutinen 
;-------------------------------------------------------------------------------
; Interrupt-Behandlungsroutine von INT0
ISR_I0:	push	r16		;benutzte Reg. retten (r16 = Zwischenspeicher)
	in	r16,SREG	;Statusregister einlesen
	push	r16		;Statusregister retten

	sbi	PORTC,LEDI      ;LED ein

	pop	r16		;Werte der geretteten Register wieder-
	out	SREG,r16	;herstellen
	pop	r16		
	reti			;Ruecksprung ins Hauptprogramm aus einer
				;Interrupt-Behandlungsroutine

; Interrupt-Behandlungsroutine von INT1
ISR_I1:	push	r16		;benutzte Reg. retten (r16 = Zwischenspeicher)
	in	r16,SREG	;Statusregister einlesen
	push	r16		;Statusregister retten

	cbi     PORTC,LEDI      ;LED aus

	pop	r16		;Werte der geretteten Register wieder-
	out	SREG,r16	;herstellen
	pop	r16		
	reti			;Ruecksprung ins Hauptprogramm aus einer
				;Interrupt-Behandlungsroutine

.INCLUDE "lib/SR_TIME_16M.asm"	;Zeitschleifenbibliothek einbinden
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.EXIT                           ;Ende des Quelltextes
