;*******************************************************************************
;*
;*	Titel:	Unterprogramme zur Darstellung von Daten auf einer 4-stelligen
;*		7-Segment-Anzeige (SR_NUMDISPLAY.asm)
;*
;*      Datum:  22/11/11        Version:        0.3
;*      Autor:  WEIGU
;*
;*      Informationen zur Beschaltung:
;*      Prozessor:      ATmega32A        Quarzfrequenz:  16MHz
;*      Eingaenge:
;*	Ausgaenge:	Pin 0-7 (a-g, DP) am SegPort
;*			4 Pin am DigPort
;*
;*	Informationen zur Funktionsweise:
;*	
;*	Eine Zeitschleifenbibliothek (UP W1ms) muss eingebunden sein.
;*	
;*	Unterprogramme:
;*	
;*	D7SINI		Muss im Hauptprogramm in der Initialisierungsphase 
;*			aufgerufen werden (Initialisiert Portpins als Ausgang)
;*	D7SHEX		Der Inhalt des Doppelregisters W (r25:r24) wird waehrend
;*			einer definierten Zeit in Millisekunden in Hex am 
;*			Display ausgegeben. Die Dekodiertabelle befindet sich im
;*			Programmspeicher. Die Hexstelle addiert zur Anfangs-
;*			adresse dient als Adresszeiger.
;*			
;*			      
;*      Copyright (c) 2011   Guy WEILER         weigu[at]weigu[dot]lu
;*
;*      Hiermit wird unentgeltlich, jeder Person, die eine Kopie der Software
;*      und der zugehoerigen Dokumentationen (die "Software") erhaelt, die
;*      Erlaubnis erteilt, uneingeschraenkt zu benutzen, inklusive und ohne
;*      Ausnahme, dem Recht, sie zu verwenden, kopieren, aendern, fusionieren,
;*      verlegen, verbreiten, unterlizenzieren und/oder zu verkaufen, und
;*      Personen, die diese Software erhalten, diese Rechte zu geben, unter den
;*      folgenden Bedingungen:
;*
;*      ;Der obige Urheberrechtsvermerk und dieser Erlaubnisvermerk sind in alle
;*      ;Kopien oder Teilkopien der Software beizulegen.
;*      ;
;*      ;DIE SOFTWARE WIRD OHNE JEDE AUSDRUECKLICHE ODER IMPLIZIERTE GARANTIE
;*      ;BEREITGESTELLT, EINSCHLIESSLICH DER GARANTIE ZUR BENUTZUNG FUER DEN
;*      ;VORGESEHENEN ODER EINEM BESTIMMTEN ZWECK SOWIE JEGLICHER RECHTS-
;*      ;VERLETZUNG, JEDOCH NICHT DARAUF BESCHRAENKT. IN KEINEM FALL SIND DIE
;*      ;AUTOREN ODER COPYRIGHTINHABER FUER JEGLICHEN SCHADEN ODER SONSTIGE
;*      ;ANSPRUECHE HAFTBAR ZU MACHEN, OB INFOLGE DER ERFUELLUNG EINES
;*      ;VERTRAGES, EINES DELIKTES ODER ANDERS IM ZUSAMMENHANG MIT DER SOFTWARE
;*      ;ODER SONSTIGER VERWENDUNG DER SOFTWARE ENTSTANDEN.
;*
;*******************************************************************************

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;       Zuweisungen
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.EQU    SegDDR  = DDRC		;Segment-Port definieren (8 Bit)
.EQU    SegPort = PORTC
.EQU    DigDDR  = DDRB		;Digit-Port (Stellen) definieren 
.EQU    DigPort = PORTB
.EQU    D1PinNr = 0
.EQU    D2PinNr = 1
.EQU    D3PinNr = 2
.EQU    D4PinNr = 3

.EQU	DispTime = 1000		;Zeit der Darstellung in Millisekunden
.				;(max. 262140 ms)

.EQU    D1_Dot = 0		;hier kann der Dezimalpunkt (Bit 7) fuer jede 
.EQU    D2_Dot = 0		;Stelle freigeschaltet werden (1 = on, 0 = off)
.EQU    D3_Dot = 1
.EQU    D4_Dot = 0

;-------------------------------------------------------------------------------
;	7 Segmentanzeige initialisieren
;-------------------------------------------------------------------------------
D7SINI:	push	r16
	ser	r16
	out	SegDDR,r16
	sbi	DigDDR,D1PinNr
	sbi	DigDDR,D2PinNr
	sbi	DigDDR,D3PinNr
	sbi	DigDDR,D4PinNr
	pop	r16
	ret

;-------------------------------------------------------------------------------
;	Unterprogramm zur Darstellung des Doppelreg. W auf dem 7-Seg.-Display
;-------------------------------------------------------------------------------
D7SHEX:	push    r16             ;alle verwendeten Register (inkl. SREG) retten
        in      r16,SREG
        push    r16
        push    r17
        push    r18
        push    r19
        push	r24
        push	r25
        push    ZL
        push    ZH
        
        ;16 Bit Zeitzaehler r19:r18 initialisieren
        ldi     r18,LOW(DispTime/4)  	;Minimale Zeit = 4*1ms=4ms)
        ldi     r19,HIGH(DispTime/4)

