Autor Tema: Libreria BUS_I2C.INC para pic 16F84A.  (Leído 9651 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Libreria BUS_I2C.INC para pic 16F84A.
« en: 01 de Enero de 2009, 21:33:44 »
;****************************Librería "BUS_I2C.INC"*************************************
;
;Estas subrutinas permiten realizar las tareas básicas de control del bus serie I2C,
;por parte de un solo microcontrolador maestro.
;
;ZONA DE DATOS**************************************************************************

       CBLOCK
       I2C_ContadorBits                       ;Cuenta los bits a transmitir o a recibir.
       I2C_Dato                               ;Dato a transmitir o recibido.
       I2C_Flags                              ;Guarda la información del estado del bus I2C.
       ENDC

#DEFINE I2C_UltimoByteLeer I2C_Flags,0
; - (I2C_UltimoByteLeer)=0, NO es el último byte a leer por el maestro.
; - (I2C_UltimoByteLeer)=1, SI es el último byte a leer por el maestro.

;La definición de las líneas SCL y SDA del bus I2C se puede cambiar según las
;necesidades del hardware.

#DEFINE SCL      PORTA,3                      ;Línea SCL del bus I2C.
#DEFINE SDA      PORTA,4                      ;Línea SDA del bus I2C.

;Subrutina "SDA_Bajo"********************************************************************

SDA_Bajo
        bsf          STATUS,RP0               ;Configura la línea SDA como salida.
        bcf          SDA
        bcf          STATUS,RP0
        bcf          SDA                      ;SDA en bajo.
        return

;Subrutina "SDA_AltaImpedancia"**********************************************************

SDA_AltaImpedancia     
        bsf          STATUS,RP0               ;Configura la línea SDA entrada.
        bsf          SDA                      ;Lo pone en alta impedancia y, gracias a la
        bcf          STATUS,RP0               ;Rp de esta línea, se mantiene a nivel alto.
        return

;Subrutina"SCL_Bajo"*********************************************************************

SCL_Bajo
        bsf          STATUS,RP0
        bcf          SCL                      ;Configura la línea SCL como salida.
        bcf          STATUS,RP0
        bcf          SCL                      ;La línea de reloj SCL en bajo.
        return

;Subrutina "SCL_AltaImpedancia"**********************************************************

SCL_AltaImpedancia
        bsf          STATUS,RP0               ;Configura la línea SCL entrada.
        bsf          SCL                      ;Lo pone en alta impedancia y, gracias a la Rp
        bcf          STATUS,RP0               ;de esta línea, se mantiene a nivel alto.
SCL_EsperaNivelAlto
        btfss        SCL                      ;Si algún esclavo mantiene esta línea en bajo
        goto         SCL_EsperaNivelAlto      ;hay que esperar.
        return


;Subrutina "I2C_EnviaStart"**************************************************************

;Esta subrutina envía una condición de Start o inicio.

I2C_EnviaStart
        call         SDA_AltaImpedancia       ;Línea SDA en alto.
        call         SCL_AltaImpedancia       ;Linea SCL en alto.
        call         Retardo_4micros          ;Tiempo tBUF del protocolo.
        call         SDA_Bajo                 ;Flanco de bajada de SDA mientras SCL está en alto.
        call         Retardo_4micros          ;Tiempo tHD;STA del protocolo.
        call         SCL_Bajo                 ;Flanco de bajada del reloj SCL.
        call         Retardo_4micros
        return

;Subrutina "I2C_EnviaStop"***************************************************************

;Esta subrutina envía una condición de Stop o parada.

I2C_EnviaStop
        call         SDA_Bajo
        call         SCL_AltaImpedancia       ;Flanco de subida de SCL.
        call         Retardo_4micros          ;Tiempo tSU;STO del protocolo.
        call         SDA_AltaImpedancia       ;Flanco de subida de SDA.
        call         Retardo_4micros          ;Tiempo tBUF del protocolo.
        return

;Subrutina "I2C_EnviaByte"***************************************************************

;El microcontrolador maestro transmite un byte por el bus I2C, comenzando por el bit
;MSB. El byte a transmitir debe estar cargado previamente en el registro de trabajo W,
;de la subrutina ejecutada anteriormente I2C_EnviaStart o esta misma I2C_EnviaByte,
;la línea SCL se debe encontrar a nivel bajo al menos durante 5us.

I2C_EnviaByte
        movwf        I2C_Dato                 ;Almacena el byte a transmitir.
        movlw        0x08                     ;A transmitir 8 bits.
        movwf        I2C_ContadorBits
I2C_EnviaBit
        rlf          I2C_Dato,F               ;Chequea el bit, llevándolo previamente al Carry.
        btfsc        STATUS,C
        goto         I2C_EnviaUno
I2C_EnviaCero
        call         SDA_Bajo                 ;Si es "0" envía un nivel bajo.
        goto         I2C_FlancoSCL
I2C_EnviaUno
        call         SDA_AltaImpedancia       ;Si es "1" lo activará alto.
I2C_FlancoSCL
        call         SCL_AltaImpedancia        ;Flanco de subida del SCL.
        call         Retardo_4micros          ;Tiempo tHIGH del protocolo.
        call         SCL_Bajo                 ;Termina el semiperiodo positivo del reloj.
        call         Retardo_4micros          ;Tiempo tHD;DAT del protocolo.
        decfsz       I2C_ContadorBits,F       ;Lazo para los ocho bits.
        goto         I2C_EnviaBit

        call         SDA_AltaImpedancia       ;Libera la línea de datos.
        call         SCL_AltaImpedancia       ;Pulso en alto de reloj para que el esclavo
        call         Retardo_4micros          ;pueda envíar el bit ACK.
        call         SCL_Bajo
        call         Retardo_4micros
        return

;Subrutina "I2C_LeeBit"*******************************************************************

;El microcontrolador maestro lee un byte desde el esclavo conectado al bus I2C. El dato
;recibido se carga en el registro I2C_Dato y lo envía a la subrutina superior a través
;del registro W .Se empieza a leer por el bit de mayor peso MSB.
;De alguna de las subrutinas ejecutadas anteriormente I2C_EnviaStart, I2C_EnviaByte
;o esta misma I2C_LeeByte, la línea SCL lleva en bajo al menos 5 us.

I2C_LeeByte
        movlw        0x08                     ;A recibir 8 bits.
        movwf        I2C_ContadorBits
        call         SDA_AltaImpedancia       ;Deja libre la línea de datos.
I2C_LeeBit
        call         SCL_AltaImpedancia       ;Flanco de subida del reloj.
        bcf          STATUS,C                 ;En principio supone que es "0".
        btfsc        SDA                      ;Lee el bit
        bsf          STATUS,C                 ;Si es "1" carga en el carry.
        rlf          I2C_Dato,F               ;Lo introduce en el registro.
        call         SCL_Bajo                 ;Termina el semiperiodo positivo del reloj.
        call         Retardo_4micros          ;Tiempo tHD;DAT del protocolo.
        decfsz       I2C_ContadorBits,F       ;Lazo para los 8 bits.
        goto         I2C_LeeBit

;Chequea si este es el último byte a leer para enviar o no el bit de reconocimiento
;ACK en consecuencia.

        btfss        I2C_UltimoByteLeer       ;Si es el último, no debe envíar
                                              ;el bit de reconocimiento AK.
        call         SDA_Bajo                 ;Envía el bit de reconocimiento ACK
                                              ;porque todavía no es el último byte a leer.
        call         SCL_AltaImpedancia       ;Pulso en alto del SCL para transmitir el
        call         Retardo_4micros          ;bit ACK de reconocimiento. Este es tHIGH.
        call         SCL_Bajo                 ;Pulso de parada del SCL.
        call         Retardo_4micros
        movf         I2C_Dato,W               ;El resultado se manda en el registro de
        return                                ;trabajo W.





Espero que os sirvan, lo he simulado en Proteus sin éxito, pero ya no me fio del puñetero PROTEUS.
« Última modificación: 02 de Enero de 2009, 07:39:56 por antimason »

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #1 en: 02 de Enero de 2009, 07:42:00 »
Había un error en la subrutina "SDA_AltaImpedancia", ya lo he reeditado.

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #2 en: 02 de Enero de 2009, 17:33:04 »
Aquí dejo otro código que por lo menos da muestra en el proteus generar actividad en una eeprom externa, pero no se simula correctamente y la salida a leds
no corresponde con lo que se espera del programa. (al final me tendré que hacer con un simulador hardware), espero que os sirva de ayuda y me digais que tal
os ha ido con uno u otro código en la realidad.







;PROTOCOLO I2C POR SOFWARE PARA COMUNICACIÓN DEL PIC 16F84A CON MEMORIAS EXTERNAS I2C, 24CXX.
;XTAL = 4 Mhz.



              LIST P=16F84A
              INCLUDE "P16F84A.inc"
   
   
EEPROM        EQU 1CH
ADDR          EQU 1DH
DATAI         EQU 1EH
DATAO         EQU 1FH
TXBUF         EQU 20H
RXBUF         EQU 21H
COUNT         EQU 22H
DEL           EQU 23H
SEL           EQU 24H
DATOS         EQU 25H             

DI            EQU 7
DO            EQU 6
SDA           EQU 1
SCL           EQU 0

 
;PortA.0--------->Serial Clock
;PortA.1<-------->Serial Data
;PortB LED outs


   __CONFIG _WDT_OFF & _XT_OSC & _CP_OFF


;************************************************************
;start
;************************************************************

              ORG    00H
              GOTO   START
             

START
              CALL   PORT_INIT
PRINCIPAL
              MOVLW  B'00000000'    ;pagina EEPROM a escribir
              MOVWF  ADDR
              MOVLW  B'00000000'    ;direccion EEPROM a escribir
              MOVWF  DATAO
              MOVLW  B'10101010'    ;dato a escribir en EEPROM
              MOVWF  DATOS         
              CALL   WRITE_EEPROM   ;escribe en EEPROM
              MOVLW  .100
              CALL   DELAY_NMS
              MOVLW  00H            ;pagina EEPROM a leer
              MOVWF  ADDR
              MOVLW  00H            ;direccion EEPROM a leer
              MOVWF  DATAO           
              CALL   READ_EEPROM    ;lee de EEPROM
              MOVF   DATAI,W
              MOVWF  PORTB          ;saca el dato leido por PORTB
              MOVLW  .100
              CALL   DELAY_NMS
DONE
              GOTO DONE



;*************************************************************
;Port Init
;*************************************************************

PORT_INIT
              CLRF   PORTA
              CLRF   PORTB
 
              BSF    STATUS,RP0     ;selecciona pagina 1
              CLRF   TRISA
              CLRF   TRISB
              BCF    STATUS,RP0     ;selecciona pagina 0
 
              CLRF   PORTB
              RETURN


;*************************************************************
;COMUNICACIÓN CON EEPROM
;*************************************************************

WRITE_EEPROM
              CALL   BSTART
 
              MOVLW  B'10100000'
              MOVWF  TXBUF
              CALL   TX
 
              MOVF   ADDR,W
              MOVWF  TXBUF
              CALL   TX
 
              MOVF   DATAO,W
              MOVWF  TXBUF
              CALL   TX

              MOVF   DATOS,W       
              MOVWF  TXBUF         
              CALL   TX           
 
              CALL   BSTOP
 
              RETURN


READ_EEPROM
              CALL   BSTART
 
              MOVLW  B'10100000'
              MOVWF  TXBUF
              CALL   TX
 
              MOVF   ADDR,W
              MOVWF  TXBUF
              CALL   TX
       
              MOVF   DATAO,W       
              MOVWF  TXBUF         
              CALL   TX           
 
              CALL   BSTART
 
              MOVLW  B'10100001'
              MOVWF  TXBUF
              CALL   TX
 
              CALL   RX
 
              CALL   BSTOP
 
              RETURN

BSTART
              BSF    PORTA,SDA
              BSF    STATUS,RP0       
              MOVLW  00H
              MOVWF  TRISA
              BCF    STATUS,RP0   
 
              BCF    PORTA,SCL
              NOP
              BSF    PORTA,SCL
              NOP
              NOP
              NOP
              NOP
              NOP
              BCF    PORTA,SDA
              NOP
              NOP
              NOP
              NOP
              NOP
              BCF    PORTA,SCL
              NOP   
              NOP
              RETURN
       
BSTOP
              BSF    STATUS,RP0       
              MOVLW  00H
              MOVWF  TRISA
              BCF    STATUS,RP0   
 
              BCF    PORTA,SDA
              NOP
              NOP
              NOP
              BSF    PORTA,SCL
              NOP
              NOP
              NOP
              BSF    PORTA,SDA
              NOP
              NOP
              BCF    PORTA,SCL
              NOP
              NOP
              NOP
              RETURN


BITOUT
              BSF    STATUS,RP0       
              MOVLW  00H
              MOVWF  TRISA
              BCF    STATUS,RP0   
 
              BTFSS  EEPROM,DO
              GOTO   BITLOW
              BSF    PORTA,SDA
              GOTO   CLK_OUT
BITLOW
              BCF    PORTA,SDA
CLK_OUT
              BSF    PORTA,SCL
              NOP
              NOP
              NOP
              NOP
              BCF    PORTA,SCL
              NOP
              RETURN

BITIN
              BSF    EEPROM,DI
 
              BSF    STATUS,RP0
              MOVLW  02H
              MOVWF  TRISA
              BCF    STATUS,RP0   
 
              BSF    PORTA,SCL
              NOP
              NOP
              NOP
              NOP
              NOP
              BTFSS  PORTA,SDA
              BCF    EEPROM,DI
              BCF    PORTA,SCL
              RETURN

TX
              MOVLW  .8
              MOVWF  COUNT
TXLP
              BCF    EEPROM,DO
              BTFSC  TXBUF,7
              BSF    EEPROM,DO
              CALL   BITOUT
              RLF    TXBUF,F
              DECFSZ COUNT,F
              GOTO   TXLP
              CALL   BITIN
              RETURN

RX
              CLRF   DATAI
              MOVLW  .8
              MOVWF  COUNT
              BCF    STATUS,0
RXLP
              RLF    DATAI,F
              CALL   BITIN
              BTFSC  EEPROM,DI
              BSF    DATAI,0
              DECFSZ COUNT,F
              GOTO   RXLP
              BSF    EEPROM,DO
              CALL   BITOUT
              RETURN


DELAY_NMS
              MOVWF  DEL
OUTTER_MS
              MOVLW  .110
              MOVWF  SEL
INNER_MS
              NOP
              NOP
              NOP
              NOP
              NOP
              NOP
              DECFSZ SEL,F
              GOTO   INNER_MS
              DECFSZ DEL,F
              GOTO   OUTTER_MS
              RETURN


              END
« Última modificación: 02 de Enero de 2009, 20:28:20 por antimason »

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #3 en: 07 de Enero de 2009, 14:50:11 »
Aquí os dejo otra rutina para comunicar el 16f84 con una memoria 24lcxxx.








;      RUTINAS DE COMUNICACIÓN CON DISPOSITIVO I2C
;
;         ABRIL 10 DEL 2000
;
;PORTX ES EL PUERTO DONDE SE ENCUENTRAN LOS BITS SCL Y SDA DEL DISPOSITIVO
;TRISX   ES EL REGISTRO DE DIRECCIÓN DEL PUERTO PORTX
;
#DEFINE _c STATUS,C
;
;****************************************************************************
;ENVIA CONDICIÓN DE START AL DISPOSITIVO I2C
;**************************************************************************
START
   BSF   PORTX,SDA
   BANK1
   BCF   TRISX,SDA
   BCF   TRISX,SCL
   BANK0
   BCF   PORTX,SCL
   NOP
   BSF     PORTX,SCL
   NOP
   NOP
   NOP
   NOP
   NOP
   BCF     PORTX,SDA
   NOP
   NOP
   NOP
   NOP
   NOP
   BCF     PORTX,SCL
   NOP
   NOP
   RETURN
;**************************************************************************
;ENVIA CONDICIÓN DE STOP AL DISPOSITIVO I2C
;**************************************************************************
STOP
   BANK1
   BCF   TRISX,SDA
   BCF   TRISX,SCL
   BANK0
   BCF     PORTX,SDA
   NOP
   NOP
   NOP
   BSF     PORTX,SCL
   NOP
   NOP
   NOP
   BSF     PORTX,SDA
   NOP
   NOP
   BCF     PORTX,SCL
   NOP
   NOP
   NOP
   RETURN
;**************************************************************************
;RUTINA QUE COLOCA 8 BITS EN EL DISPOSITIVO I2C, AFECTA F0
;**************************************************************************
WRIBYTE
   BANK1
   BCF   TRISX,SCL
   BCF   TRISX,SDA
   BANK0
   MOVLW   .8
   MOVWF   F0
   BCF     _c
ROTA
   RLF       F4,F
   BTFSS   _c
   GOTO    ESCERO
ESUNO
   BSF     PORTX,SDA
   GOTO    PULSO
ESCERO
   BCF     PORTX,SDA
PULSO
   nop
   nop
   BSF     PORTX,SCL
   nop
   nop
   nop
   BCF     PORTX,SCL
   nop
   DECFSZ  F0,F
   GOTO    ROTA
   RETLW   TRUE
;****************************************************************************
;RUTINA QUE TOMA 8 BITS DEL DISPOSITIVO I2C, ALMACENA EL RESULTADO EN F4
;****************************************************************************
REBYTE
   MOVLW   .8              ;
   MOVWF   F0              ;CONTADOR
   BANK1
   BSF   TRISX,SDA   ;SDA de Entrada
   BANK0
   CLRF    F4
RBIT
   BSF     PORTX,SCL             ;
   nop
   BTFSS   PORTX,SDA
   GOTO    ESTACERO
ESTAUNO
   BSF     _c         ;CARRY=1
   GOTO    PULSDOWN
ESTACERO
   BCF     _c      ;CARRY=0
PULSDOWN
   RLF       F4,F
   BCF     PORTX,SCL   ;SCL=0
   nop
   DECFSZ  F0,F      ;DEC F0
   GOTO    RBIT
   BANK1
   BCF   TRISX,SDA   ;SDA DE SALIDA
   BANK0
   RETLW   TRUE            ;
;***************************************************************************
;RUTINA QUE LEE EL ACK DEL DISPOSITIVO I2C, AFECTA F0
;entrega en el reg W un TRUE si fue OK ó un FALSE si hubo error.
;***************************************************************************
ACKMEM
   BANK1
   BSF   TRISX,SDA   ;SDA=IN
   BANK0
   MOVLW   .255
   MOVWF   F0
LOOPACKM
   BSF     PORTX,SCL
   nop
   nop
   nop
   nop
RSDA
   BTFSS   PORTX,SDA
   GOTO    SIACK
NOACK
   nop
   BCF     PORTX,SCL
   DECFSZ  F0,F
   GOTO    LOOPACKM
   RETLW   FALSE           ;EL DISP. I2C NO ENTREGÓ ACK
SIACK
   nop
   BCF     PORTX,SCL
   RETLW   TRUE            ;ACK = CORRECTO
;***************************************************************************
;ENVIA UN ACK AL DISPOSITIVO I2C
;***************************************************************************
ACKMICRO
   BANK1
   BCF   TRISX,SDA
   BCF   TRISX,SCL
   BANK0
   BCF     PORTX,SDA
   BSF     PORTX,SCL
   nop
   NOP
   NOP
   BCF     PORTX,SCL
   nop
   RETLW   TRUE
;***************************************************************************
;RUTINA LA CUAL ESCRIBE UN BYTE EN EL DISPOSITIVO I2C PARÁMETROS:
; DIREE y DATO (A ESCRIBIR)
;***************************************************************************
WR_EE
   CALL   START
   MOVLW   0xA0      ; W=10100000 B
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   MOVF   DIREE,W      ;ACOMODO DE WORD ADDRESS
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   MOVF   DATO,W      ;ACOMODO DEL DATO A ESCRIBIR
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   CALL   STOP
   CALL   DEL5MS
   CALL   DEL5MS      ;TIEMPO DE ESPERA twc
   CALL   DEL5MS
   RETLW   TRUE
;***************************************************************************
;ESTA RUTINA LEE DEL DISPOSITIVO I2C UN BYTE , PARÁMETROS:
; DIREE y DATO (LEÍDO)
;***************************************************************************
RD_EE
   CALL   START
   MOVLW   0xA0      ; W=10100000 B
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   MOVF   DIREE,W      ;ACOMODO DE WORD ADDRESS
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   CALL   START
   MOVLW   0xA1
   MOVWF   F4
   CALL   WRIBYTE
   CALL   ACKMEM
   CALL   REBYTE
   MOVF   F4,W
   MOVWF   DATO
   CALL   STOP
   RETLW   TRUE
;***************************************************************************

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #4 en: 07 de Enero de 2009, 18:16:15 »
Vamos, alguna funcionará en la vida real, digo yo.

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #5 en: 17 de Enero de 2009, 02:19:05 »
Agrego una que hice yo solo para recepcion de datos como exclavo, por interrupcion de flaco de RB0.- Adjunto un posible hardware y el diagrama de flujo de la recepcion por interrupcion.-

   List p=16f84a

   #include <p16f84a.inc>

   __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC


; Cristal de 10 MHz !!!
; Dispositivo Maestro I2C configurado a 100 kHz.-



;**********************************************
;      Declaracion de Registros
;**********************************************
CONTADOR      equ         0x0C   ;registro utilizado para conteo
PDel0         equ         0x10   ;registro utilizado en demoras
PDel1         equ         0x11   ;registro utilizado en demoras
PDel2         equ         0x12   ;registro utilizado en demoras
FLAGS         equ         0x13   ;registro utilizado en carga de banderas para control de I2C
DATO_I2C      equ         0x14   ;registro utilizado para el guardado del byte recibido por I2C
TEMP_W         equ         0x15   ;registro temporario para guardado de W
STATUS_TEMP      equ         0x16   ;registro temporario para guardado de STATUS

;**********************************************
;      Declaracion de Bit
;**********************************************
SCL            equ         0   ;pin SCL de comunicacion I2C, en este caso usamos RA0
SDA            equ         0   ;pin SDA de comunicacion I2C, Debe ser siempre el Rb0, para deteccion de flanco x interrupcion
PFULL         equ         0   ;si es 1 pila completa
SLAVE_OK      equ         1   ;si es 1 se ha direccionado el esclavo correcto
KBHIT         equ         2   ; Control de recepcion de datos
DIRE         equ         3   ; Se recibe direccion I2C
;**********************************************

            org            0x00
            goto         inicio

;******************************************
; Interrupcion
;******************************************
            org          0x04            
            btfsc          INTCON,INTF
               goto          interrupcion_rb0
            goto         salida_interrupcion
;******************************************
;   Interrupcion RB0
;******************************************
; se genero interrupcion, posible envio de Start para la comunicacion.-
interrupcion_rb0
            btfss         PORTA,SCL      ; si es 1 entonces se ha generado condicion de start
            goto          salida_interrupcion   
            movwf         TEMP_W   
            swapf         TEMP_W,1
            movf         STATUS,w
            movwf         STATUS_TEMP
            clrf         STATUS   ;Bank0
            bcf            INTCON,GIE
            movlw         0x08
            movwf         CONTADOR
;*******************************************
espera_bit      btfsc         PORTA,SCL   ; esperamos que SCL=0
            goto         $-1
espera_clock   btfss         PORTA,SCL   ; esperamos que SCL=1 para leer bit.
            goto         $-1            
            bcf          DATO_I2C,0   ; cargo 0
            btfsc         PORTB,SDA   ; si es 0 salta, sino carga 1
cargo_1         bsf            DATO_I2C,0   ; cargo 1
consulta      decfsz         CONTADOR   ; determina si ya llegaron los 8 bit's
            goto         $+2         ; no se cargaron
            goto         espera_ack
            rlf            DATO_I2C,1   ; rotamos a la izquierda
            goto         espera_bit
;*******************************************   
espera_ack   
            bsf            STATUS,RP0   ; Bank1
            bcf            TRISB,SDA   ; SDA como salida
            bcf            STATUS,RP0   ; Bank0
            bcf            PORTB,SDA   ; envio ack
            btfsc         FLAGS,PFULL   ; determino si estoy en condiciones de recibir dato (PFULL=0 Si)
            bsf            PORTB,SDA   ; envio un nack
            btfss         PORTA,SCL   ; espero a que SCL=1
            goto         $-1
            call         demora_6us
            bsf            PORTB,SDA
            bsf            STATUS,RP0   ; Bank1
            bsf            TRISB,SDA   ; ya se envio ack o nack, reconfiguro SDA como entrada.
            clrf         STATUS      ; Bank0

;*******************************************
            call         grabar_dato
            movlw         0x08
            movwf         CONTADOR   ; por si se recibe otro byte
;*******************************************
            btfss         PORTA,SCL   ; determinamos si es un stop u otro byte
            goto         $-1
            btfsc         PORTB,SDA   ; si es 0 puede ser un stop
            goto         cargo_1      ;no es stop, se carga el byte, MSB es 1
            nop                        ;demora de 5us.
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            btfsc         PORTA,SCL   ; pregunta si el SCL esta generando clock.
            goto         salida_interrupcion   ; si no genera clock, entonces STOP
            bcf            DATO_I2C,0   ; si se genera clock, se carga byte, MSB=0
            decf         CONTADOR,1
            rlf            DATO_I2C,1
            goto         espera_clock
               
;******************************************   
salida_interrupcion
            bcf            FLAGS,SLAVE_OK
            bcf            INTCON,INTF
            bsf            INTCON,GIE
            movf         STATUS_TEMP,w
            movwf         STATUS
            swapf         TEMP_W,w
            retfie
;__________________________________________________________________
;******************************************
;    Grabar Dato
;******************************************
; La recepcion fue creada como para recibir varios datos consecutivos y en este caso
; hay que crear un buffer (No expuesto para facilitar entendimiento), en este ejemplo
; solo se pueden recibir 1.-

grabar_dato
            btfss         FLAGS,DIRE ; Se recibio Direccion del Exclavo?
            goto         guardo_direccion ;no, lo verifico.-
            bsf            FLAGS,PFULL ;Se lleno el Buffer, para no recibir mas
            bsf            FLAGS,KBHIT ;Se recibio dato y queda guardado en DATO_I2C
            return
guardo_direccion
            movlw         0xAA   ; Direccion de mi exlavo.-
            subwf         DATO_I2C,w   ; verifico si es la correcta
            btfss         STATUS,Z
            goto         salida_interrupcion   ; no lo es, salgo.-
            bsf            FLAGS,DIRE   ; Si es, lo indico seteando DIRE
            return
;-------------------------------------------------------------------------


;******************************************
;        Programa Principal   
;******************************************
inicio
             movlw          b'00000001'  ;configurar el puerto a como xxxsssse
               banksel         TRISA        ;cambiar a banco 1
               movwf          TRISA
               movlw          b'00000001'  ;configurar el puerto b como ssssssse
               movwf          TRISB
            bcf          OPTION_REG,INTEDG      ;interrupción rb0 por flanco descendente
               banksel         PORTB
            clrf         FLAGS
         
;**********************************************   
;    Activacion de interrupciones
;**********************************************

               bsf            INTCON,GIE         ;activar habilitador general de interrupciones.
               bsf          INTCON,INTE        ;activar interrupción por rb0.
;**********************************************
            clrf         FLAGS
            clrf         PORTA
;**********************************************
;       Estado de espera
;**********************************************
Espera         
            btfss         FLAGS,KBHIT   ; Llego dato de I2C?
            goto         $-1         ; No
            clrf         FLAGS
            ; En DATO_I2C tenemos el byte enviado por el Dispositivo Maestro
            ; para posterior manejo, como enviarlo a un LCD, etc. No lo expuse
            ; para no complicar el entendimiento
            goto   Espera   ; bucle infinito.-



;**********************************************
;**      Subrutinas Demoras
;**********************************************
;**********************************************
demora_6us      movlw           .2       
              movwf           PDel0   
PLoop0_6        nop             
              decfsz          PDel0, 1 
              goto            PLoop0_6   
PDelL1_6        goto          PDelL2_6         
PDelL2_6 
            return             
;**********************************************

            end
No contesto mensajes privados, las consultas en el foro

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #6 en: 17 de Enero de 2009, 08:49:10 »
Interesante aportación, a ver si entre unos y otros vamos solventando los problemas de comunicación I2C del 16F84.

Desconectado antimason

  • PIC12
  • **
  • Mensajes: 81
Re: Libreria BUS_I2C.INC para pic 16F84A.
« Respuesta #7 en: 18 de Diciembre de 2009, 14:59:50 »
Otra rutina interesante esta vez del amigo Pedro Luis Sánchez Fornell.



Rutina: I2C.INC      Fecha: MARZO - 2002
;          Optimizadas por: Pedro Luis Sánchez Fornell
;
; Protocolo I2C para lectura / escritura de la Eeprom 24Cxx (4 Mhz)
;
; RB1: Señal de reloj del emisor (SCL)
; RB2: Señal de datos del emisor (SDA)
;
; Programa para PIC16F84
; Velocidad del reloj: 4 MHz   Reloj instrucción: 1 MHz - 1 uS
; Perro guardián: deshabilitado   Tipo de reloj: XT
; Protección del código: OFF
;
;*************************************************************************************

                          CBLOCK             I2c_var

                          GenCount                           ; Contador
                          Mem_Loc                            ; Dirección de acceso a la EEPROM
                          Mem_Loc_H                          ; Dirección alta de acceso a la EEPROM
                          Data_Buf                           ; Byte de lectura de la EEPROM
                          OutputByte                         ; Byte de escritura en la EEPROM
                          flags                              ; Banderas de estado de lectura/escritura
                          ENDC
 

#define                   SDA                TRISB, 2
#define                   SCL                TRISB, 1


;*************************************************************************************
; Lectura de la EEPROM
;
; Llamada con la dirección en Mem_Loc
; Retorna con el byte en Data_Buf
;*************************************************************************************

ReadEPROM                 bcf                STATUS,RP0      ; Banco 0
                          movf               PORTB,0
                          andlw              0xF9
                          movwf              PORTB           ; Pone a 0 RB1 y RB2 para control pasivo del bus
                          bsf                STATUS,RP0      ; Banco 1
                          bsf                SDA             ; SDA alto
                          bsf                SCL             ; SCL alto
                          bcf                SDA             ; START - SDA bajo
                          movlw              b'10100000'
                          iorwf              Mem_Loc_H,0     ; Coloca los tres bits más altos de la dirección
                          call               Byte_Out        ; Escribe cabecera
                          btfsc              flags,0
                          goto               Error_Routine   ; Error
                          movf               Mem_Loc,0
                          call               Byte_Out        ; Escribe dirección
                          btfsc              flags,0
                          goto               Error_Routine   ; Error
                          bcf                SCL             ; SCL bajo
                          nop
                          bsf                SDA             ; SDA alto
                          bsf                SCL             ; SCL alto
                          bcf                SDA             ; 2º START - SDA bajo
                          movlw              b'10100001'     ; Esta vez NO SE DEBEN colocar los tres
                                                             ;bits más altos
                          call               Byte_Out        ; Escribe 2ª cabecera
                          btfsc              flags,0
                          goto               Error_Routine   ; Error

                          call               Byte_In         ; Recibe byte
                          movf               Data_Buf,0      ; Almacena el valor en Data_Buf
                          bcf                SCL             ; SCL bajo
                          nop
                          bcf                SDA             ; SDA bajo
                          bsf                SCL             ; SCL alto
                          bsf                SDA             ; STOP - SDA alto
                          bcf                STATUS, RP0     ; Banco 0
                          return

;*************************************************************************************
; Escritura de la EEPROM
;
; Llamada con la dirección en Mem_Loc
; No retorna nada
;*************************************************************************************

WriteEPROM                bcf                STATUS,RP0      ; Banco 0
                          movf               PORTB,0
                          andlw              0xF9
                          movwf              PORTB           ; Pone a 0 RB1 y RB2 para control pasivo del bus
                          bsf                STATUS,RP0      ; Banco 1
                          bsf                SDA             ; SDA alto
                          bsf                SCL             ; SCL alto
                          bcf                SDA             ; START - SDA bajo
                          movlw              b'10100000'
                          iorwf              Mem_Loc_H,0     ; Coloca los tres bits más altos de la dirección
                          call               Byte_Out        ; Escribe cabecera
                          btfsc              flags,0
                          goto               Error_Routine   ; Error
                          movf               Mem_Loc,0
                          call               Byte_Out        ; Escribe dirección
                          btfsc              flags,0
                          goto               Error_Routine   ; Error
                          movf               Data_Buf,0
                          call               Byte_Out        ; Escribe dato
                          btfsc              flags,0
                          goto               Error_Routine   ; Error
                          bcf                SCL             ; SCL bajo
                          nop
                          bcf                SDA             ; SDA bajo
                          bsf                SCL             ; SCL alto
                          bsf                SDA             ; STOP - SDA alto
                          call               Delay10ms       ; Retardo max. para el ciclo de escritura de 10ms
                          bcf                STATUS, RP0     ; Banco 0
                          return

;*************************************************************************************
; Recibe byte de la EEPROM
;*************************************************************************************

Byte_In                   clrf                Data_Buf
                          movlw               0x08           ; 8 bits a recibir
                          movwf               GenCount

ControlIn                 rlf                 Data_Buf,1     ; rota Data_Buf
                          bcf                 SCL            ; SCL bajo
                          nop
                          bsf                 SCL            ; SCL alto
                          bcf                 STATUS,RP0     ; Banco 0
                          btfss               SDA            ; Testea el bit de la EPROM
                          goto                $+3
                          bsf                 STATUS,RP0     ; Banco 1
                          bsf                 Data_Buf,0     ; Bit actual de Data_Buf a 1
                          bsf                 STATUS,RP0     ; Banco 1
                          decfsz              GenCount,1     ; Decrementa contador
                          goto                ControlIn
                          return

;*************************************************************************************
; Envía byte a la EEPROM
; y espera el ACK (256us)
;*************************************************************************************

Byte_Out                  movwf               OutputByte
                          movlw               0x08           ; 8 bits a enviar
                          movwf               GenCount
                          rrf                 OutputByte,1   ; Rota al revés OutputByte

ControlOut                rlf                 OutputByte,1   ; Rota OutputByte
                          bcf                 SCL            ; SCL bajo
                          nop
                          btfsc               OutputByte,7   ; Testea el bit 7
                          goto                BitHigh
                          bcf                 SDA            ; Bit a 0 - SDA bajo
                          goto                ClockOut

BitHigh                   bsf                 SDA            ; Bit a 1 - SDA alto

ClockOut                  bsf                 SCL            ; SCL alto - envía bit
                          decfsz              GenCount, 1    ; Decrementa contador
                          goto                ControlOut
                          bcf                 SCL            ; SCL bajo
                          bsf                 SDA            ; SDA alto
                          nop
                          nop
                          nop
                          bsf                 SCL
                          clrf                GenCount

WaitForACK                bsf                 STATUS,RP0     ; Banco 1
                          incf                GenCount,1
                          btfsc               STATUS,Z       ; Testea el desbordamiento del carry
                          goto                No_ACK_Rec     ; Se esperaron 256 useg y no se recibió el ACK
                          bcf                 STATUS,RP0     ; Banco 0
                          btfsc               SDA            ; Testea SDA
                          goto                WaitForACK     ; Aún no se recibe, continúa esperando...
                          bsf                 STATUS,RP0     ; Banco 1
                          bcf                 flags,0        ; ACK recibido, borra bandera.
                          return

No_ACK_Rec bsf            flags,0                            ; No se recibió el ACK, bandera a 1
                          return

;*************************************************************************************
; Error
;*************************************************************************************

Error_Routine             bcf                 STATUS,RP0     ; Banco 0
                          return                             ; Retorna al programa principal

                                                             ; (bandera permanece a 1)

;*************************************************************************************
; Retardos
;*************************************************************************************

Delay10ms                 movlw              0x0A
                          movwf              GenCount

Delay_Start               nop
                          movlw              0x07            ; 249 ciclos * 4us por ciclo + 5us = 1.000ms

Delay                     addlw              0x01
                          btfss              STATUS,Z
                          goto               Delay
                          decfsz             GenCount,1
                          goto               Delay_Start
                          return
                         


 

anything