; Rutina obsluhy I2C sběrnice
; Krystal 4MHz
; Power by M.Supík 2011

LIST P=16F628A,R=DEC 
INCLUDE<P16F628A.INC>  

;------------------------------------------------------------------------------
; Definice registrů
;------------------------------------------------------------------------------

EEPROM_ADRESA_H		EQU		21h			; Horních 8 bitů adresy zápisu/čtení
EEPROM_ADRESA_L		EQU		22h			; Dolních 8 bitů adresy zápisu/čtení
EEPROM_DATA			EQU		23h			; Data pro zápis do EEPROM

I2C_BITS	EQU		24h			; Počet odesílaných/přijímaných bitů
I2C_DATA	EQU		25h			; Data pro zápis na I2C sběrnici

POZICE_ZNAKU EQU	26h			; Pozice znaku v tabulce - číslo řádku
ZNAK		EQU		27h			; Zobrazovaný znak 


;------------------------------------------------------------------------------
; Definice portů
;------------------------------------------------------------------------------

#DEFINE SCL         PORTA,7
#DEFINE SDA         PORTA,6
#DEFINE SCLDIR      TRISA,7
#DEFINE SDADIR      TRISA,6

;------------------------------------------------------------------------------
; Direktivita ORG
;------------------------------------------------------------------------------

	ORG 	00h
	GOTO	INI_PIC

;------------------------------------------------------------------------------
; Inicializace procesoru
;------------------------------------------------------------------------------

INI_PIC
	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	EEPROM_ADRESA_H

	CLRF	EEPROM_DATA

START
	MOVLW	5
	MOVWF	EEPROM_ADRESA_L
	MOVLW	5
	MOVWF	EEPROM_DATA
	CALL	EEPROM_WRITE

	CALL	Delay10ms 

	MOVLW	15
	MOVWF	EEPROM_ADRESA_L
	MOVLW	15
	MOVWF	EEPROM_DATA
	CALL	EEPROM_WRITE

	CALL	Delay10ms 

	MOVLW	6
	MOVWF	EEPROM_ADRESA_L
	CALL	EEPROM_READ
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	Delay10ms 

	MOVLW	16
	MOVWF	EEPROM_ADRESA_L
	CALL	EEPROM_READ
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK
KONEC
NOP
GOTO $-1
	

Delay10ms 
    movlw   0x0A 
    movwf   EEPROM_DATA 
 Delay_Start 
    nop 
    movlw 0x07   ; 249 cycles * 4us per cycle + 5us = 1.000ms 
 Delay 
    addlw 0x01 
    btfss STATUS, Z 
    goto Delay 
    decfsz EEPROM_DATA, 1 
    goto Delay_Start 
    return



