Autor Tema: Protocolo y Dispositivos I2C.  (Leído 3349 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado groundman

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1870
    • www.ingeniopic.com
Protocolo y Dispositivos I2C.
« en: 13 de Junio de 2016, 15:52:38 »


hola a todos.hace tiempo. cuando todabia estaba con los 16f876.realize un proyecto usando una memoria eeprom 24lc16 cullo protocolo de comunicacion hera el I2C.
y que hasta el dia de hoy no me ha hecho falta usarlo de nuevo.

ahora que voy por el 18F87k22 he tenido la necesidad de conectar diferentes dispositivos externos con este tipo de interface.yo pensaba que para conectarme
con este sistema.solo hacia falta una libreria para todos los dispositivos que usan esta conexion.pero ahora me doy cuenta de que diferentes dispositivo usan
diferentes formas de recibir y enviar datos con este mismo protocolo.

por eso quiero compartir un trabajo que me ha costado dos semanas de dolores de cabeza.

los ejemplos que voy a poner aqui son para un pic 18F2550 configurarado como maestro.los esclavos segun el tipo.tienen una direccion que los identifica y pueden conectarse
en paralelo siempre y cuando las direcciones no coincidan.

estas serian algunas direcciones de unos dispositivos esclavos con los que practicare:

#define      ID_WRITE       movlw   0xD0   ;valor de direccion para escritura del DS1307(reloj)
#define      ID_READ      movlw   0xD1   ;valor de direccion para lectura del DS1307
#define      ID_WRITE       movlw   0x42   ;valor de direccion para escritura del OV7670(camara)
#define      ID_READ      movlw   0x43   ;valor de direccion para lectura del OV7670
#define      ID_WRITE       movlw   0xA0   ;valor de direccion para escritura del 24c16(eeprom)
#define      ID_READ      movlw   0xA1   ;valor de direccion para lectura del 24c16

Cada esclavo tiene dos direcciones de 8 bit que son identicas a excepcion del utimo bit.este bit indica al esclavo si vamos a leer o escribir en el. 1=leer y 0=escribir.
estos dispositivos tienen dos pin de conexion I2C. CLK para el clock y SDA entrada y salida de datos.
la velocidad de comunicacion varia segun el dispositivo.siendo mas comunes señales de 100 y 400Khz.

para el pic con el que pondre los ejemplos sera el 18F2550 trabajando a 48Mhz este pic tiene conectado un crystal de 4Mhz que mediante el PLL interno se multiplica
hasta esos 48Mhz.

esta seria la configuracion del pic para activar el I2C

         bsf   TRISB,0;SDA      ;configura pins como entrada
         bsf   TRISB,1;SCL      ;configura pins como entrada
                  
         bsf   PIE1,SSPIE
         movlw    0x28              ;
         movwf    SSPCON1           ;
         
         movlw   0x80                ;
         movwf   SSPSTAT             ;
         ;movlw   .159      ; configurar I2C a 100kHz (para fosc de 64Mhz) clock=Fosc/(4*(SSPxADD+1))
         ;movlw   .39      ; configurar I2C a 400kHz (para fosc de 64Mhz) clock=Fosc/(4*(SSPxADD+1))
         movlw   .119      ; configurar I2C a 100kHz (para fosc de 48Mhz) clock=Fosc/(4*(SSPxADD+1))
         ;movlw   .29      ; configurar I2C a 400kHz (para fosc de 48Mhz) clock=Fosc/(4*(SSPxADD+1))
         ;movlw   .9      ; configurar I2C a 100kHz (para fosc de 4Mhz) clock=Fosc/(4*(SSPxADD+1))
         ;movlw   .59      ; configurar I2C a 100kHz (para fosc de 24Mhz) clock=Fosc/(4*(SSPxADD+1))
         
         movwf   SSPADD
         clrf   SSPCON2

El proyecto que he realizado lo he hecho en win10 con el MPLAB X y el ISIS del proteus.ademas he tenido que hacer las pruebas en el ICD2 y el ICD3 para entender
por que me estaba fallando todo.
aun asi el ISIS tiene algunos problemas con las simulaciones I2C.de tal modo que he tenido que modificar alguna que otra linea.el unico problema
es que es posible que haya que resetear el esclavo segun que tipo decomunicacion realicemos.


aqui pongo la libreria que he creado para el control del I2C de un 18f2550 con una memoria 24lc16.para otros dispositivos y microcontrolador.habia que cambiar el codigo.

Código: [Seleccionar]
LIST

CBLOCK I2C_VAR
CONT_BYTE_RTC ;contador de numero de bytes
DIR_I2C ;principio de direccion de dispositivo
DATO_I2C
ENDC
;Lineas en programa principal

;#define ID_WRITE    movlw 0xD0 ;valor de direccion para escritura del DS1307
;#define ID_READ movlw 0xD1 ;valor de direccion para lectura del DS1307
;#define ID_WRITE    movlw 0x42 ;valor de direccion para escritura del OV7670
;#define ID_READ movlw 0x43 ;valor de direccion para lectura del OV7670
;#define ID_WRITE    movlw 0xA0 ;valor de direccion para escritura del 24c16
;#define ID_READ movlw 0xA1 ;valor de direccion para lectura del 24c16


;-------------------------------------------------------------------------------------------;
;                                  SUBRUTINA DE I2C BYTE READ                                      ;
;-------------------------------------------------------------------------------------------;
;Lectura de un byte del dispositivo I2C.el dato es traspasado al registro DATO_I2C
;introducir en w la direccion del dispositivo I2C.antes de la llamada a esta rutina


BYTE_READ movwf DIR_I2C     ;numero de bytes a escribir
rcall Start_I2C     ;Llama a la subrutina de START
ID_WRITE     ;byte de control en modo escritura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
movff DIR_I2C,SSPBUF     ;direccion del dispositivo donde empezaremos a leer
rcall Write_I2C     ;Llama a la subrutina de escritura
;rcall Start_I2C     ;Llama a la subrutina de START
rcall Restart_I2C     ;Llama a la subrutina de RESTART
ID_READ     ;byte de control en modo lectura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
rcall Read_I2C     ;Llama a la subrutina de lectura
movff SSPBUF,DATO_I2C     ;Guarda el dato en la Ram e incrementa el puntero
rcall Send_I2C_NoAck     ;llama a la subrutina de ACKNOWLEDGE
rcall Stop_I2C     ;Llama a la subrutina de STOP
return     ;Retorna
;-------------------------------------------------------------------------------------------;
;                                  SUBRUTINA DE I2C SEQ READ                                      ;
;-------------------------------------------------------------------------------------------;
;Lectura del dispositivo I2C y traspaso de datos a la ram del pic
;introducir en el registro DIR_I2C.el principio de  direccion del dispositivo I2C.
;Introducir numero bytes a transferir en w. antes de la llamada a esta rutina.
;seleccinar direccionamiento de la ram donde hubiar datos. ejm.. lfsr FSR2,0X100

SEQ_READ movwf CONT_BYTE_RTC     ;numero de bytes a escribir
rcall Start_I2C     ;Llama a la subrutina de START
ID_WRITE     ;byte de control en modo escritura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
movff DIR_I2C,SSPBUF     ;direccion del dispositivo donde empezaremos a leer
rcall Write_I2C     ;Llama a la subrutina de escritura
;rcall Start_I2C     ;Llama a la subrutina de START
rcall Restart_I2C     ;Llama a la subrutina de RESTART
ID_READ     ;byte de control en modo lectura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
Bucle_rnd rcall Read_I2C     ;Llama a la subrutina de lectura
movff SSPBUF,POSTINC2     ;Guarda el dato en la Ram e incrementa el puntero
dcfsnz CONT_BYTE_RTC,F     ;repite hasta que sea cero
goto out_i2c     ;si es el ultimo dato.salir de la lectura
rcall Send_I2C_Ack     ;Llama a la subrutina de ACKNOWLEDGE
bra Bucle_rnd     ;continúa leyendo
   
out_i2c rcall Send_I2C_NoAck     ;llama a la subrutina de ACKNOWLEDGE
rcall Stop_I2C     ;Llama a la subrutina de STOP
return     ;Retorna

;------------------------------------------------------------- BYTE_WRITE -------------------------------
;escribir en dispositivo I2C un dato en la direccion seleccionada por DIR_I2C.y el dato en W

BYTE_WRITE movwf DATO_I2C     ;dato a excribir
rcall Start_I2C     ;Llama a la subrutina de START
ID_WRITE     ;byte de control en modo escritura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
movff DIR_I2C,SSPBUF     ;carga direccion en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
movff DATO_I2C,SSPBUF     ;carga dato en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
rcall Stop_I2C     ;Llama a la subrutina de STOP
return    
;------------------------------------------------------------ RANG_WRITE --------------------------------
;Traspaso de datos de la ram del pic al dispositivo I2C
;Introducir numero bytes a transferir en w. antes de la llamada a esta rutina.
;direccionar FSR2 ejem.. lfsr FSR2,0X100

RANG_WRITE movwf CONT_BYTE_RTC     ;numero de bytes a escribir
rcall Start_I2C     ;Llama a la subrutina de START
ID_WRITE     ;byte de control en modo escritura
movwf SSPBUF,0     ;cargalo en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
movff DIR_I2C,SSPBUF     ;carga direccion a escribir del dispositivo  en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
rang1 movff POSTINC2,SSPBUF     ;carga dato en el Buffer de salida
rcall Write_I2C     ;Llama a la subrutina de escritura
decfsz CONT_BYTE_RTC,F     ;repite hasta que sea cero
bra rang1     ;continúa leyendo
rcall Stop_I2C     ;Llama a la subrutina de STOP
return    



;////////////////////////////////////////////////////////////////// RUTINAS DE FUNCIONAMIENTO I2C pic 18f2550//////////////////////////////////////////////////////////

i2c_idle     btfsc       SSPSTAT,R_W
    goto       i2c_idle
reps     movf       SSPCON2,w
    andlw       0x1F
    btfss       STATUS,Z
    goto       reps
    return    
   



Start_I2C           BSF      SSPCON2,SEN     ;Pone a uno el bit de START
S2                  BTFSC    SSPCON2,SEN     ;Espera a que se ponga a cero el bit de START
                    BRA      S2
S3                  BTFSS    PIR1,SSPIF     ;Espera a que la condicion de START haya sido completada
                    BRA      S3     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF     ;Borra la bandera de la interrupción
                    RETURN     ;Retorna de la subrutina
                                                     

Write_I2C           BTFSC    SSPSTAT,R_W,0     ;Verifica que se ponga a cero el bit R/W
                    BRA      Write_I2C     ;Espera a que termine de enviar el dato
W2                  BTFSC    SSPCON2,ACKSTAT     ;Espera a que reciba el bit de ACKNOWLEDGE
                    BRA      W2
                    BCF      PIR1,SSPIF,0     ;borra la bandera de la interrupción
    RETURN     ;Retorna de la subrutina
   


Restart_I2C         BSF      SSPCON2,RSEN,0     ;Pone a uno el bit de RESTART
R2                  BTFSC    SSPCON2,RSEN,0     ;Espera a que se ponga a cero el bit de RESTART
                    BRA      R2
R3                  BTFSS    PIR1,SSPIF,0     ;Espera a que la condicion de RESTART haya sido completada
                    BRA      R3     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF,0     ;Borra la bandera de la interrupción
                    RETURN     ;Retorna de la subrutina


Read_I2C            BSF      SSPCON2,RCEN,0     ;Habilita la recepción de datos mediante el bit RCEN
Rea2                BTFSC    SSPCON2,RCEN,0     ;Espera a que se ponga a cero el bit RCEN
                    BRA      Rea2
Rea3                BTFSS    SSPSTAT,BF,0     ;Dato disponible en SSPBUF para ser leidos?
                    BRA      Rea3     ;No, esperar
Rea4                BTFSS    PIR1,SSPIF,0     ;Espera a que la condicion de Lectura haya sido completada
                    BRA      Rea4     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF,0     ;Borra la bandera de la interrupción
                    RETURN     ;Retorna de la subrutina


Send_I2C_Ack        BCF      SSPCON2,ACKDT,0     ;Pone a cero el bit de ACKNOWLEDGE DATA
                    BSF      SSPCON2,ACKEN,0     ;Genera la condición de ACKNOWLEDGE Poniendo a 1 el bit ACKEN
Se1                 BTFSS    PIR1,SSPIF,0     ;Espera a que la condicion de ACK haya sido completada
                    BRA      Se1     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF,0     ;Borra la bandera de la interrupción
                    RETURN     ;Retorna de la subrutina


Send_I2C_NoAck      BSF      SSPCON2,ACKDT,0     ;Pone a 1 el bit de ACKNOWLEDGE DATA
                    BSF      SSPCON2,ACKEN,0     ;Genera la condición de NO ACKNOWLEDGE Poniendo a 1 el bit ACKEN
Se2                 BTFSS    PIR1,SSPIF,0     ;Espera a que la condicion de No ACK haya sido completada
                    BRA      Se2     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF,0     ;Borra la bandera de la interrupción
                    RETURN     ;Retorna de la subrutina


Stop_I2C            BSF      SSPCON2,PEN,0     ;Genera la condición de STOP poniendo a 1 el bit PEN
P2                  BTFSC    SSPCON2,PEN,0     ;Espera a que se ponga a cero el bit PEN
                    BRA      P2
Se3                 BTFSS    PIR1,SSPIF,0     ;Espera a que la condicion de Stop haya sido completada
                    BRA      Se3     ;cuando se ponga a 1 la bandera de interrupción
                    BCF      PIR1,SSPIF,0     ;Borra la bandera de la interrupción
                    RETURN 



LIST

y este es el programa principal:



Código: [Seleccionar]

;************************************************** www.ingeniopic.com ***************************************************
; PROGRAMA : 18F2550_I2C.asm
; Funcion : Ejemplo I2C
;           
;   
;  Revision : 1.0        12/06/2016            Programa para : PIC18F2550
; CPU Clock : 48 MHz                     Reloj instruccion :
;       WDT : Deshabilitado                  Tipo de reloj : HSPLL (crystal 4Mhz)
; Code Prot : OFF           
;************************************************* www.ingeniopic.com **************************************************


LIST   P=PIC18F2550   ;Se indica el modo de procesador

     #INCLUDE   <P18F2550.inc>


      RADIX   HEX      ;Sistema de numeracion hexadecimal

    CONFIG PLLDIV =1
  CONFIG USBDIV = 1
  CONFIG CPUDIV = OSC1_PLL2
  CONFIG FOSC = HSPLL_HS      ;Osc por XTAL 4mhz
 
 
  CONFIG DEBUG = OFF
      CONFIG PWRT = OFF
      CONFIG BOR  = OFF
      CONFIG WDT = OFF;ON
  CONFIG WDTPS = 256
      CONFIG MCLRE = ON
      CONFIG PBADEN = OFF
      CONFIG LVP = OFF
      CONFIG CP0 = OFF
      CONFIG CP1 = OFF
      CONFIG CP2 = OFF
      CONFIG CP3 = OFF
      CONFIG CPB = OFF
      CONFIG CPD = OFF
  CONFIG CCP2MX= OFF
ERRORLEVEL -302



I2C_VAR EQU 0X7A0



#define BANK0 movlb 0x00
#define BANK1 movlb 0x01
#define BANK2 movlb 0x02
#define BANK3 movlb 0x03
#define BANK4 movlb 0x04
#define BANK5 movlb 0x05
#define BANK6 movlb 0x06
#define BANK7 movlb 0x07
#define BANK8 movlb 0x08
#define BANK9 movlb 0x09
#define BANK10 movlb 0x0A
#define BANK11 movlb 0x0B
#define BANK12 movlb 0x0C
#define BANK13 movlb 0x0D
#define BANK14 movlb 0x0E
#define BANK15 movlb 0x0F

#define GENERAL_BANK movlb 0x07 ;banco de trabajo general
   
#define I2C_18F 0x0100 ;direccion donde hubicaremos el programa de gestion del I2C



;#define ID_WRITE    movlw 0xD0 ;valor de direccion para escritura del DS1307
;#define ID_READ movlw 0xD1 ;valor de direccion para lectura del DS1307
;#define ID_WRITE    movlw 0x42 ;valor de direccion para escritura del DS1307
;#define ID_READ movlw 0x43 ;valor de direccion para lectura del DS1307
#define ID_WRITE    movlw 0xA0 ;valor de direccion para escritura del 24c16
#define ID_READ movlw 0xA1 ;valor de direccion para lectura del 24c16

;<<<<<<---------------------- VECTOR DE RESET ------------------------>>>>>>>
          ORG    0x00      ;Inicio en el Vector de Reset
  goto   INICIO      ;ir a la primera instruccion del programa

INICIO clrwdt
call CLEAR_ALL ;borra toda la ram del pic
GENERAL_BANK


clrf INTCON ;desactiva interrupciones
; clrf TMR0L
; clrf TMR0H
;
clrf UCON,1

clrf PIE1,1      ;deshabilita interrupciones perifericas


clrf PORTB
clrf LATB


movlw 0x07
movwf CMCON

clrf UCON,0 ;deshabilita el usb para que los bancos 6 y 7 sean accesibles.
;
bcf UCON,USBEN ;deshabilita USB
bcf CVRCON,CVREN ;deshabilita comparador


;
;configura i2c
bsf TRISB,0;SDA ;configura pins como entrada
bsf TRISB,1;SCL ;configura pins como entrada

bsf PIE1,SSPIE
movlw 0x28        ; SPI master, clk/16, ckp=1
movwf SSPCON1      ; SSPEN enabled

movlw   0x80                ; set up spi port, SPI master,
movwf   SSPSTAT             ; cke = 0 (mode 1,1)
;movlw .159 ; configurar I2C a 100kHz (para fosc de 64Mhz) clock=Fosc/(4*(SSPxADD+1))
;movlw .39 ; configurar I2C a 400kHz (para fosc de 64Mhz) clock=Fosc/(4*(SSPxADD+1))
movlw .119 ; configurar I2C a 100kHz (para fosc de 48Mhz) clock=Fosc/(4*(SSPxADD+1))
;movlw .29 ; configurar I2C a 400kHz (para fosc de 48Mhz) clock=Fosc/(4*(SSPxADD+1))
;movlw .9 ; configurar I2C a 100kHz (para fosc de 4Mhz) clock=Fosc/(4*(SSPxADD+1))
;movlw .59 ; configurar I2C a 100kHz (para fosc de 24Mhz) clock=Fosc/(4*(SSPxADD+1))

movwf SSPADD
clrf SSPCON2
clrf PIR1

clrf INTCON3



CLRF INTCON


;***********************************************PRINCIPIO DEL PROGRAMA********************************************************************
 
PRINCIPAL lfsr FSR2,0X100 ;principio de ram donde se introduciran los datos para escribir en el RTC

;lectura de datos en un rango de direcciones
BANK7
lfsr FSR2,0X100 ;principio de ram donde se introduciran los datos leidos del dispositivo I2C
movlw 0x00 ;principio de direccion a leer
movwf DIR_I2C
movlw 0x08 ;numero de bytes a gestinar
call SEQ_READ ;leer datos del DS1307 y hubicarlos en la direccion 0x100 de la ram

;escritura de datos en un rango de direcciones
BANK7
movlw 0x00 ;principio de direccion del dispositivo I2C
movwf DIR_I2C
lfsr FSR2,0X200 ;banco de ram donde se leeran los datos del pic
movlw 0x10 ;numero de bytes a transferir
call RANG_WRITE ;rutina de escritura de rango de direcciones

BANK7
;Lectura de un dato en una direccion
movlw 0x01 ;direccion
call BYTE_READ

;Escritura de un dato en una direccion
BANK7
movlw 0x01 ;direccion
movwf DIR_I2C
movlw 0x55 ;dato
call BYTE_WRITE

;
;

goto PRINCIPAL


;******************************************************** CLEAR **************************************************************
;borra banco seleccionado en W
;; return ;retorna
;******************************************************** CLEAR_ALL **************************************************************
;borra toda la memoria

CLEAR_ALL movlw 0x0f ;valor limite de borrado FSR0H
lfsr FSR0,700h ;direcciona la ram
clr2 clrf INDF0 ;borra direccion direccionada
incfsz FSR0L ;siguiente direccion a borrar
goto clr2 ;salta a borrado de direccion
decf FSR0H,f ;decrementa direccionamiento alto
cpfseq FSR0H ;comprueba si se ha llegado al final del direccionamiento
goto clr2 ;si no ha llegado,continua borrando
return ;retorna si se a acabado el borrado



org I2C_18F
include "I2C_18F.inc"

end



Ahora pondre imagenes con diferentes tramas del ISIS para ver como funciona esto del I2C en una eeprom 24lc16.



La primera linea corresponde a la llamada de la rutina    SEQ_READ.es una sequencia de lectura.y lo que hace es leer una cantidad determinada de bytes de la 24lc16.
antes de llamar a esta rutina hay que indicarle en que parte de la memoria de nuestro Pic hay que introducir los datos que vamos a leer de la 24lc16.
por ejemplo poniendo: lfsr   FSR2,0X100.   usaremos el direccionamiento de la memoria mediante el registro FSR2.si quisieramos otro registro,habria que
cambiar tambien el registro de la rutina de lectura.

la direccion 0x100 es el principio de direccion donde hubiaremos los datos leidos de la 24c16.
tambien hay que indicar el principio de la direccion de la 24lc16 donde queremos empezar a leer los datos.en este caso cargaremos el valor 0x00 en el registro DIR_I2C
cargaremos en W el numero de bytes a leer 0x08 por ejemplo.y llamaremos a la rutina: call   SEQ_READ

si os fijais en la imagen.la primera linea empieza por una S.es el comando Start. A0 es el byte de control.indica la direccion del esclavo al que estamos enviando
los datos y que el dato siguiente que se va a enviar es de escritura.A(ACKNOWLEDGE) es un bit de informacion que viene del esclavo y nos indica que esta preparado
para recibir el siguiente dato.
Sr es un restart que enviamos al esclavo para iniciar otra comunicacion.A1 es de nuevo el byte de control.pero esta vez indicamos al esclavo que queremos leer de el.
A nos vuelve a decir que esta preparado.

y posterior mente reciviremos una secuencia de los datos almacenados en la 24lc16 separados por un A(ACKNOWLEDGE)de cada byte que se lea.para finalizar la lectura
se envia un N(NoAck) y P(Stop)




En la segunda linea.se trata de escribir en la 24lc16 un numero determinado de datos hubicados desde la ram del Pic.la rutina se llama RANG_WRITE
antes de su llamada cargaremos en el registro DIR_I2C el principio de la direccion de la memoria 24lc16 donde escribiremos los datos.en este caso 0x00

indicaremos la direccion de la ram del pic donde estan hubicados los datos a transpasar.ejem...lfsr   FSR2,0X200  ademas de indicar en W el nuemro de bytes a enviar.
una vez llamada a la subrutina call RANG_WRITE.reciviremos los datos como los de la segunda linea de la imagen.

S (Start).A0 indicamos que vamos a escribir.A(ACKNOWLEDGE) nos indica siguiente byte a escribir.que sera la direccion donde empezaremos el envio de datos.A(ACKNOWLEDGE)
nos vuelve a indicar que enviemos otro byte.pero de aqui en adelante los bytes que se envien son datos.entre dato y dato se recibira un (ACKNOWLEDGE)
y cuando hallamos terminado se enviara un S(Stop)



En la siguiente imagen pongo dos lineas la lectura y escritura de un solo byte.



La rutina de lectura de un solo byte se llama BYTE_READ.
antes de su llamada hay que indicarle solamente la direccion de donde queremos leer el dato.en este caso la 0x01 que intrduciremos en W.

la repueta de esta rutina esta en la primera linea.

S (Start),A0(Comando de ecritura) ,A(ACKNOWLEDGE) ,A1(Comando de lectura) ,A(ACKNOWLEDGE) ,Sr(Restart),A(ACKNOWLEDGE) 0x00(el dato recibido) N(NoAck) y P(Stop)



la segunda linea de la imagen.corresponde a la rutina de escritura de un solo byte.cargaremos en DIR_I2C la direccion de la 24lc16 y en W el dato a enviar.
antes de la llamada a esta rutina.

la segunda respuesta de la imagen corresponde a esta subrutina.

S (Start),A0(Comando de ecritura) ,A(ACKNOWLEDGE) ,01(Direccion de la 24lc16) ,A(ACKNOWLEDGE) , 55(el dato a enviar) A(ACKNOWLEDGE) y P(Stop)



En algunas lineas envio un Sr.cuando segun el datasheet deberia de ser un S(start).pero se me da el caso de que el ISIS se me bloquea.asi que mientras funcione.
es lo que voy a poner.en el ICD3 no tengo ningun problema en poner S.y supngo que en un ciruito montado tampoco deberia haber problemas.

no si lo habre dicho.pero tambien tengo problemas en ISIS al querer leer o escribir un byte y luego un rango de bytes.el programa se bloquea en los Stop finales.
asi que sera mas que recomendable usar un Watchdog para evitar cuelgues.

he intentado ajustarme lo mejor posible al datasheet.pero quizas haya algun truco para estos bloqueos.o quizas los bloqueos sean porque haya algo mal en mi codigo.
puede que haya que enviar mas de un Stop.u otra cosa.pero yo por el momento no lo se.

espero que les sea de utilidad estas rutinas.proximamente pondre otras rutinas para otros pic y dispositivos mas avanzados.





Montando mi primera impresora 3D (Raprep Prusa i3)

Desconectado groundman

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1870
    • www.ingeniopic.com
Re:Protocolo y Dispositivos I2C.
« Respuesta #1 en: 14 de Junio de 2016, 11:10:25 »

aqui estamos de nuevo.pero ahora voy a poner un ejemplo de transmision con el reloj DS1307.en esta imagen pongo una trama de lectura.donde el DS1307 nos responde
con los datos de fecha,hora y el registro de control.



como podemos ver la trama empieza con la S(Start)
D0 que indicamos al esclavo que vamos a escribir en el.y podemos notar que este valor varia de los anteriores ejemplos con la memoria 24lc16.ya que son dierentes direcciones.
esto posibilita la opcion de poner estos dos dispositivos en paralelo sin que halla conflictos.aunque tenemos la misma tecnica de dispner el ultimo bit a 0 para escribir
y 1 para leer.

A(ACKNOWLEDGE) recibido por el esclavo.

00 indicamos la direccion que queermos leer.en este caso la 0x00 y A(ACKNOWLEDGE)

Sr(Restart),A(ACKNOWLEDGE) y ya recibiremos todos los datos disponibles hasta que enviemos un N(NoAck) y P(Stop).para terminar la recepcion.

en el ejemplo podemo notar los siguientes datos recibidos:
28,09,15,03,14,06,16,10 que son: segundos,minutos,hora,dia de la semana"martes",dia 14,mes 06,año 16,registro de control 10.

el DS1307 tambien tiene una eeprom interna.donde podemos leer y escribir.que va desde la direccion 08h a la 3Fh.que puede servirnos para programar una alarma por ejemplo.


la forma de lectura es la misma que para el 24lc16.

lfsr   FSR2,0X100      ;principio de ram donde se introduciran los datos leidos del dispositivo I2C
movlw   0x00         ;principio de direccion a leer
movwf   DIR_I2C
movlw   0x08         ;numero de bytes a gestinar
call   SEQ_READ      ;leer datos del DS1307 y hubicarlos en la direccion 0x100 de la ram

y este seria el resultado.meter los datos eidos del DS1307 en la memoria de nuestro pic.



puede notarse que los valores de hora y fecha estan en Hexagesimal.pero solo para poder distinguirlos.aunque para manipular estos datos tendran que pasarse a ASCII si queremos
mostrarlos en una LCD o a decimal si  queremos sumarlos restarlo o compararlos en el caso que programar una alarma.

para pasarlos a ASCII es muy facil.solo tenemos que seleccionar uno de los nibles que queremos usar y sumarle 48d. o 30h.asi tendremos el codigo asccii de ese nible.o valor numerico
si lo queremos entender asi.

en el caso de querer pasar el valor Hex a decimal de todos los datos de hora y fecha.solo tenemos que usar esta rutina que he realizado:

Código: [Seleccionar]
;************************************* TRANSFIERE DATOS BCD DEL RTC A OTRA ZONA CONVERTIDOS EN HEX ******************************************
; Programa que transfiere los datos BCD del RTC a otra xona de memoria convertidos en HEX
; ejemplo: 0x15(15 segundos del RTC) a 0x0F (valor 15 en decimal)

TRANS_RTC lfsr FSR1,0x100 ;principio de direccion donde estan hubicados los valores del RTC
lfsr FSR2,0x108 ;principio de direccion donde se hubicaran los datos convertidos
rep_mem movf INDF1,W ;introduce en W el valor el valor a convertir
call BCD_HEX ;convierte valor contenido en W
movwf POSTINC2 ;traspasa el valor convertido a la direccion apuntada por FSR2
incf FSR1L ;incrementa siguiente valor a leer
btfss FSR1L,3 ;comprueba si se convirtieron los 8 valores
goto rep_mem ;si no es asi,repite
return ;en caso contrario retorna


;*********************************** CONVERTIR VALOR HEX EN DECIMAL ******************************************************
; Convierte valor hexagesimal en decimal.
; ejemplo: 0x15(15 segundos del RTC) a 0x0F (valor 15 en decimal)
BCD_HEX BANK7 ;selecciona banco 7 de ram
movwf ByteL ;carga valor a convertir contenido en W
movwf ByteH ;carga valor a convertir contenido en W
movlw 0x0f ;selecciona el nibble bajo de W
andwf ByteL,f ;introducelo en el registro ByteL
movlw 0xf0 ;selecciona el nibble alto de W
andwf ByteH,f ;introducelo en el registro ByteH
swapf ByteH,w ;invierte los nibles de ByteH e introduce el resultado en W
mullw .10 ;multiplica el contenido de W por 10d
movf PRODL,w ;caga el resultado en W
addwf ByteL,w ;suma el contenido de ByteL a W
return
en esta imagen pongo el resultado de esa conversion.los bytes convertidos estan en rojo.con estos datos ya podemos realizar operaciones arismeticas.cosa que antes no podiamos.
porque aquellos datos solo son para visualizacion.      



Montando mi primera impresora 3D (Raprep Prusa i3)

Desconectado groundman

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1870
    • www.ingeniopic.com
Re:Protocolo y Dispositivos I2C.
« Respuesta #2 en: 25 de Octubre de 2016, 11:15:50 »
hola de nuevo.he vuelto a practicar con el DS1307 pero con el 18f87k22 y a 3.3v. pero no me funciono.asi que lo puse a 5v y tampoco funciono.
lo monte en el 18f2550 a 5v y tampoco funciono.lo unico comun a todos ellos es que los datos de la lectura del reloj eran:

0x80,0x00,0x00,0x01,0x01,0x01,0x00,0x03

asi que supuse que el DS1307 estaba averiado o bloqueado.la verdad que no se si seria por el byte de control o porque hay que ponerlo en hora.
pero al grabarle los datos de la hora el DS1307 empezo a funcionar.

estos valores los he buscado por todo internet y no he encontrado nada parecido.por eso los explico aqui por si ha alguien le pasa que sepa
lo que hay que hacer.y no se vuelba loco  buscando el fallo tal y como me ha pasado a mi.

ya que se esto.lo siguiente sera probarlo en el 18f87k22 con 3.3v haber si lo puedo adaptar a los 5v que es con lo que funciona el DS307.un saludo
Montando mi primera impresora 3D (Raprep Prusa i3)

Desconectado groundman

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1870
    • www.ingeniopic.com
Re:Protocolo y Dispositivos I2C.
« Respuesta #3 en: 27 de Octubre de 2016, 10:16:17 »
aqui traigo una imagen de un dispositivo chino que trae un DS1307 y una eeprom.



segun el datasheet del dispositivo el DS1307 trabaja a 5v.pero no se porque,he probado un pic18f87k22 a 3.3v y funciona.
asi que toddos los problemas que tenia hera porque el DS1307 estaba bloqueado.no por las alimentaciones.


asi que me pongo manos a la obra con la comunicacion I2C de la camara OV7670.
Montando mi primera impresora 3D (Raprep Prusa i3)


 

anything