
; Datei: rs232inc.asm
; Behandlung der seriellen Schnittstelle
; Proceduren
; ***********************
; ** I N T E R F A C E **
; ***********************
;
; benutzt das Modul "arithmetik.asm"
;
; UPR-Name		used Registers	ch	calls	affects	Beschreibung
;				in		out
; serinit		-		-							Initialisieren der RS232 mit 9600,8,k,1
; v24_test		-		-					  temp1	Sendet permanent "U" = 0x55 -> halbe Baudrate
; serout		temp1	temp1	n				-	Zeichen ausgeben
; serin			-		temp1	j				-	Zeichen einlesen
; serin_echo	-		temp1	j	serout		-	Zeichen mit Echo einlesen
; v24_LF		-		-		n	serout		-	Zeilenvorschub ausgeben
; v24_CR		-		-		n	serout		-	Wagenrücklauf ausgeben
; v24_LFCR		-		-		n	serout		-	Zeilenvorschub und Wagenrücklauf ausgeben
; v24_CD		-		-		n	serout		-	Clear Display ausgeben
; v24_in_hex	-		temp1	j	serin		-	Zwei Zeichen als Hexziffern für ein Byte in temp1
; v24_in_number	-		temp1	j	serin		R1	Zwei Ziffern als Zehnerziffern für ein Byte in temp1
; v24_number	temp1	temp1	n	serout		-	Zahl in temp1 ausgeben
; v24_flash_str temp1	temp1	n	serout		-	0-term. String aus Flashmemory ausgeben
; v24_read_int	-		-		j	serin	  R2:R8	Ganzzahl <= 16,7 Mio einlesen (3-Byte)
; 									addbtemp1
;									bmal10
; v24_binout	temp2	-		n	serout		-	3-Byte-Zahl in Akku B ausgeben
;				Akku B			n	bin2asc		-			
; v24_eep_strin	temp1	temp1	j	eep_read	-	0-term. String aus dem EEPROM ausgeben	
;									serout
; eep_serout	temp1	temp2	j	eep_read	-	Byte von Adresse in temp1(/temp2) aus dem EEPROM ausgeben
;	an EEPROM-Umfang anpassen!!!
; ****************************************************************************************************
serinit:
	push temp1
	; Baudrate für RS232 einstellen
	ldi temp1, high(ubrr_val)		; zuerst Baudrate Highbyte (davon Lownibble)
	out ubrrh, temp1				; Weil URSEL-Bit =0 geht das für den mega8 in Ordnung
									; für den Tiny2313 spielt es keine Rolle
	ldi temp1, low(ubrr_val)		; Lowbyte schreiben und prescaler damit triggern
	out ubrrl, temp1

	; frameformat setzen
.ifdef mega8
	ldi temp1, (1<<ursel) | (1<<ucsz1) | (1<<ucsz0)	
		; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
		; Achtung! beim Mega8 belegen UBRRH und UCSRC die gleiche Adresse (0x20 bzw 0x40)
		; URSEL = 0 schreibt in UBRRH
		; URSEL = 1 schreibt in UCSRC
		; beim Lesen wird zunächst UBRRH ausgelesen
		;    unmittelbar danach (Interrupts durch CLI verhindern!!) UCSRC)
.else
	ldi temp1, (1<<ucsz1) | (1<<ucsz0)	; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
.endif
	out ucsrc, temp1

	; Transmitter einschalten, PortD Bit1 wird überschrieben
	sbi ucsrb, txen					; TXE-Bit (3) setzen
	
	; Receiver einschalten, PortD Bit0 wird überschrieben
	sbi ucsrb, rxen					; RXE-Bit (4) setzen
									; Das folgende Bit nur setzen, wenn eine ISR dazu existiert!
;	sbi ucsrb, rxcie				; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, 
									; wenn ein Zeichen da ist
    pop temp1
	ret

v24_test:				; Test der rs232, sendet permanent "U" -> halbe Baudrate als
						; Rechteck an TXD
	ldi temp1, 0x55
	rcall serout
	rjmp v24_test
	ret


	; Zeichen in Temp1 über rs232 ausgeben
	; temp1: enthält das zu sendende Zeichen
serout:
	sbis ucsra,udre					; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
									; UART Data Register Empty
	rjmp serout
	out	 udr, temp1					; Zeichen senden
	ret								; zurück aus der Subroutine


	; Zeichen über RS232 einlesen
	; temp1: gibt das Zeichen zurück 
