;+-----------------------------------------------------------------------------
;| Title						: LCD-Spielereien
;+-----------------------------------------------------------------------------
;| Funktion						: Nichts besonderes
;| Schaltung					: LCD-AddOn an Erweiterungsbuchse, evtl. Eingabe
;|								: oder Ausgabe (siehe Quelltext)
;+-----------------------------------------------------------------------------
;| Prozessor					: ATmega8
;| Takt							: 3,6864 MHz
;| Sprache						: Assembler
;| Datum						: 16.05.11
;| Version						: build160511
;| Autor						: Thomas Schneider
;+-----------------------------------------------------------------------------
.include		"m8Adef.inc"
;------------------------------------------------------------------------------
begin:	rjmp	main				;  RESET External Pin, Power-on Reset, Brown-out
									;  Reset and Watchdog Reset
		reti						;  INT0 External Interrupt Request 0
		reti						;  INT1 External Interrupt Request 1
		reti						;  TIMER2 COMP Timer/Counter2 Compare Match
		reti						;  TIMER2 OVF Timer/Counter2 Overflow
		reti						;  TIMER1 CAPT Timer/Counter1 Capture Event
		reti						;  TIMER1 COMPA Timer/Counter1 Compare Match A
		reti						;  TIMER1 COMPB Timer/Counter1 Compare Match B
		reti						;  TIMER1 OVF Timer/Counter1 Overflow
		reti						;  TIMER0 OVF Timer/Counter0 Overflow
		reti						;  SPI, STC Serial Transfer Complete
		reti						;  USART, RXC USART, Rx Complete
		reti						;  USART, UDRE USART Data Register Empty
		reti						;  USART, TXC USART, Tx Complete
		rjmp	onADC				;  ADC ADC Conversion Complete
		reti						;  EE_RDY EEPROM Ready
		reti						;  ANA_COMP Analog Comparator
		reti						;  TWI 2-wire Serial Interface
		reti						;  SPM_RDY Store Program Memory Ready
;------------------------------------------------------------------------------
main:	ldi			r16,HIGH(RAMEND)	; Main program start
		out			SPH,r16				; Set Stack Pointer to top of RAM
		ldi			r16,LOW(RAMEND)
		out			SPL,r16
		sbi			DDRB,0
		sei
		; AD-Wandlereinstellungen
		ldi			r16,0
		out			ADMUX,r16
		ldi			r16,0b11011101
		out			ADCSRA,r16
		;---
		rcall		initUART
		rcall		LCD_init
		rcall		LCD_clear
		rcall		initPWM
		rcall		Char_def
;------------------------------------------------------------------------------
			ldi		r20,100
			ldi		r21,20
mainloop:	wdr
			rcall	wait
			rcall	wait
			mov		r20,r25			; ADC Wert holen
			andi	r20,0b00001111	; untere Bits maskieren (0-15)
			cp		r20,r28			; nur bei Änderungen des Wertes das Display
			breq	mainloop		; aktualisieren (flimmert sonst)
			mov		r28,r20
			mov		r16,r25			; für Debug/Kontrolle auf Terminal
			rcall	putChar
			rcall	LCD_clear
			ldi		r16,16			; Zeichen je Zeile
			mov		r15,r16
balken:		cpi		r20,0
			breq	mainloop		; Wenn ADC-Wert = 0
			dec		r15
			mov		r16,r15
			lsr		r16				; ADC-Werte (0-15) geteilt durch 2 (0-7)
			rcall	LCD_data		; Anzeige mit selbstdefinierten Zeichen
			dec		r20
			rjmp	balken
;------------------------------------------------------------------------------
onADC:		cli						; Interrupts sperren
			in		r26,ADCL		; 10 Bit ADC-Daten holen
			in		r27,ADCH
			asr		r27
			ror		r26
			asr		r27
			ror		r26
			ror		r26				; auf 4 Bit reduzieren
			ror		r26
			ror		r26
			ror		r26
			andi	r26,0b00001111
			mov		r25,r26			; Datenüberagabe an main
			sbi		ADCSRA,6		; nächste Wandlung starten
			sei						; Interrupts erlauben
			reti
;------------------------------------------------------------------------------
Char_def:	push	r16
			push	r30
			push	r31
			push	r19
			ldi		r30,LOW(symbole-begin)	; Zeiger Z auf Zeichen im
			ldi		r31,HIGH(symbole-begin)	; Flash, siehe Ende!
			;................. Alle Zeichen in den CGRAM laden
			ldi		r19,0b01000000			; Kommando CGRAM Adresse 0x00
def_next:	mov		r16,r19					; 0b010aaaaa
			rcall	LCD_cmd					; Kommando CGRAM.Adresse
			lpm								; hole Zeichen r0=[Z]
			mov		r16,r30					; Übertrage Bitmuster an LCD
			rcall	LCD_data
			adiw	r30,1					; Z+1
			inc		r19						; CGRAM Adresse + 1
			cpi		r19,0b01111111			; letzte CGRAM Adresse?
			brne	def_next				; nein->weiter
			;................. alle Zeichen sind in den CGRAM geladen
			pop		r19
			pop		r31
			pop		r30
			pop		r16
			ret

