; *****************************************************************************************************
; 	PWM-Steuerung einer RGB-LED mit dem Tiny2313
; *****************************************************************************************************
;
;	Datei rgb_dimmer.asm
; 	Autor: Jürgen Grzesina
; 	Stand: 11.01.09
;
; *****************************************************************************************************
; *****************************************************************************************************
;
.equ debuglevel = 0
;
; *****************************************************************************************************
	.equ takt = 8000000				; Quarzfrequenz

.nolist
.include "tn2313def.inc"
.include "arithmetik_header.asm"
.include "lcd-routines-bib_header.asm"
.include "rs232inc_header.asm"
.list



	.def temp1 = R16
	.def temp2 = R17
	.def temp3 = r18

	.def grubs	= R19				; zählt bis 50
	.def jiffies = R20				; Hundertstelsekunden
	.def sekunden = R21
	.def Minuten = R22

	.def t1 = R23					; Zähler für Tastenentprellung
	.def t2 = R24					; Zähler für Tastenentprellung
	.def t3 = R25					; Zähler für Tastenentprellung
	.def wahl = r26					; ausgesuchter Farbkanal
		.equ wrot = 0				; Bits für die Farbwahl
		.equ wgruen = 1				; in "wahl"
		.equ wblau = 2

	.equ flag = GPIOR0
		.equ fblau = 5				; OC0B Pin 9  (PD5)
		.equ frot = 2				; OC0A Pin 14 (PB2)
		.equ fgruen = 3				; OC1A Pin 15 (PB3)


	.equ tastenport = portd			; Port für den Tastenanschluss
	.equ tastenddr = ddrd			; DDR für Tastenleitungen
	.equ tastenpin = pind	 		; Eingang für Tastenabfrage
	.equ taste1 = 2 				; Funktionstaste Pin 6 (PD2)
	.equ taste2 = 3					; Auf-Taste Pin 7 (PD3)
	.equ taste3 = 4					; Ab-Taste Pin 8 (PD4)
	.equ longtime = 10				; Wert ab dem ein Langzeittastendruck gilt

	.equ ledport = portd			; Status LED: zuständiger Port
	.equ ledddr = ddrd				; 			  zuständiges ddr

	.equ b_port = portd				; Ports für die Ansteuerung der FarbLEDs
	.equ r_port = portb
	.equ g_port = portb
	.equ b_ddr = ddrd				; DDRs für die Ansteuerung der FarbLEDs
	.equ r_ddr = ddrb
	.equ g_ddr = ddrb

	.equ blau = 5					; Bitnummern für die Ausgänge
	.equ rot = 2					; FarbLEDs und
	.equ gruen = 3
	.equ LED = 6					; StatusLED

	.equ vocomp1b	= 200-1			; Jiffies entsprechen 0,01 s (1/(takt/8/200/50) = 1 Jiffie)
	
.dseg
	rot_wert:	.byte 1				; Übergabevariablen der Farbwerte an
	gruen_wert:	.byte 1				; die ISR
	blau_wert:	.byte 1


; *****************************************************************************************************

.cseg 
.org 0x0000
	rjmp start

.org 0x0005
	rjmp TOVL1						; Regelt GRÜN-Übergabe

.org 0x0006
	rjmp TOVL0						; Regelt ROT- und BLAU-Übergabe

.org 0x000c
	rjmp TOC1b						; erledigt die Zeitsteuerung

.org 0x001a
start:
	ldi temp1, ramend
	out spl, temp1

lcd_prep:
	; LCD initialisieren
	rcall lcd_init
	rcall lcd_clear
	rcall lcd_cursor
;	ldi temp1, 'T'
;	rcall lcd_data
.if debuglevel == 1 		; wir testen auf statische Signale (Kurzschlüsse) 
	rjmp lcd_prep			; an den LCD-Pins
.endif

.if debuglevel == 2			; Wir prüfen auf Bitmuster 0:1 an RS:E und
	cbi e_port, pin_e
	sbi rs_port, pin_rs
	in  temp1, lcd_port
	andi temp1, 0b00001111	; auf 1:0:1:0 auf PB7:PB6:PB5:PB4
	ori temp1, 0b10100000
	out lcd_port, temp1
test2:
	rjmp test2
.endif