serin:
	sbis ucsra, rxc	
	rjmp serin						; wir warten bis ein Byte angekommen ist

	in temp1, udr					; Zeichen einlesen
	;rcall serout					; und zurücksenden	
	ret


	; Zeichen über RS232 einlesen und als Echo zurücksenden
	; temp1: gibt das Zeichen zurück 
serin_echo:
	sbis ucsra, rxc	
	rjmp serin_echo						; wir warten bis ein Byte angekommen ist

	in temp1, udr					; Zeichen einlesen
	rcall serout					; und zurücksenden	
	ret


v24_lf:								; Linefeed ausgeben
	push temp1
	ldi temp1, LF
	rcall serout
	pop temp1
	ret

v24_CR:								; Wagenrücklauf ausgeben
	push temp1
v24_cr1:
	ldi temp1, CR
	rcall serout
	pop temp1
	ret


v24_LFCR:							; Linefeed und Wagenrücklauf ausgeben
	push temp1
	ldi temp1, LF
	rcall serout
	rjmp v24_CR1

v24_CD:								; Clear dislay ausgeben
	push temp1
	ldi temp1, CD
	rcall serout
	pop temp1
	ret


 ; Die Funktion hexit ist in der Lib arithmetik.asm untergebracht

.ifndef asc2bin
.include "arithmetik.asm"
.endif

    ; Ein Hex-Byte von V24 einlesen nach temp1 
v24_in_hex:
	push temp2
	push temp3
hziffer0:
	rcall serin
	mov temp2,temp1
	rcall asc2bin		; in hexnibble wandeln (benutzt temp2 für transport)
	brcs hziffer0		; Fehler? -> noch mal einlesen
	rcall serout		; echo zurücksenden
	mov temp3, temp2	; ergebniszwischenspeicher
	swap temp3			; ins highnibble bringen
hziffer1:
	rcall serin
	mov temp2,temp1
	rcall asc2bin		; in hexnibble wandeln (benutzt temp2 für transport)
	brcs hziffer1		; Fehler? -> noch mal einlesen
	rcall serout		; echo zurücksenden
	mov temp1, temp2	; Ergebnis aufbauen
	or  temp1, temp3	; und in temp1 zurückgeben
	pop temp3
	pop temp2		
	ret
		
	; Zahl aus 2 Digits in temp2 aufbauen
	; temp1: rückgabe des Funktionswerts Zahl 
v24_in_number:
	rcall serin		; Zeichen (Zehnerstelle) von V24 holen
;	rcall serout
	andi temp1, 0x0f; Oberes Nibble abschneiden
	lsl temp1		; Zur Zehnermultiplikation vorbereiten, erst einmal x 2
	mov accu1, temp1; das doppelte sichern
	lsl accu1       ; Sicherung mal 2
	lsl accu1		; sicherung mal 4 ist insgesamt temp1 mal 8
	add accu1, temp1; 2fach plus 8fach (ohne carry) gibt zehnfach
	rcall serin		; Einerstelle von V24 holen
;	rcall serout
	andi temp1, 0x0f; Oberes Nibble abschneiden
	add temp1, accu1; Einerstelle zu Zehnerstelle addieren
	ret				; fertig



.ifndef lcd_number
	; ein Byte als Dezimalzahl auf LCD oder via RS232 ausgeben
	; Datenbyte: temp1 
lcd_number:
.ifdef lcd_data
           push  temp1
           push  temp2
           push  temp3

		   ldi temp2, low(lcd_data) 	  ; Adresse von Befehl "lcd_data" als
		   mov zl, temp2 				  ; Sprungadresse für indirekten SUB-Call
		   ldi temp2, high(lcd_data)	  ; in Z-Register ablegen
		   mov zh, temp2
		   rjmp v24_number_0
.endif ; ifdef lcd_data

v24_number:
           push  temp1
           push  temp2
           push  temp3

		   ldi temp2, low(serout) 		  ; Adresse von Befehl "serout" als
		   mov zl, temp2 				  ; Sprungadresse für indirekten SUB-Call
		   ldi temp2, high(serout)		  ; in Z-Register ablegen
		   mov zh, temp2

v24_number_0:
		   ldi	 temp3, 0
           mov   temp2, temp1
                                  		  ; abzählen wieviele Hunderter
                                          ; in der Zahl enthalten sind
           ldi   temp1, '0'
v24_number_1:
           subi  temp2, 100
           brcs  v24_number_2
           inc   temp1
           rjmp  v24_number_1
                                          ;
                                          ; die Hunderterstelle ausgeben
v24_number_2:
		   cpi	 temp1, '0'
		   breq  v24_number_2a
           icall 
		   inc 	 temp3