;------------------------------------------------------------------------------
initPWM:	push	r16
			sbi		DDRB,1
			sbi		PORTB,1
			ldi		r16,0b10000001
			out		TCCR1A,r16
			ldi		r16,0x02
			out		TCCR1B,r16
			ldi		r16,80
			out		OCR1AL,r16
			ldi		r16,0
			out		OCR1AH,r16
			pop		r16
			ret
;------------------------------------------------------------------------------
wait:		push	r24
			ldi		r24,0x13		; hier delay einstellen 13 = ca. 20yS
w1:			subi	r24,1
			rcall	wait20ms
			brcc	w1
			pop r24
			ret
;------------------------------------------------------------------------------
wait5ms:	push	r24
			push	r25
			ldi		r25 , 50
loop1:		ldi		r24 , 123
loop2:		dec		r24
			brne	loop2
			dec		r25
			brne	loop1
			pop		r25
			pop		r24
			ret
;------------------------------------------------------------------------------
wait20ms:	ldi		r16,255
			ldi		r17,104
w20ms:		dec		r16
			brne	w20ms
			dec		r17
			brne	w20ms
			ret
;------------------------------------------------------------------------------
LCD_init:	ldi		r16,0b11111100	; LCD {RS;E;D4;D5;D6;D7}=OUT
			out		DDRD,r16
			cbi		PORTd,2			; LCD RS=LOW
			; warte bis PowerUp
			ldi		r18,10
powerup:	rcall wait5ms
			dec		r18
			brne	powerup			; Power-Up Wartezyklus min 30 ms
			; sende init 1
			ldi		r16, 0b00100000	; 4-Bit-Modus aktivieren
			out		PORTD,r16
			rcall	LCD_enable		; Enable-Impuls
			rcall 	wait5ms
			ldi 	r16,0b00101000
			rcall	LCD_cmd
			rcall	LCD_off
			rcall	LCD_clear
			ldi		r16,0x06
			rcall	LCD_cmd			; Entry Mode Set, increase+shifted
			rcall	LCD_on
			ret
;------------------------------------------------------------------------------
LCD_data:	ldi		r18,0b00000100	; RS=hi
			rjmp	LCD_out
;------------------------------------------------------------------------------
LCD_cmd:	ldi		r18,0x00
LCD_out:	mov		r17,r16
			swap	r17
			andi	r16,0b11110000
			or		r16,r18
			andi	r17,0b11110000
			or		r17,r18
			out		PORTD,r16
			rcall	LCD_enable
			out		PORTD,r17
			rcall	LCD_enable
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_enable:	sbi		PORTD,3			; Enable hi
			nop
			nop
			nop						; kurz warten
			cbi		PORTD,3			; Enable wieder lo
			ret
;------------------------------------------------------------------------------
LCD_clear:	ldi		r16,0b00000001	; Display löschen
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_home:	ldi		r16,0b00000010	; Display-Cursor HOME
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_off:	ldi		r16,0b00001000
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_on:		ldi		r16,0b00001110
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_line1:	ldi		r16,0b10000000	; DRAM auf Adresse 0x00
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_line2:	ldi		r16,0b11000000
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
; Goto r16=Adresse (Zeile 1=0x00..0x0F, Zeile 2=0x40..0x4F)
LCD_goto:	ori		r16,0b10000000
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_CUL:	ldi		r16,0b00010000	; Cursor eins nach links
			rcall	LCD_CMD
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------
LCD_CUR:	ldi		r16,0b00010100	; Cursor eins nach rechts
			rcall	LCD_cmd
			rcall	wait5ms
			ret
;------------------------------------------------------------------------------

;---------- Unterprogramm: initUART, initialisiert UART Pollin bei 9600 Baud
initUART:	push	r16
			sbi		UCR,4			; UCSRB=0x0B RXEN=Bit4 RX aktivieren
			sbi		UCR,3			; UCSRB=0x0B UDRE=Bit3 TX aktiv
			ldi		r16,3686400/(9600*16)-1	; Baudrate 9600 einstellen
			out		UBRRL,r16
			pop		r16
			ret
;---------- Unterprogramm: putChar, sendet ein Zeichen aus r16 per UART
putChar:	sbis	0x0B,5			; UCSRA=0x0B UDRE=Bit5
			rjmp	putChar			; warten, bis UDR bereit
			out		UDR,r16			; senden
			ret						; zurück zum Hauptprogramm
;------------------------------------------------------------------------------
.DSEG
symbole:
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
;.................
.byte	0b00000000
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
;.................
.byte	0b00000000
.byte	0b00000000
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
;.................
.byte	0b00000000
.byte	0b00000000
.byte	0b00000000
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
;.................
.byte	0b00000000
.byte	0b00000000
.byte	0b00000000
.byte	0b00000000
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
.byte	0b11111111
;.................
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0xFF
.byte	0xFF
.byte	0xFF
;.................
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0xFF
.byte	0xFF
;.................
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0x00
.byte	0xFF
;.................

