; Testprogramm für RS232 - Betrieb
;
.nolist
.include "tn2313def.inc"
.list
;
.equ takt = 8000000 ; 16/8 MHz Systemtakt
.equ baud = 9600  	; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1)	; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1)))	; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000)	; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10))		; max +/- 10 Promill Fehler
	.error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
	.message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
;

.equ debuglevel = 0

	.def temp1 = r16
	.def temp2 = r17
	.def temp3 = r18

	.def flag  = r19
	.equ fcounthex = 2				; Übergabe des Lownibbles von sekunden an PortB wenn gesetzt

	.def dimmer = r20				; Register für die Steuerung der Leuchtdauer von LED4

	.def jiffies = r21
	.def sekunden = r22
	.def minuten = r23
	.def stunden = r24
	.def cnt_relais = r25			; counter für Relaisschaltzeit

	.equ led_port = portb			; portb
	.equ led1 = 0					; portb.0
	.equ led2 = 1					; portb.1
	.equ led3 = 2					; portb.2
	.equ led4 = 3					; portb.3
	.equ led_ddr = ddrb				; ddrb


	.equ vwert = 40000-1			; Wert für ocr1a-Vergleichsregister
;
.cseg
	.org 0x0000						; Programmstart
	rjmp Start						; Resetvektor

	.org 0x06; OC1Aaddr					; IRQ-Vektor für Timer 1
	rjmp Timer1_oc1a				; Sprung zur Serviceroutine

;	.org 0x0b; URXCaddr					; IRQ-Vektor für RS232-Zeichenempfang
;	rjmp int_rxc					; Sprung zur Serviceroutine

Start:
	.org 0x0013						; hinter allen IRQ-Vektoren
	ldi temp1, low(ramend)			; Stackpointer setzen
	out spl, temp1					

	; Baudrate für RS232 einstellen
	ldi temp1, high(ubrr_val)		; zuerst Baudrate Highbyte (davon Lownibble)
	out ubrrh, temp1
	ldi temp1, low(ubrr_val)			; Lowbyte schreiben und prescaler damit triggern
	out ubrrl, temp1

	; frameformat setzen
	ldi temp1, (1<<ucsz1) | (1<<ucsz0)	; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
	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
	;sbi ucsrb, rxcie				; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
	
	rcall serout_say_hallo
	;rjmp loop
	; PortB3:0 für LED-Ausgabe setzen
	ldi temp1, (1<<led1) | (1<<led2) | (1<<led3) |(1<<led4)	; Bits led_port als ausgang
	out led_ddr, temp1					;  setzen
	out led_port, temp1					; Leds aus
	
	; Zähler 1 für die Erzeugung des Zweihundertstel-Sekundentakts vorbereiten
	ldi temp1, high(vwert)			; OCR1A setzen
	out ocr1ah, temp1				; wir lassen Timer1 bis 40000 zählen
	ldi temp1, low(vwert)			; das schafft er 200 mal pro Sekunde
	out ocr1al, temp1				; ein Durchgang = 1 Jiffie = 1/200 s

	ldi temp1, (1<<wgm12) | (0<<cs12) | (0<<cs11) | (1<<cs10); CTC ein, Taktquelle = Systemtakt ein, kein Vorteiler
	out tccr1b, temp1
	ldi temp1, 0					; tccr1a alle Bits = 0
	out tccr1a, temp1

	ldi temp1, (1<<ocie1a)			; output compare 1A IRQ zulassen
	out timsk, temp1

	clr sekunden					; Zeitrechnung auf 0 stellen
	clr minuten
	clr stunden
	clr jiffies
	clr flag						; lösche alle Merker
	ldi dimmer, 100					; mittlere Helligkeit für LED4

	sei								; Uhr scharf machen

loop:
.if debuglevel ==0
job00:
	rcall serin
	cpi temp1, 'e'
	brne job01
		rcall serin_echo
		cpi temp1, '1'
		brne job0a
		cbi led_port, led1
		rjmp job99
  	job0a:
		cpi temp1, '2'
		brne job0b
		cbi led_port, led2
		rjmp job99
  	job0b:
		cpi temp1, '3'
		brne job0c
		cbi led_port, led3
		rjmp job99
	job0c:
		cpi temp1, '4'
		brne job99
		cbi led_port, led4
		rjmp job99
job01:
	cpi temp1, 'a'
	brne job02
		rcall serin_echo
		cpi temp1, '1'
		brne job1a
		sbi led_port, led1
		rjmp job99
  	job1a:
		cpi temp1, '2'
		brne job1b
		sbi led_port, led2
		rjmp job99
  	job1b:
		cpi temp1, '3'
		brne job1c
		sbi led_port, led3
		rjmp job99
	job1c:
		cpi temp1, '4'
		brne job99
		sbi led_port, led4
		rjmp job99
job02:
	cpi temp1, 't'
	brne job03
	ldi temp1, 0xc9
	rcall serout
	rjmp job99
job03:	
	cpi temp1, 's'
	brne job04
	rcall v24_test
	rjmp job99

job04:
	cpi temp1, 'h'
	brne job05
	sbr flag, 1<<fcounthex		; Zählen in der ISR von Timer1 aktivieren
	rjmp job99

job05:
	cpi temp1, 'c'
	brne job06
	cbr flag, 1<<fcounthex		; Zählen in der ISR von Timer1 deaktivieren
	in temp2, led_port
	ori temp2, 0x0f				; alle LEDs aus
	out led_port, temp2
	rjmp job99

job06:
	cpi temp1, 'u'
	brne job07
	cpi dimmer, 1
	breq job99
	dec dimmer
	rjmp job99

job07:
	cpi temp1, 'd'
	brne job08
	cpi dimmer, 199
	breq job99
	inc dimmer
	rjmp job99