.if debuglevel == 3			; Wir prüfen auf Bitmuster 1:0 an RS:E und
	sbi e_port, pin_e
	cbi rs_port, pin_rs
	in  temp1, lcd_port
	andi temp1, 0b00001111	; auf 0:1:0:1 auf PB7:PB6:PB5:PB4
	ori temp1, 0b01010000
	out lcd_port, temp1
test3:
	rjmp test3
.endif

	; RS232 initialisieren
	rcall serinit
	ldi temp1, 0b00000100
	rcall hallo

.if debuglevel == 4
test4:
	rjmp v24_test
.endif

.if debuglevel == 5
test5:
	rcall serin_echo
	rjmp test5
.endif

	; Ports initialisieren - LCD-Leitungen managt "lcd_init"
	in temp1, tastenport
	andi temp1, ~((1<<taste1) | (1<<taste2) | (1<<taste3))	; explizit auf 0 setzen für Eingang
	out tastenport, temp1									; interne Pullups aus
	
	in temp1, tastenddr
	andi temp1, ~((1<<taste1) | (1<<taste2) | (1<<taste3))	; explizit auf 0 setzen für Eingang
	out tastenddr, temp1

	ldi t1, 0					; Tastenzähler auf Null
	ldi t2, 0
	ldi t3, 0
	ldi wahl, 1<<wrot			; bit für roten Kanal
	

	sbi R_port, rot				; Rote LED ist lowaktiv, durch setzen auf 1 ausschalten
	sbi r_ddr, rot				; Leitung für rote LED auf Ausgang
	sbi g_port, gruen			; dto
	sbi g_ddr, gruen
	sbi b_port, blau			; dto
	sbi b_ddr, blau
	sbi ledport, led			; dto
	sbi ledddr, led				

	; timer initialisieren
	; verwendet OC0B, OC0A, OC1A
	; alle Timer mit Vorteiler 8
	; OCR - Werte vorbesetzen
	ldi temp1, 5
	out OCR0A, temp1			; Steuerwert für rot
	sts rot_wert, temp1
	rcall showrot
	ldi temp1, 8
	out OCR0B, temp1			; Steuerwert für blau
	sts blau_wert, temp1
	rcall showblau
	ldi temp1, 15
	out OCR1AL, temp1			; Steuerwert für grün
	sts gruen_wert, temp1
	rcall showgruen
	ldi temp1, high(vocomp1b)
	out OCR1BH, temp1			; Highbyte der Vollständigkeit wegen
	ldi temp1, low(vocomp1b)
	out OCR1BL, temp1			; Zeitsteuerung
	ldi temp1, 0
	out flag, temp1

	; TCCR0A: COM0A1, COM0A0, COM0B1, COM0B0,   -   ,    -    , WGM01, WGM00
	;         1       1       1       1        0        0       1      1
	; Fast PWM invertiert
	ldi temp1, 0b11110011	
	out tccr0a, temp1
	; TCCR0B: FOC0A,  FOC0B,    -   ,   -   , WGM02,  CS02,    CS01,   CS00
	;          0        0       0       0      0        0       1       0
	; Vorteiler 8
	ldi temp1, 0b00000010
	out tccr0b, temp1

	ldi temp1, 0
	out tccr1c, temp1			; kein Bedarf
	; TCCR1A: COM1A1, COM1A0, COM1B1, COM1B0,   -   ,    -    , WGM11, WGM10
	;          1       1       0       0        0       0       0      1
	ldi temp1, 0b11000001
	out tccr1a, temp1
	; TCCR1B: ICNC1,  ICES1,    -   , WGM13,  WGM12,  CS02,    CS01,   CS00
	;          0       0        0       0       1       0        1       0
	; no input capture, Vorteiler 8
	ldi temp1, 0b00001010
	out tccr1b, temp1

	; TIMSK:  TOIE1,  OCIE1A, OCIE1B,   -   , ICIE1, OCIE0B, TOIE0 , OCIE0A
	;    	   1        0        1      0       0       0      1       0
	ldi temp1, 0b10100010
	out timsk, temp1
	

	sei							; Interrupts freigeben

	sbis tastenpin, taste1
	rjmp dauerlauf
; *****************************************************************************************************

loop:
	sbic ucsra, rxc				; rxc-Bit = 0? dann keine taste gedrückt, tastenabfrage überspringen
	rcall tastenabfrage