D7SHE1:	;erste Stelle anzeigen
        ldi     ZL,LOW(NDISP2*2)  ;Adresszeiger mit der Adresse der Tab.*2
        ldi     ZH,HIGH(NDISP2*2) ;initialisieren (Worte statt Bytes)
        mov     r16,r24         ;Adresszeiger errechnen
        andi    r16,0x0F        ;Maskieren des untersten Nibble von r24
        clr     r17             ;Zwischenspeicher = 0
        add     ZL,r16          ;Addiere Zaehlerstand zur Basisadresse
        adc     ZH,r17          ;ZH erhoehen falls Carry!
	lpm	r16,Z		;Speichere das Zeichen der Speicherzeile deren
				;Adresse im Z-Pointer steht in das Arbeits-
				;register r16.
	.IF	D1_Dot == 1	;Setze Dezimalpunkt Stelle 1 falls D1_Dot == 1
	ori	r16,0x80
	.ENDIF	
	sbi	DigPort,D1PinNr	;Erste Stelle einschalten
        out	SegPort,r16	;Zeichen am SegPort ausgeben
	rcall	W1ms		;Warte 1ms
	cbi	DigPort,D1PinNr ;Erste Stelle ausschalten		

	;zweite Stelle anzeigen
	ldi     ZL,LOW(NDISP2*2)  ;Adresszeiger mit der Adresse der Tab.*2
        ldi     ZH,HIGH(NDISP2*2) ;initialisieren (Worte statt Bytes)
        mov     r16,r24         ;Adresszeiger errechnen
        andi    r16,0xF0        ;Maskieren des obersten Nibble von r24
        swap    r16             ;Vertausche beide Nibble        
        clr     r17             ;Zwischenspeicher = 0
        add     ZL,r16          ;Addiere Zaehlerstand zur Basisadresse
        adc     ZH,r17          ;ZH erhoehen falls Carry!
        lpm     r16,Z           ;Speichere das Zeichen der Speicherzeile deren
                                ;Adresse im Z-Pointer steht in das Arbeits-
                                ;register r16.
	.IF	D2_Dot == 1	;Setze Dezimalpunkt Stelle 2 falls D2_Dot == 1
	ori	r16,0x80	
	.ENDIF	
        sbi     DigPort,D2PinNr ;Zweite Stelle einschalten      
        out     SegPort,r16     ;Zeichen am SegPort ausgeben
        rcall   W1ms            ;Warte 1ms
        cbi     DigPort,D2PinNr ;Zweite Stelle ausschalten              


	;dritte Stelle anzeigen
        ldi     ZL,LOW(NDISP2*2)  ;Adresszeiger mit der Adresse der Tab.*2
        ldi     ZH,HIGH(NDISP2*2) ;initialisieren (Worte statt Bytes)
        mov     r16,r25         ;Adresszeiger errechnen
        andi    r16,0x0F        ;Maskieren des untersten Nibble von r25
        clr     r17             ;Zwischenspeicher = 0
        add     ZL,r16          ;Addiere Zaehlerstand zur Basisadresse
        adc     ZH,r17          ;ZH erhoehen falls Carry!
        lpm     r16,Z           ;Speichere das Zeichen der Speicherzeile deren
                                ;Adresse im Z-Pointer steht in das Arbeits-
                                ;register r16.                        
	.IF	D3_Dot == 1	;Setze Dezimalpunkt Stelle 3 falls D3_Dot == 1
	ori	r16,0x80	
	.ENDIF	
        sbi	DigPort,D3PinNr	;Dritte Stelle einschalten
	out	SegPort,r16	;Zeichen am SegPort ausgeben
	rcall	W1ms		;Warte 1ms
	cbi	DigPort,D3PinNr	;Dritte Stelle ausschalten		

	;vierte Stelle anzeigen
        ldi     ZL,LOW(NDISP2*2)  ;Adresszeiger mit der Adresse der Tab.*2
        ldi     ZH,HIGH(NDISP2*2) ;initialisieren (Worte statt Bytes)
        mov     r16,r25         ;Adresszeiger errechnen
        andi    r16,0xF0        ;Maskieren des obersten Nibble von r25
        swap    r16             ;Vertausche beide Nibble        
        clr     r17             ;Zwischenspeicher = 0
        add     ZL,r16          ;Addiere Zaehlerstand zur Basisadresse
        adc     ZH,r17          ;ZH erhoehen falls Carry!
        lpm     r16,Z           ;Speichere das Zeichen der Speicherzeile deren
                                ;Adresse im Z-Pointer steht in das Arbeits-
                                ;register r16.
	.IF	D4_Dot == 1	;Setze Dezimalpunkt Stelle 4 falls D4_Dot == 1
	ori	r16,0x80	
	.ENDIF	
	sbi	DigPort,D4PinNr	;Vierte Stelle einschalten
	out	SegPort,r16	;Zeichen am SegPort ausgeben
	rcall	W1ms		;Warte 1ms
	cbi	DigPort,D4PinNr	;Vierte Stelle ausschalten		

	;Zeitzaehler ueberpruefen
	subi	r18,1	        ;Zaehler dekrementieren und Zeit ueberpruefen
	sbci	r19,0
	brne	D7SHE1		

        pop     ZH
        pop     ZL
        pop     r25
        pop     r24
        pop	r19
	pop	r18
        pop     r17
        pop     r16
        out     SREG,r16
        pop     r16
	ret			;Zurueck ins Hauptprogramm

;-------------------------------------------------------------------------------
;	Tabelle		(7-Segment-Dekodiertabelle (hoechstwertigstes Bit = 0))
;-------------------------------------------------------------------------------
NDISP2:	
.DB	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07     ;Dekodiertabelle fuer
.DB	0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71     ;alle Hex-Zahlen