job08:
	cpi temp1, 'x'
	brne job09
	rcall v24_in_number
	mov cnt_relais, temp1
	sbi led_port,led4				; Reais ein
	rjmp job99
job09:

job99:

.endif


.if debuglevel != 2
	rjmp loop
.endif

	ldi temp1, 'T'					; erstes Zeichen laden
	rcall serout					; und senden
	ldi temp1, 'e'					; nächstes Zeichen laden
	rcall serout					; und senden	
	ldi temp1, 's'					; nächstes Zeichen laden
	rcall serout					; und senden
	ldi temp1, 't'					; nächstes Zeichen laden
	rcall serout					; und senden
	ldi temp1, 10					; nächstes Zeichen laden
	rcall serout					; und senden
	ldi temp1, 13					; nächstes Zeichen laden
	rcall serout					; und senden

	rjmp loop

; ********************************************************************************************************
; Betriebssystemprogramme für die RS232
; ********************************************************************************************************
	
	; Unterprogramm zum Ausgeben von Zeichen via RS232
	; Parameter: register R16 alias 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_test:				; Test der rs232, sendet permanent "U" -> halbe Baudrate als
						; Rechteck an TXD
	ldi temp1, 0x55
	rcall serout
	rjmp v24_test
	ret


serout_say_hallo:
	push temp1
	push temp2
	ldi temp1, low(my_string*2)
	ldi temp2, high(my_string*2)
	rcall serout_string
	pop temp2
	pop temp1
	ret

serout_string:
	mov zl, temp1
	mov zh, temp2
serout_string0:
	lpm								; liest ein Byte von der im Z-Register (16bit) adressierten Stelle(8bit)
	and r0,r0						; 0-Byte? 
	breq serout_string_ende			; ja, dann Stringende
serout_string_wait:
	sbis ucsra, udre				; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
									; UART Data Register Empty
	rjmp serout_string_wait
	out udr, r0						; Zeichen in r0 ausgeben
	adiw zl:zh, 1					; pointer in z incrementieren
	rjmp serout_string0				; nächstes Zeichen
serout_string_ende:
	ret								; zurück nach Zeichenausgabe

my_string:
	.db "Hallo - Willkommen beim Chat mit dem ATTiny2313! ",10,13,0

	; Zahl aus 2 Digits in temp2 aufbauen
	; temp1: rückgabe des Funktionswerts Zahl 
v24_in_number:
	push temp2
	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 temp2, temp1; das doppelte sichern
	lsl temp2       ; Sicherung mal 2
	lsl temp2		; sicherung mal 4 ist insgesamt temp1 mal 8
	add temp2, temp1; 2fach plus 8fach (ohne carry) gibt zehnfach
	rcall serin		; Einerstelle von V24 holen
;	rcall serout
	andi temp1, 0x0f; Oberes Nibble abschneiden
	add temp1, temp2; Einerstelle zu Zehnerstelle addieren
	pop temp2
	ret				; fertig
; ********************************************************************************************************
; ISR - Betriebssystemprogramme für die Timerbehandlung 
; ********************************************************************************************************

; Output compare Interrupt - Service Routine
timer1_oc1a:
	push temp1						; temp1 sichern
	in temp1, sreg					; Statusregister sichern
	push temp1
	push temp2

	inc jiffies						; Jiffies erhöhen
	cpi jiffies, 200				; so lange 200 nicht erreicht ist, fertig
	brne end_isr					
									; es ist der wert 200 erreicht
	clr jiffies						; Jiffies löschen 


.if debuglevel == 1
	sbic led_port, led1	
	rjmp loeschen					; LED1 blinken lassen
	sbi led_port, led1
	rjmp bit_fertig
loeschen:
	cbi led_port, led1
.endif

bit_fertig:
	inc sekunden					; sekunden erhöhen

counting:
	sbrs flag, fcounthex
	rjmp counting_done
	mov temp2, sekunden
	andi temp2, 0x0f
	ldi temp1, 0x0f
	eor temp2, temp1
	in temp1, led_port
	andi temp1, 0xf0
	or temp1, temp2
	out led_port, temp1
counting_done:
relais:
	tst cnt_relais
	breq relais_off
	dec cnt_relais
	rjmp relais_done
relais_off:
	cbi led_port,led4				; Relais aus
relais_done:
	cpi sekunden, 60
	brne fertig

	clr sekunden
	inc minuten	
	cpi minuten, 60		
	brne fertig

	clr minuten
	inc stunden
	cpi stunden, 24
	brne fertig

	clr stunden

fertig:
	sbr flag, (1<<0)

end_isr:
	pop temp2
	pop temp1
	out sreg, temp1					; status register restaurieren
	pop temp1						; temp1 zurück
	reti							; irq-routine beenden

; *************************************************************************************************

int_rxc:
	push temp1						; temp1 sichern
	in temp1, sreg					; Status sichern
	push temp1

	in temp1, udr					; zeichen lesen, rxc-flag wird autom. gelöscht
	rcall serout					; und wieder senden

	cpi temp1, '1'
	brne int_rxc_1
	sbi led_port,led2						; led2 an
	rjmp int_rxc_fertig
int_rxc_1:
	cpi temp1, '0'
	brne int_rxc_fertig
	cbi led_port,led2						; led2 aus

int_rxc_fertig:
	pop temp1
	out sreg, temp1					; status restaurieren
	pop temp1						; temp1 restaurieren
	reti							; zurück vom Interrupt




	cp	dimmer, jiffies				; Einschaltwert erreicht?
	brne j_continue
	cbi led_port, led4				; LED4 einschalten, wenn Schwellert erreicht
j_continue:

	sbi led_port,led4				; LED4 aus