jobs:

	rjmp loop					; Hauptschleife Ende

; *****************************************************************************************************
;	IRQ-Service-Routinen
; *****************************************************************************************************
; Timer0 Überlauf
TOVL0:
	push temp1
	push temp2
	in temp2,sreg

	sbis flag, fblau
	rjmp w_rot
	lds temp1, blau_wert
	out ocr0b, temp1
	cbi flag, fblau
w_rot:
	sbis flag, frot
	rjmp rb_done
	lds temp1, rot_wert
	out ocr0a, temp1
	cbi flag, frot
rb_done:
	out sreg, temp2
	pop temp2
	pop temp1
	reti

TOVL1:
	push temp1
	push temp2
	in temp2,sreg

	sbis flag, fgruen
	rjmp g_done
	lds temp1, gruen_wert
	out ocr1al, temp1
	cbi flag, fgruen
g_done:
	out sreg, temp2
	pop temp2
	pop temp1
	reti


TOC1B:
	push temp1
	push temp2
	in temp2,sreg
	push temp2
	
	inc grubs
	; ------------------------------- IRQ - Aufgaben ----------------------------------------------

	; Job 1   Zeitscheibe 1: Tastenabfrage ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
jif01:
	cpi grubs, 1					; 
	brne jif02
	; Taste 1 gedrückt, wenn taste1-bit=0  ........................................................
	sbic tastenpin, taste1			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t1r						; bit = 1 -> Taste nicht gedrückt
t1p:
	inc t1							; Zähler für Taste 1 erhöhen
	cpi t1, longtime+1				; Langzeit Tastendruck	
	brlo t1_ok
	ldi t1,longtime
t1_ok: 
	rjmp t1_fertig
t1r:
	clr t1							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t1_fertig:

	; Taste 2 gedrückt, wenn taste2-bit=0 .........................................................
	sbic tastenpin, taste2			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t2r						; bit = 1 -> Taste nicht gedrückt
t2p:
	inc t2							; Zähler für Taste 2 erhöhen
	cpi t2, longtime+1				; Langzeit Tastendruck	
	brlo t2_ok
	ldi t2,longtime
t2_ok: 
	rjmp t2_fertig
t2r:
	clr t2							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t2_fertig:

	; Taste 3 gedrückt, wenn taste3-bit=0 ........................................................
	sbic tastenpin, taste3			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t3r						; bit = 1 -> Taste nicht gedrückt
t3p:
	inc t3							; Zähler für Taste 3 erhöhen
	cpi t3, longtime+1				; Langzeit Tastendruck	
	brlo t3_ok
	ldi t3,longtime
t3_ok: 
	rjmp t3_fertig
t3r:
	clr t3							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t3_fertig:

	; Job 2   Zeitscheibe 2: Tastenaktionen +++++++++++++++++++++++++++++++++++++++++++++++++++++
jif02:
	cpi grubs, 2					; 
	brne jif03
	; Taste 1 war kurz gedrückt, wenn t1=3
	cpi t1,3
	brne t2k
	lsl wahl						; das Kanalwahlbit rotiert 
	cpi wahl,5						; wenn es die höchste Position (2) für Blau passiert hat,
	brlo t1b						; 
	ldi wahl, 1<<wrot				; bit für roten Kanal setzen
t1b:
	rcall lcd_home					; Zeile 1 im LCD löschen
	ldi zl, low(str_blank_line*2)
	ldi zh, high(str_blank_line*2)
	rcall lcd_flash_string
	sbrs wahl, wrot					; roter Kanal gewählt?  Bit "wrot" in "wahl" gesetzt ?
	rjmp t1c						; nein, -> weiter bei grün
	ldi temp1, 1
	ldi temp2, 0
	rcall lcd_position				; erste Zeile Spalte 2 als Kenner 
	ldi temp1, 'R'					; ein "R" schreiben
	rcall lcd_data					; 
t1c:
	sbrs wahl, wgruen				; dto grün
	rjmp t1d
	ldi temp1, 6
	ldi temp2, 0
	rcall lcd_position
	ldi temp1, 'G'
	rcall lcd_data
t1d:	
	sbrs wahl, wblau				; dto blau
	rjmp t2k
	ldi temp1, 11
	ldi temp2, 0
	rcall lcd_position
	ldi temp1, 'B'
	rcall lcd_data
