; Rutina obsluhy I2C sběrnice
; Krystal 4MHz
; Power by M.Supík 2011

LIST P=16F628A,R=DEC 
INCLUDE<P16F628A.INC>  

;------------------------------------------------------------------------------
; Definice registrů
;------------------------------------------------------------------------------

TMP_W		EQU		27h			; Pomocný registr přerušení - obsah W
TMP_S		EQU		28h			; Pomocný registr přerušení - obsah Status
POZICE_ZNAKU EQU	29h			; Pozice znaku v tabulce - číslo řádku
ZNAK		EQU		2Ah			; Zobrazovaný znak 

;------------------------------------------------------------------------------
; !!! MUSÍ BÝT NA ADRESE 70h - 7Ah !!! Tyto adresy se zrcadlí v 0 a 1 Bance !!!
;------------------------------------------------------------------------------

I2C_DATA	EQU		70h			; Data pro zápis/čtení do/z externí EEprom ( 24CXX )
I2C_BITS	EQU		71h			; Počet odesílaných bitů ( počet opakování )
I2C_DAT		EQU		72h			; Data pro zápis - sem nezasahovat
I2C_ERR		EQU		73h			; 
I2C_ADRESA_H	EQU		74h			; Registr adresy EEprom - H
I2C_ADRESA_L	EQU		75h			; Registr adresy EEprom - L
;------------------------------------------------------------------------------
; Definice portů
;------------------------------------------------------------------------------

#define	SDA	PORTA,6		; I2C data
#define	SCL	PORTA,7		; I2C Hodiny

;------------------------------------------------------------------------------
; Direktivita ORG
;------------------------------------------------------------------------------

	ORG 	00h
	GOTO	INI_PIC

;------------------------------------------------------------------------------
; Inicializace procesoru
;------------------------------------------------------------------------------

INI_PIC
	movlw	b'00000000'
	movwf	PORTA
	movlw	b'00000000'
	movwf	PORTB

	movlw	b'00000111'			; Komparátor OFF
	movwf	CMCON 
	bsf		STATUS,RP0			; Banka 1
	movlw	b'00000000'			; TRISA
	movwf	TRISA
	movlw	b'00000010'			; TRISB	- RB1=RX=1
	movwf	TRISB
	bcf		STATUS,RP0			; Banka 0

	call	SET_RS232			; Nastavení seriového portu

	CLRF	I2C_ADRESA_H
	CLRF	I2C_ADRESA_L
	CLRF	I2C_DATA
	CLRF	I2C_BITS

START
	INCF	I2C_ADRESA_L
	BTFSC	STATUS,Z
	GOTO	CTI
	INCF	I2C_DATA
	CALL	I2C_WRITE
	GOTO	START

CTI
	CLRF	I2C_ADRESA_H
	CLRF	I2C_ADRESA_L
	CLRF	I2C_DATA
CTI1
	INCF	I2C_ADRESA_L
	BTFSC	STATUS,Z
	GOTO	KONEC	
	CALL	I2C_READ
	MOVFW	I2C_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK
	GOTO	CTI1
KONEC
NOP
GOTO $-1
	
	

;------------------------------------------------------------------------------
; Obsluha I2C sběrnice - EEprom
;------------------------------------------------------------------------------

I2C_WRITE						; Zápis dat do EEprom
	CALL	I2C_START			; Podprogram START sekvence

	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
	CALL	I2C_SEND			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_WRITE_END		; Ne, ukonči zápis

	MOVFW	I2C_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_SEND			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_WRITE_END		; Ne, ukonči zápis

	MOVFW	I2C_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_SEND			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_WRITE_END		; Ne, ukonči zápis

	MOVFW	I2C_DATA			; Data k zápisu do W
	CALL	I2C_SEND			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_WRITE_END		; Ne, ukonči zápis

	CALL	I2C_STOP			; Podprogram STOP sekvence
I2C_WRITE_END
	RETURN						; Konec zápisu


I2C_READ						; Čtení dat z EEprom
	CALL	I2C_START			; Podprogram START sekvence
	
	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
								; !!! R/W = 0 !!! Zápis adresy
	CALL	I2C_SEND			; Odešle 1 byte - zápis adresy
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_READ_END		; Ne, ukonči čtení

	MOVFW	I2C_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_SEND			; Odešle 1 byte - zápis adresy
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_READ_END		; Ne, ukonči čtení

	MOVFW	I2C_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_SEND			; Odešle 1 byte - zápis adresy
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_READ_END		; Ne, ukonči čtení

	CALL	I2C_START			; Opakuj sekvenci START

	MOVLW	b'10100001'			; !!! R/W = 1 !!! Teď už čtení
	CALL	I2C_SEND			; Odešle 1 byte 
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání v pořádku
	GOTO	I2C_READ_END		; Ne, ukonči čtení

	CALL	I2C_RECIVE			; Podprogram čtení dat z EEprom - do I2C_DATA
	
	CALL	I2C_STOP			; Podprogram sekvence STOP
I2C_READ_END
	RETURN

I2C_START 						; Odeslání START sekvence
	BSF		STATUS,RP0			; Banka 1
	BSF		SDA					; SDA do H ( vstup - odpory táhnou sběrnici nahoru )
	BSF		SCL					; SCL do H ( vstup - odpory táhnou sběrnici nahoru )
	NOP
	BCF		SDA					; SDA do L ( výstup - uroven nula)
	BCF		STATUS,RP0			; Banka 0
	RETURN
	
I2C_STOP  						; Odeslání STOP sekvence
	BSF		STATUS,RP0			; Banka 1
	BCF		SDA					; SDA do L ( výstup - uroven nula)
	BSF		SCL 				; SCL do H ( vstup - odpory táhnou sběrnici nahoru )
	NOP							; Cekej 1us
	BSF		SDA					; SDA do H ( vstup - odpory táhnou sběrnici nahoru )
	BCF		STATUS,RP0			; Banka 0
	RETURN
	