v24_number_2a:
           subi  temp2, -100              ; 100 wieder dazuzählen, da die
                                          ; vorherhgehende Schleife 100 zuviel
                                          ; abgezogen hat

                                          ; abzählen wieviele Zehner in
                                          ; der Zahl enthalten sind
           ldi   temp1, '0'
v24_number_3:
           subi  temp2, 10
           brcs  v24_number_4
           inc   temp1
           rjmp  v24_number_3

                                          ; die Zehnerstelle ausgeben
v24_number_4:
		   cpi	 temp3, 0
		   brne  v24_number_4a
		   cpi   temp1, '0'
		   breq  v24_number_4b
v24_number_4a:
           icall 
v24_number_4b:
           subi  temp2, -10               ; 10 wieder dazuzählen, da die
                                          ; vorhergehende Schleife 10 zuviel
                                          ; abgezogen hat

                                          ; die übrig gebliebenen Einer
                                          ; noch ausgeben
           ldi   temp1, '0'
           add   temp1, temp2
           icall 

           pop   temp3
           pop   temp2
           pop   temp1
           ret

.endif ;lcd_number

 	; Einen konstanten Text aus dem Flash Speicher
 	; ausgeben. Der Text wird mit einer 0 beendet
	; Z-Reg enthält die Adresse des Strings * 2
v24_flash_string:
           push  temp1

v24_flash_string_1:
           lpm   temp1, Z+
           cpi   temp1, 0
           breq  v24_flash_string_2
           rcall  serout
           rjmp  v24_flash_string_1

v24_flash_string_2:
           pop   temp1
           ret

.ifdef arithmetik

; Macros müssen __VOR__ der ersten Verwendung deklariert werden

.MACRO lade_z						; Lade das Z-Register mit einer
	ldi zl, low(@0)					; Speicheradresse
	ldi zh, high(@0)				; Beispiel:
.ENDM


 ; eine ganze Zahl von der V24 einlesen. 
 ; Wert <= 16.777.215
 ; benötigt Akku A, B und Temp1
 ; Ergbnis steht in Akku B
v24_read_int:	
	push temp1
	push temp2
	in temp2,sreg

	lade_z buffer					; Z-Pointer auf Buffer setzen (Macro lade_Z expandieren)
	clr stellen						; Stellenzahl auf 0
b0_a:
	rcall serin_echo				; Zeichen von der V24
	cpi temp1, 0x0d					; CR -> Eingabe abschließen
	breq b0_b						; fertig für Wandlung, falls enter gedrückt
.ifdef lcd_data
	rcall lcd_data					; Ziffer auf LCD
.endif
	andi temp1, 0x0f				; ASCII-Teil ausblenden
	st z+, temp1					; im SRAM ablegen und Zeiger erhöhen
	inc stellen						; Stellenzahl erhöhen
	rjmp b0_a						; wieder zur Eingabe
b0_b:
	sbic ucsra, rxc					; kein Zeichen mehr im Puffer? -> springen
	rcall serin 					; sonst einlesen und vergessen
	clr lb							; Akkumulator B löschen
	clr mb
	clr hb
	lade_z buffer					; Z-Pointer erneut auf Bufferanfang setzen
b0_c:
	ld temp1,z+						; Ziffernwert aus buffer lesen
	rcall addbtemp1					; zum Akku B addieren 
	dec stellen						; Stellenzahl runterzählen
	breq b0_d						; war's die letzte Stelle? dann fertig
	rcall bmal10					; sonst Akku B mal 10 und 
	rjmp b0_c						; nächste Stelle verarbeiten
b0_d:								; Ergebnis steht in Akku B
	out sreg, temp2
	pop temp2
	pop temp1
	ret

	; Binärzahl in akku b ausgeben, Binär-Stellenzahl in temp2 (<=24)
	; mit bin2asc nach buffer wandeln, Ziffern-Stellenzahl + 1 in temp2
	; der bufferzeiger z steht auf der Null des String-Endes
v24_binout:
	push temp1
	push temp2
	push zl
	push zh
	rcall bin2asc			; Binärzahl in eine Dezimalzahl in buffer (Z-Pointer) wandeln
v24_bin2asc_0:
	ld temp1, -z			; Ziffernzeichen aus SRAM laden mittels Z-Pointer
	rcall serout
	dec temp2				; Anzahl zu verarbeitender Ziffern verringern
	brne v24_bin2asc_0		; noch Ziffern da? -> von vorne
	pop zh
	pop zl
	pop temp2
	pop temp1
	ret



.endif ; ifdef arithmetik