t2k:
	cpi t2, 3 						; entsprechenden Kanal aufwärtszählen
	brne t3k
	ldi t2, 0
	sbrc wahl, wrot
	rcall rotplus
	sbrc wahl, wgruen
	rcall gruenplus
	sbrc wahl, wblau
	rcall blauplus

t3k:
	cpi t3, 3 						; entsprechenden Kanal abwärtszählen
	brne jif03
	ldi t3, 0
	sbrc wahl, wrot
	rcall rotminus
	sbrc wahl, wgruen
	rcall gruenminus
	sbrc wahl, wblau
	rcall blauminus
	
jif03:
	; ------------------------------- IRQ - Aufgaben  fertig ---------------------------------------
	cpi grubs, 50
	brne timing_done

	clr grubs
	inc jiffies
	cpi jiffies, 100
	brne timing_done

	clr jiffies
	inc sekunden
blink_LED:
	sbis ledport, led			; wenn Bit gesetzt, ist LED aus, rjmp überspringen zum Einschalten
	rjmp led_aus
led_an:
	cbi ledport, led			; Bit auf 0 -> LED an (lowaktiv)
	rjmp led_done
led_aus:
	sbi ledport, led			; Bit auf 1 -> LED aus
led_done:
	cpi sekunden, 60
	brne  timing_done

	clr sekunden
	inc minuten
	cpi minuten, 60
	brne  timing_done

	clr minuten

timing_done:
	pop temp2
	out sreg, temp2
	pop temp2
	pop temp1
	reti

; *****************************************************************************************************
;	Bibliotheksroutinen
; *****************************************************************************************************

.nolist
.include "arithmetik.asm"
.include "lcd-routines-bib.asm"
.include "rs232inc.asm"
.list

; *****************************************************************************************************
;	Jobroutinen
; *****************************************************************************************************

Hallo:
	ldi zl, low(2*str_hallo)
	ldi zh, high(2*str_hallo)
	rcall v24_flash_string
	rcall v24_lfcr
	ldi zl, low(2*str_hallo)
	ldi zh, high(2*str_hallo)
	rcall lcd_flash_string
	ret
; -----------------------------------------------------------------------------------------------------
tastenabfrage:
	rcall serin_echo
	; Blauwert senken
	cpi temp1, 'b'
	brne ta01
	rcall blauminus
	rjmp ta99
ta01:
	; Rotwert senken
	cpi temp1, 'r'
	brne ta02
	rcall rotminus
	rjmp ta99
ta02:
	; grünwert senken
	cpi temp1, 'g'
	brne ta03
	rcall gruenminus
	rjmp ta99
ta03:
	; grünwert steigern
	cpi temp1, 'G'
	brne ta04
	rcall gruenplus
	rjmp ta99
ta04:
	; Rotwert steigern
	cpi temp1, 'R'
	brne ta05
	rcall rotplus
	rjmp ta99
ta05:
	; Blauwert steigern
	cpi temp1, 'B'
	brne ta06
	rcall blauplus
	rjmp ta99
ta06:
	; null
	cpi temp1, 'n'
	brne ta07
	RCALL null
	rjmp ta99
ta07:
	; voll
	cpi temp1, 'v'
	brne ta08
	ldi temp1, 255
	sts rot_wert,temp1
	sts blau_wert, temp1
	sts gruen_wert,temp1
	rcall showrot
	rcall showblau
	rcall showgruen
	sbi flag, fblau
	sbi flag, frot
	sbi flag, fgruen
	rjmp ta99
ta08:
	; Automatik?
	cpi temp1, 'a'
	brne ta09
.ifdef automatik
	rcall automatik
.endif
	rjmp ta99

ta09:
.if debuglevel == 6
	cpi temp1, 'i'
	brne ta10
	rcall lcd_init
	rjmp ta99	
ta10: 
	cpi temp1, 'c'
	brne ta11
	rcall lcd_clear
	rjmp ta99
ta11:
	cpi temp1, 'h'
	brne ta12
	rcall lcd_home
	rjmp ta99
ta12:


.endif
ta99:
	ret

showrot:
	push temp1
	in temp1, sreg
	push temp1
	push temp2

	ldi temp1, 0
	ldi temp2, 1
	rcall lcd_position
	lds temp1, rot_wert
	rcall lcd_number

	pop temp2
	pop temp1
	out sreg, temp1
	pop temp1
	ret