EEPROM_READ						; Čtení jednoho byte z určené adresy
        CALL    I2C_START		; Podprogram START sekvence pro I2C sběrnici

		MOVLW   B'10100000'		; Definuje: typ zařízení XXXX0000 ( 1010 - 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_WRITE		; Odešle 1 byte na sběrnici

		MOVFW	EEPROM_ADRESA_H	; Horních 8 bitů adresy čtení do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

      	MOVFW	EEPROM_ADRESA_L	; Dolních 8 bitů adresy čtení do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		CALL    I2C_START		; Opakuj sekvenci START

		MOVLW   B'10100001'		; Definuje: typ zařízení XXXX0000 ( 1010 - 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1 
								; !!! R/W = 1 !!! Teď už čtení
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

	    CALL    I2C_READ		; Podprogram čtení dat z EEprom - do EEPROM_DATA

		CALL    I2C_STOP		; Podprogram sekvence STOP
		RETURN

EEPROM_READ_PAGE				; Čtení více dat od určené adresy
        CALL    I2C_START		; Podprogram START sekvence pro I2C sběrnici

		MOVLW   B'10100000'		; Definuje: typ zařízení XXXX0000 ( 1010 - 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_WRITE		; Odešle 1 byte na sběrnici

		MOVFW	EEPROM_ADRESA_H	; Horních 8 bitů adresy čtení do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

      	MOVFW	EEPROM_ADRESA_L	; Dolních 8 bitů adresy čtení do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		CALL    I2C_START		; Opakuj sekvenci START

		MOVLW   B'10100001'		; Definuje: typ zařízení XXXX0000 ( 1010 - 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1 
								; !!! R/W = 1 !!! Teď už čtení
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

        CALL    I2C_READ		; Podprogram čtení dat z EEprom - do EEPROM_DATA
		CALL	I2C_ACK			; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)
	
		CALL    I2C_READ		; Podprogram čtení dat z EEprom - do EEPROM_DATA
		CALL	I2C_ACK			; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)
	
		CALL    I2C_READ		; Podprogram čtení dat z EEprom - do EEPROM_DATA
								; !!! u posledního přijímaného byte se NEodesílá ACK !!!
		CALL    I2C_STOP		; Podprogram sekvence STOP
		RETURN


EEPROM_WRITE					; Zápis jednoho byte do určené adresy
		CALL    I2C_START		; Podprogram START sekvence pro I2C sběrnici

		MOVLW   B'10100000'		; Definuje: typ zařízení XXXX0000 ( 1010 - 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1 
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		CALL	Delay10ms

        MOVFW	EEPROM_ADRESA_H	; Horních 8 bitů adresy zápisu do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		MOVFW	EEPROM_ADRESA_L	; Dolních 8 bitů adresy zápisu do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		MOVFW	EEPROM_DATA
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

	
		CALL    I2C_STOP		; Podprogram sekvence STOP

		RETURN

EEPROM_WRITE_PAGE				; Zápis více dat od určené adresy
		CALL    I2C_START		; Podprogram START sekvence pro I2C sběrnici

      	MOVLW   B'10100000'		; Definuje: typ zařízení XXXX0000 ( 1010 - 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1 
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

        MOVFW	EEPROM_ADRESA_H	; Horních 8 bitů adresy zápisu do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

      	MOVFW	EEPROM_ADRESA_L	; Dolních 8 bitů adresy zápisu do W
		CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

								; Zápis více dat od určené adresy. Data se zapisují hned po sobě - bez sekvence
								; !!! Maximální zápis 32 bytů najednou !!!
								; Sekvence STOP se zapisuje až nakonec
	
		MOVLW   H'01'
     	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'02'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'03'
      	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

        MOVLW   H'04'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'05'
      	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'06'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

        MOVLW   H'07'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'08'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici
        MOVLW   H'09'
       	CALL    I2C_WRITE		; Odešle 1 byte na sběrnici

		CALL    I2C_STOP		; Podprogram sekvence STOP se zapisuje až nakonec
		RETURN


I2C_READ						; Příjem 1 byte do EEPROM_DATA
        MOVLW   8 
        MOVWF   I2C_BITS        ; Počet přijímaných bitů (8)

        BSF     STATUS,RP0      ; Banka 1
        BSF     SDADIR          ; SDA - vstup
        BCF     STATUS,RP0		; Banka 0
    
I2C_READ_BITS
        CALL    CEK10     		; Čekej 10 us
        BSF     SCL             ; SCL do H (1)
        CALL    CEK10     		; Čekej 10 us

        BCF     STATUS,C        ; Vynuluje bit, přes který se bude rolovat
        BTFSC   SDA             ; Otestuj SDA, zda je ve vysoké úrovni ( přijímaný bit = 1 )
        BSF     STATUS,C        ; ANO, zapiš 1 do C ( přijímaný bit = 1)
								; Ne, v C je 0	( přijímaný bit = 0)
        CALL    CEK10		    ; Čekej 10 us
        BCF     SCL             ; SCL - L (0)

        RLF     EEPROM_DATA,F	; Rotace EEPROM_DATA přes C doleva - postupné uložení jednotlivých bitů
        DECFSZ  I2C_BITS,F		; Počet přijímaných bitů -1 - počet opakování příjmu 1 bitu - 8x
        GOTO    I2C_READ_BITS	; Cyklus - opakování příjmu 1 bitu - 8x
        
		CALL    CEK10     		; Pauza cca 10us

        BCF     SDA             ; SDA = 0
        BSF     STATUS,RP0		; Banka 1
        BCF     SDADIR          ; SDA výstup
        BCF     STATUS,RP0		; Banka 0
		RETURN

I2C_SEND_ACK					; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)
        BCF     SDA             ; SDA - 0
        CALL    CEK10    		; Pauza cca 10us
        BSF     SCL             ; SCL - 1
        CALL    CEK10    		; Pauza cca 10us
        BCF     SCL             ; SCL - 0
		RETURN

I2C_WRITE       
		MOVWF   I2C_DATA		; Obsah W do I2C_DATA
        MOVLW   8           
        MOVWF   I2C_BITS		; Počet odesílaných bitů - 8
I2C_WRITE_BITS
        RLF     I2C_DATA,F		; Rotace I2C_DATA přes C doleva

        BTFSS   STATUS,C        ; Otestujeme C, zda je jedna 
        GOTO    $+3 			; NE, odešle 0
        BSF     SDA             ; ANO, odešle 1
        GOTO    $+2 
        BCF     SDA             ; SDA - 0

        CALL    CEK10     		; Čekej 10us
        BSF     SCL             ; SCL - 1
        CALL    CEK10    		; Čekej 10us
        BCF     SCL             ; SCL - 0;

        DECFSZ  I2C_BITS,F      ; Počet odesílaných bitů -1 - počet opakování odesílání 1 bitu - 8x     
        GOTO    I2C_WRITE_BITS  ; Cyklus - opakování odesílání 1 bitu - 8x
        
        CALL    CEK10     		; Čekej 10us
       	
I2C_ACK							; ACK - příjem ACK bitu
        BSF     STATUS,RP0      ; Banka 1
        BSF     SDADIR          ; SDA - vstup
        BCF     STATUS,RP0		; Banka 0
        CALL    CEK10     		; Čekej 10us
        BSF     SCL             ; SCL = 1

        CALL    CEK10     		; Čekej 10us
        BTFSC   SDA				; Otestuj ACK, zda je jedna
        GOTO    $-1				; ANO, čekej, dokud ACK se nerovná 1
        CALL    CEK10     		; Čekej 10us

        BCF     SCL             ; SCL - 0
        CALL    CEK10     		; Čekej 10us
        BCF     SDA             ; SDA - 0
        BSF     STATUS,RP0		; Banka 1
        BCF     SDADIR          ; SDA výstup
        BCF     STATUS,RP0		; Banka 0
        RETURN

I2C_START						; Podprogram sekvence START
        BSF     SDA             ; SDA - 1
        BSF     STATUS,RP0		; Banka 1
        BCF     SDADIR          ; SDA - výstup
        BCF     STATUS,RP0		; Banka 0
        BSF     SCL             ; SCL - 1
        CALL    CEK10     		; Čekej 10us
        BCF     SDA             ; SDA - 0
        CALL    CEK10     		; Čekej 10us
        BCF     SCL             ; SCL - 0
        RETURN

I2C_STOP						; Podprogram sekvence STOP
        CALL    CEK10     		; Čekej 10us
        BCF     SDA             ; SDA = 0
        CALL    CEK10   		; Čekej 10us
        BSF     SCL             ; SCL = 1
        CALL    CEK10    		; Čekej 10us
        BSF     SDA             ; SDA = 1
        BSF     STATUS,RP0		; Banka 1
        BCF     SDADIR          ; SDA vstup
        BCF     STATUS,RP0		; Banka 0
        RETURN

CEK10
        GOTO    $+1
        GOTO    $+1
 GOTO    $+1
 GOTO    $+1
        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