I2C_SEND 						; Procedůra na odeslání 8bit slova a vyčkání na ACK
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; SCL do L ( výstup - uroven nula)
	MOVWF	I2C_DAT 			; Přesunutí W do I2C_DAT
	MOVLW	8
	MOVWF	I2C_BITS			; Počet odesílaných bitů (8)
I2C_SEND_LOOP
	BCF		SCL					; Vynulujeme hodiny (při prvním průchod nemá smysl)
	BCF		SDA					; Vynulujeme data na SDA
	RLF		I2C_DAT,F			; Rotujeme daty vlevo přes C
	BTFSC	STATUS,C			; Je C = 1?
	BSF		SDA					; Ano - Nastavíme data do 1
	BSF		SCL					; Nastavíme hodiny
	BTFSS	SCL
	GOTO	$-1
	BCF		SCL
	DECFSZ	I2C_BITS,F			; Odecteme 1 od čítače a pokud neni nula
	GOTO	I2C_SEND_LOOP		; Jdeme na začátek odesílání
	NOP
	NOP
	BCF		SCL					; Vynulujeme hodiny (odeslání posledního bitu)
	BSF		SDA					; Nastavení DAT do 1 pro čekání na ACK
	NOP
	NOP
	BSF		SCL
	BCF		STATUS,RP0
I2C_SEND_WAIT_ACK				; Cekani na ACK CCA 1.5ms
	INCF	I2C_BITS			; Pricteni 1 k citeci
	BTFSC	STATUS,Z			; Overeni jestli pretekl citac (pokud ano, cekani na ACK se nezdarilo)
	GOTO	I2C_ERROR			; Skok na proceduru osetrujici chybu
	BTFSC	SDA					; Jsou data v nule? (ACK)
	GOTO	I2C_SEND_WAIT_ACK   ; Pokud ne čekáme dál
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; Nastavení SCL do nuly (po přijetí ACK)
	BCF		STATUS,RP0			; Banka 0
	RETURN
	
I2C_RECIVE 						; Procedůra na přijmutí 8bit slova a potvrzení ACK
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; Nastavení SCL do nuly
	BSF		SDA					; SDA do 1 (příjem dat)
	MOVLW	8
	MOVWF	I2C_BITS			; Počet odesílaných bitů (8)
I2C_RECIVE_LOOP
	BSF		SCL					; Nastavíme SCL do 1 
	BCF		STATUS,RP0			; Nastavíme banku 0
	RLF		I2C_DATA,F			; Posuneme přijmaná data o jeden bit do leva
	BCF		I2C_DATA,0			; Vynulujeme poslední bit
	BTFSC	SDA					; Pokud je na dat. zběrnici 1
	BSF		I2C_DATA,0			; Nastavíme poslední bit do 1
	BSF		STATUS,RP0			; Přepneme na banku 1
	BCF		SCL					; Nastavíme SCL do nuly
	DECFSZ	I2C_BITS,F			; Odecteme 1 od čítače a pokud neni nula
	GOTO	I2C_RECIVE_LOOP		; Jdeme na začátek odesílání
	BCF		SDA					; Nastavíme data do 0 (ACK)
	BSF		SCL					; Nastavíme SCL do 1
	NOP					
	NOP							; Čekání 3cykly (3us)
	NOP
	BCF		SCL					; Nastavíme SCL do 0
	BCF		STATUS,RP0			; Banka 0
	RETURN

I2C_ERROR						; Procedůra se volá pokud nedojde k přijmutí ACK bitu
	BSF		I2C_ERR,0			; Nastaví se příznak chyby I2C_ERR = 1
	CALL	I2C_STOP			; Pošle se stop byt (po NO ACK musí následovat stop bit)
	RETURN		

;------------------------------------------------------------------------------
; Obsluha seriové linky
;------------------------------------------------------------------------------

SET_RS232	
	bsf		STATUS,RP0			; Banka 1
	movlw	25					; 9600b, krystal 4,00MHz, HighSpeed
	movwf	SPBRG
	movlw	b'00100110'			; 8bit, vysílání povoleno, asynchroní mod, vysoká rychlost
	movwf	TXSTA				; Nastavení vysílání !!!
	bcf		STATUS,RP0			; Banka 0

	movlw	b'10010000'			; povolen sériový port, 8bit, asynchroní mod
	movwf	RCSTA				; Nastavení příjmu !!!

	RETURN

;	bsf		TXSTA,BRGH			; BRGH=1 HighSpeed, BRGH=0 LowSpeed
;	bsf		TXSTA,TXEN			; 1=povoleno vysílání, 0=zakázáno vysílání
;	bsf		RCSTA,SPEN			; 1=povolena komunikace po RS232 (příjem i vysílání)
;	bsf		RCSTA,CREN			; 1=povolen pokračující příjem



VYSILANI_ZNAK
	btfss	PIR1,TXIF			; Testuj, zda se může vysílat
	goto	$-1					; =0, 0=buffer je plny, 1=buffer je prazdny
	MOVFW	ZNAK				; Znak do W
	movwf	TXREG				; W -> do TX registru
	RETURN

PRIJEM_ZNAK
	btfss	PIR1,RCIF			; Testuj, zda je co přijmout
	goto	$-1					; =0, 0=buffer je prazdny, 1=buffer je plny
	movf	RCREG,W				; prijmuta data -> do W
	movwf	ZNAK				; Prijmuta data do ZNAK
	RETURN

;------------------------------------------------------------------------------
; KONEC
;------------------------------------------------------------------------------
	
	END