showblau:
	push temp1
	in temp1, sreg
	push temp1
	push temp2

	ldi temp1, 10
	ldi temp2, 1
	rcall lcd_position
	lds temp1, blau_wert
	rcall lcd_number

	pop temp2
	pop temp1
	out sreg, temp1
	pop temp1
	ret

showgruen:
	push temp1
	in temp1, sreg
	push temp1
	push temp2

	ldi temp1, 5
	ldi temp2, 1
	rcall lcd_position
	lds temp1, gruen_wert
	rcall lcd_number

	pop temp2
	pop temp1
	out sreg, temp1
	pop temp1
	ret

.if debuglevel == 0
automatik:
	ldi temp1, 1
auto1:
	sts rot_wert,temp1
	sbi flag, frot
	rcall showrot
	inc temp1
	rcall delay5ms
	rcall delay5ms
	cpi temp1,255
	brlo auto1
	ldi temp1, 1
auto2:
	sts gruen_wert,temp1
	sbi flag, fgruen
	rcall showgruen
	rcall delay5ms
	rcall delay5ms
	inc temp1
	cpi temp1,255
	brlo auto2
	ldi temp1, 1
auto3:
	sts blau_wert,temp1
	sbi flag, fblau
	rcall showblau
	rcall delay5ms
	rcall delay5ms
	inc temp1
	cpi temp1,255
	brlo auto3
	ldi temp1, 255
auto5:
	sts gruen_wert,temp1
	sbi flag, fgruen
	rcall showgruen
	rcall delay5ms
	rcall delay5ms
	dec temp1
	cpi temp1,2
	brsh auto5
	ldi temp1, 255
auto4:
	sts rot_wert,temp1
	sbi flag, frot
	rcall showrot
	dec temp1
	rcall delay5ms
	rcall delay5ms
	cpi temp1,2
	brsh auto4
	ldi temp1, 255
auto6:
	sts blau_wert,temp1
	sbi flag, fblau
	rcall showblau
	rcall delay5ms
	rcall delay5ms
	dec temp1
	cpi temp1,2
	brsh auto6
	ret
.endif


null:
	ldi temp1, 1
	sts rot_wert,temp1
	sts blau_wert, temp1
	sts gruen_wert,temp1
	rcall showrot
	rcall showblau
	rcall showgruen
	sbi flag, fblau
	sbi flag, frot
	sbi flag, fgruen
	ret

blauminus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, blau_wert
	cpi temp1, 1
	brsh bminus
	rjmp bm99
bminus:
	dec temp1
	sts blau_wert,temp1
	sbi flag, fblau
	rcall showblau
bm99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret 

blauplus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, blau_wert
	cpi temp1, 255
	brne bplus
	rjmp bp99
bplus:
	inc temp1
	sts blau_wert,temp1
	sbi flag, fblau
	rcall showblau
bp99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret

rotminus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, rot_wert
	cpi temp1, 1
	brsh rminus
	rjmp rm99
rminus:
	dec temp1
	sts rot_wert,temp1
	sbi flag, frot
	rcall showrot
rm99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret

rotplus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, rot_wert
	cpi temp1, 255
	brne rplus
	rjmp rp99
rplus:
	inc temp1
	sts rot_wert,temp1
	sbi flag, frot
	rcall showrot
rp99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret

gruenminus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, gruen_wert
	cpi temp1, 1
	brsh gminus
	rjmp gm99
gminus:
	dec temp1
	sts gruen_wert,temp1
	sbi flag, fgruen
	rcall showgruen
gm99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret

gruenplus:
	push temp1
	push temp2
	in temp2,sreg
	lds temp1, gruen_wert
	cpi temp1, 255
	brne gplus
	rjmp gp99
gplus:
	inc temp1
	sts gruen_wert,temp1
	sbi flag, fgruen
	rcall showgruen
gp99:
	out sreg, temp2
	pop temp2
	pop temp1
	ret

dauerlauf:
.ifdef automatik
	rcall automatik
.endif
	rjmp dauerlauf

; *****************************************************************************************************
;	Konstanten
; *****************************************************************************************************

str_hallo:
	.db "RGB-Dimmer-Tool", 0

str_blank_line: 
	.db "                ",0
.exit




