TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: BrunoF en 21 de Marzo de 2006, 20:36:00

Título: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 21 de Marzo de 2006, 20:36:00
Buenas...
Aca posteo lo que programe(he sudado bastante pa lograrlo) para leer y escribir una EEPROM de 8kbits(24LC08B) desde un 16F877A en Assembler a FOSC = 20Mhz utilizando el modulo I2C de este PIC.

Lo que hace es grabar un dato en la posicion 0 de la EEPROM , y luego leerlo y mostrar el dato leido en el PuertoB del PIC.

<span class="texto_mini">Codigo:</span>[hr /
]

;Made by Bruno Fascendini
;bipus24hs@hotmail.com


      LIST      P=PIC16F877A
      #include   <p16F877a.INC>
      ERRORLEVEL   -302

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; CONSTANTES:
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define      CLOCK         D"0"
#define      STROBE         D"2"
#define      SCL         D"3"
#define      SDA         D"4"

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;Memoria EEPROM
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; MACROS
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BANK0      MACRO
      BCF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK1      MACRO
      BSF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK2      MACRO
      BSF   STATUS,RP1
      BCF   STATUS,RP0
      ENDM

BANK3      MACRO
      BSF   STATUS,RP1
      BSF   STATUS,RP0
      ENDM

;GPR: GENERAL PURPOSE REGISTERS

;0x20 -> 0x47 Reservados Memoria cartel.

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DIRL      EQU   0X20
DIRH      EQU   0X21   
DATO      EQU   0X22   ;temporar. byte a enviar/dato leido
flag      EQU   0X24
cuenta      EQU   0X25
CONTA0      EQU   0X26
CONTA1      EQU   0X27
DATASSP      EQU      0x70

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



      ORG   0X0000
      GOTO   INICIO

      ORG   0X0004
      return

      ORG   0X0020

INICIO      BANK0
      BSF   STATUS,RP0
      MOVLW   0x06       ;PINS DEL PUERTO A Y PUERTO E TODOS DIGITALES.
      MOVWF   ADCON1
      CLRW
      MOVWF TRISA

      BANK0
      CLRF   PORTA
      BSF      STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISB

      BANK0
      CLRF   PORTB
      BSF      STATUS,RP0
      MOVLW   B"00011000"
      MOVWF   TRISC
   
      BANK0
      MOVLW   B"00010000"
      MOVWF   PORTC
      BSF   STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISD

      BANK0
      CLRF   PORTD
      BSF      STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISE
   
      BANK0
      CLRF   PORTE

      call   i2c_init   ;configurar y encender I2C
      clrf   DIRH      ;cargar paginas de 24LC08B en las cuales escribir
      clrf   DIRL      ;cargar direccion de 24LC08B en las cuales escribir      
      movlw   0xA0
      movwf   DATASSP      ;cargar dato a escribir en la 24LC08B
      call   WriteI2CByte
      btfss   flag,0
      goto   errorcom

      call   DEMORA      ;dar 10ms a que termine la escritura

      clrf   DIRH      ;cargar paginas de 24LC08B de las cuales leer
      clrf   DIRL      ;cargar direccion de 24LC08B de las cuales leer
      call   ReadI2CByte
      btfss   flag,0
      goto   errorcom

      movlw   .1      ;escritura y lectura OK. encender RA0, mostrar dato leido en PuertoB y loop eterno
      movwf   PORTA
      movf   DATO,w
      movwf   PORTB
      nop
      goto   $-1

errorcom   movlw   .3      ;error de escritura o lectura, encender RA0 y RA1 y loop eterno
      movwf   PORTA
      nop
      goto   $-1


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DEMORA
   movlw   .55
   movwf   CONTA0
RET1
   movlw   .181
   movwf   CONTA1
RET2
   nop
   nop
   decfsz   CONTA1,1
   goto   RET2
   decfsz   CONTA0,1
   goto   RET1
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_init

   movlw       b"00011000"
   banksel       TRISC         ;banco 1
   iorwf       TRISC,F
   movlw       b"00001011"      ;.11 para 400khz @ 20 mhz
   movwf       SSPADD         ;400 khz @ 20 mhz   
   clrf       SSPSTAT
   movlw      b"00101000"
   bcf      STATUS,RP0      ;banco 0
   movwf       SSPCON
   CLRF      PIR1
   call      i2c_idle
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_idle

   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W
   goto       $-1

   movf       SSPCON2,w
   andlw       0x1F
   btfss       STATUS,Z
   goto       $-3

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_start
   call      i2c_idle
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,SEN
   btfsc       SSPCON2,SEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF
   goto      $-1

   bcf      PIR1,SSPIF
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_restart

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,RSEN
   btfsc       SSPCON2,RSEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_read

   call      i2c_idle   
   bsf      STATUS,RP0      ;banco 1   
   bsf       SSPCON2,RCEN      ;activar modo lectura
   btfsc       SSPCON2,RCEN      ;termino la recepcion?
   goto       $-1         ;no, esperar

   btfss      SSPSTAT,BF      ;dato disponible en SSPBUF para ser leidos?
   goto      $-1         ;no, esperar

   bcf      STATUS,RP0      ;banco 0
   movf      SSPBUF,W
   movwf      DATO
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_write

   bcf      flag,0         ;inicializar flag como "error"
   call      i2c_idle
   movf      DATO,w         ;mover DATO a W
   movwf       SSPBUF         ;cargar dato en buffer I2C
   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W      ;esperar a que termine el envio
   goto       $-1

   btfss      SSPCON2,ACKSTAT    ;checkear ack
   goto      okack

   bsf       SSPCON2,PEN      ;error ack. enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return               ;volver con flag= 0 error

okack   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF      ;esperar finalizacion del noveno clock
   goto      $-1

   bcf      PIR1,SSPIF
   bsf      flag,0         ;volver con flag = 1 OK!
   return
   
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendack

   bsf      STATUS,RP0      ;banco 1
   bcf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendnack

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_stop
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,PEN      ;enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;WriteI2CByte
;DIRH<1:0>               ;paginas de la eeprom en las cuales grabar
;DIRL                  ;direccion baja de la posicion de eeprom en las cuales grabar
;DATASSP               ;dato a grabar
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

WriteI2CByte

   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   rlf      DIRH,W
   andlw      b"00000110"      ;solo 2 bits de paginas admitidas para esta eeprom. Asegurar bit0 =0 (write)
   iorlw      b"10100000"      ;insertar identificador de la EEPROM(1010) en el mensaje
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   movf      DIRL,w
   movwf      DATO
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   movf      DATASSP,w
   movwf      DATO         ;cargar en DATO
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   call      i2c_stop
   return               ;flag = 1 OK!

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;ReadI2CByte
;DIRH<1:0>               ;paginas de la eeprom de las cuales leer
;DIRL                  ;direccion baja de la posicion de eeprom de las cuales leer

;devuelve:
;DATO                  ;dato leido
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ReadI2CByte
   
   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   rlf      DIRH,W   
   andlw      b"00000110"      ;solo 2 bits de paginas admitidas para esta eeprom. Asegurar bit0 =0 (write)
   iorlw      b"10100000"      ;insertar identificador de la EEPROM(1010) en el mensaje
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   movf      DIRL,w
   movwf      DATO
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   call      i2c_restart      ;enviar RESSTART
   rlf      DIRH,W   
   andlw      b"00000110"      ;solo 2 bits de paginas admitidas para esta eeprom.
   iorlw      b"10100001"      ;insertar identificador de la EEPROM(1010) en el mensaje. Asegurar bit0 =1 (Read)
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,0
   return               ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return               ;flag = 1 OK!

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   END





Espero les sea de utilidad. Exitos!
Título: RE: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: Chaly29 en 22 de Marzo de 2006, 06:43:00
Me consta que a sudado, Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas Muchas risas


Un saludo

Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 11 de Mayo de 2008, 17:19:30
hola,el mplab no me compila tu programa. me parece que tienes un error en esta linea:

movf      DATASSP,w

ya que DATASSP la has definido como un valor y aqui la has utilizado como un registro.

esta en el subprograma WriteI2CByte.

creo que deberia poner :movf   SSPBUF,w

saludos
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 11 de Mayo de 2008, 19:43:31
Hola groundman!

Si. es un error(y grave) ya que estaria trabajando sobre el registro del TMR0

Igualmente deberia compilar pese a eso.

Saludos y gracias.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: RALF2 en 12 de Mayo de 2008, 22:35:18
Que tal amigos!
BrunoF muy bueno el ejemplo yo hice algo similar ya hace tiempo utilizando para ello el i2c por hardware del pic16f876A.  :D

Una observacion que pudiese facilitar las cosas a la hora de seleccionar los bancos  :mrgreen:
Veo que creaste varios macros para la seleccion de los bancos ,pero, hay una instruccion que trae el mplab que se llama BANKSEL que te facilita enormemente el manejo de los bancos  :mrgreen:

Saludos
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 13 de Mayo de 2008, 01:49:03
Que tal amigos!
BrunoF muy bueno el ejemplo yo hice algo similar ya hace tiempo utilizando para ello el i2c por hardware del pic16f876A.  :D

Una observacion que pudiese facilitar las cosas a la hora de seleccionar los bancos  :mrgreen:
Veo que creaste varios macros para la seleccion de los bancos ,pero, hay una instruccion que trae el mplab que se llama BANKSEL que te facilita enormemente el manejo de los bancos  :mrgreen:

Saludos

Bueno, si...existe BANKSEL y BANKSELW para la selección de bancos en MPLAB, pero si te fijas en el programa, solo uso las macros al inicio del programa y no en el resto del código. Se podría cambiar. Gracias.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: tapi8 en 13 de Mayo de 2008, 15:32:00
  Me creo que hayas sudado para escribirlo, yo sudo para leerlo y entenderlo.
Gracias Bruno me va a ser de utilidad.


saludos
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 14 de Mayo de 2008, 11:01:42
a mi me pasa igual,me esta costando entenderlo.pero ya estoy poniendo texto de informacion en la ineas del programa y leyendolo muchas vezes.y tambien utilizando BANKSEL.

saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 14 de Mayo de 2008, 16:33:17
hola,BrunoF.me esta siendo de gran utilidad tu programa,pero todabia no he podido hacerlo funcionar.
y es que creo que tiene varios errores.

he encontrado otro si no me equivoco,en la linea.

movwf   DATASSP      ;cargar dato a escribir en la 24LC08B

deberia poner : movwf DATO    ;?????
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 14 de Mayo de 2008, 17:18:09
Hola!

Bueno, estuve mirando cómo había aplicado el módulo I2C en uno de los proyectos en los cuales lo he utilizado y esta distinto. No se porque lo he posteado mal aqui. Se ve que era alguna prueba en la que no habia visto ese detalle....Fijate que la mejor opcion es redefinir DATASSP.
Modifique el primer post de este hilo para que vean cómo debería quedar(es importante destacar que he elegido la posición de memoria 0x70 para DATASSP por ser accesible desde cualquiera de los 4 bancos de esta serie de 16F. Esto hace que uno se despreocupe de andar seleccionando banco a la hora de leer o escribir en DATASSP).

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 14 de Mayo de 2008, 17:20:09
Y debería funcionar...Al menos ha funcionado en muchos productos que he diseñado y actualmente se venden y utilizan...

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 14 de Mayo de 2008, 19:03:47
gracias por rectificarlo.

quiero modificarlo para utilizarlo en un 16f876.y la eeprom 24lc256.
pero las modificaciones que he hecho no han dado los resultados que queria.no se si sera porque este programa no vale para el direccionamiento de esta memoria,o porque he hecho algo mal.

tendre que tirarme todo el sabado y el domingo para intentar comprender el programa y hacerlo funcionar.

Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 14 de Mayo de 2008, 19:33:27
gracias por rectificarlo.

quiero modificarlo para utilizarlo en un 16f876.y la eeprom 24lc256.
pero las modificaciones que he hecho no han dado los resultados que queria.no se si sera porque este programa no vale para el direccionamiento de esta memoria,o porque he hecho algo mal.

tendre que tirarme todo el sabado y el domingo para intentar comprender el programa y hacerlo funcionar.



Bueno, yo he usado en un proyecto precisamente el 16F876A con una 24lc256 y si...hay que cambiar unas cositas...

Reemplaza las funciones por estas que son las que use para las 24lc256..

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;WriteI2CByte
;DIRH<1:0>                  ;paginas de la eeprom en las cuales grabar
;DIRL                     ;direccion baja de la posicion de eeprom en las cuales grabar
;DATASSP                  ;dato a grabar
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

WriteI2CByte

   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   movlw      b'10100000'      ;"1010"= identificador EEPROM. "000" = numero EEPROM "0"= Write
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits de paginas admitidas para esta eeprom.
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura
   
   movf      DATASSP,W
   movwf      DATO         ;cargar en DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;ReadI2CByte
;DIRH<1:0>               ;paginas de la eeprom de las cuales leer
;DIRL                  ;direccion baja de la posicion de eeprom de las cuales leer

;devuelve:
;DATASSP                  ;dato leido
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ReadI2CByte
   
   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100000'      ;1010=identificador EEPROM 000= numero EEPROM 0=write
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits admitidos para esta EEPROM
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_restart      ;enviar RESSTART

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1=read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CurrentI2CRead

   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1= read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 15 de Mayo de 2008, 18:24:37
hola,queria preguntarte que valor asignar al OK de estas lineas:

btfss      flag,OK   

ya que no puedo compilar.debido a que esta variable no esta declarada.

saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 15 de Mayo de 2008, 18:32:16
Hola groundman! Perdon x eso...

#define    OK            D'0'

Igual funcionaría con cualquier valor entre 0 y 7 ;)

Saludos!
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 16 de Mayo de 2008, 17:38:36
OK,entendido.

y queria hacerte otra pregunta.
el 24LC256 y toda esta serie tiene un pin WP que creo que es para la proteccion de escritura.

en el datasheet creo haber entendido de que este`pin tiene una resistencia interna que hace de que si el pin esta desconectado,el chip este desprotegido.
es realmente asi o por el contrario estaria protegido y puede que sea ese el motivo de que no me grabe nada?

ademas probando el pic ,me he dado cuenta de que se me queda parado en estas lineas:

bcf      STATUS,RP0      ;banco 0   
btfss      PIR1,SSPIF     ;espera a que salte la interrupcion por cambio del flag SSPIF
goto      $-1

supongo que sera.que esta interrupcion no se sucede nunca.hay que activar gie?

y otra cosa que he visto:

movlw       b'00001011'     ;.11 para 400khz @ 20 mhz   
movwf       SSPADD            ;400 khz @ 20 mhz   

si este codigo esta optimizado para 20Mhz y yo estoy utilizando 4Mhz puede que el valor .11 no sirva para esta frecuencia.donde esta la tabla para poner el valor adecuado?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 16 de Mayo de 2008, 21:25:43
OK,entendido.

y queria hacerte otra pregunta.
el 24LC256 y toda esta serie tiene un pin WP que creo que es para la proteccion de escritura.

en el datasheet creo haber entendido de que este`pin tiene una resistencia interna que hace de que si el pin esta desconectado,el chip este desprotegido.
es realmente asi o por el contrario estaria protegido y puede que sea ese el motivo de que no me grabe nada?

Si no recuerdo mal, WP debe ir conectado a GND...
ademas probando el pic ,me he dado cuenta de que se me queda parado en estas lineas:

bcf      STATUS,RP0      ;banco 0   
btfss      PIR1,SSPIF     ;espera a que salte la interrupcion por cambio del flag SSPIF
goto      $-1

supongo que sera.que esta interrupcion no se sucede nunca.hay que activar gie?

Nono. No utilice las interr del modulo en este ejemplo.

y otra cosa que he visto:

movlw       b'00001011'     ;.11 para 400khz @ 20 mhz  
movwf       SSPADD            ;400 khz @ 20 mhz   

si este codigo esta optimizado para 20Mhz y yo estoy utilizando 4Mhz puede que el valor .11 no sirva para esta frecuencia.donde esta la tabla para poner el valor adecuado?

Es probable que debas cambiarlo...consulta el datasheet. allí debe estar.

Saludos
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 18 de Mayo de 2008, 20:04:04
hola,BrunoF.

ya que todabia estoy estancado en el codigo.se me ha ocurrido empezar de la forma mas facil.y es grabar un dato en la eeprom directamente con el programador.
y despues leerlo con el codigo que has diseñado.

ya he eliminado las instrucciones relacionadas con las interrupciones.pero sigue quedandose el programa estancado en esta linea:

btfsc       SSPSTAT,R_W      ;esperar a que termine el envio         
goto       $-1

esta en el subprograma i2c_write.no se que puede dar lugar a que no salga de este bucle. tienes alguna idea?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 18 de Mayo de 2008, 20:32:15
La verdad que no...

¿Pusiste las pullups en las lineas, no?

WP y D2,D1 y D0 de la EEPROM deberian ir a GND.

Debería funcionar...

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 18 de Mayo de 2008, 20:36:08
esas lineas estan a masa,pero no he puesto ningun tipo de resistencia en el circuito.sera ese el fallo?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 18 de Mayo de 2008, 21:55:34
Ambas líneas del I2C deben llevar(por separado) resistencias a 5V de 3.3k o 4.7k...sino no te va a funcionar nunca! :S

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 19 de Mayo de 2008, 10:43:56
 :x que ravia.el tiempo que he perdido.pero no hay mal que por bien no benga,almenos he profundizado en la utilizacion de este modulo.

ah.supongo que las resistencias hay que conectarlas entre los  pin y vcc.   no?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 19 de Mayo de 2008, 15:20:27
Sisi. Ambas van a Vcc. Jeje como bien dices...no hay mal que por bien no venga :D

Ya me comentaras si arranca.

Tendrian que quedarte similar a esto la resistencias..

(http://www.mikroe.com/en/books/picbasicbook/05/eeprom.gif)


Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 19 de Mayo de 2008, 17:50:32
lo de mal que por bien no venga. tengo un tio que es sepulturero y dice que el no quiere que nadie se muera,pero que a el  no le falte el trabajo. :D :D :D :shock:

ya he puesto las resistencias,y el programa ha salido del bucle donde estaba pillado.

pero ahora se ha quedado pillado en otro, en el subprograma i2c_read.

btfsc       SSPCON2,RCEN      ;termino la recepcion? 
goto       $-1         ;no, esperar   

yo tengo los pin A0,A1,A2 y WP a GND despues de poner las dos resistencias no creo que tenga mas fallos de hardware. o tu programa no esta puesto para que estos pin esten a GND?

ah las resistencias las he puesto de 10k como en el esquema.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 19 de Mayo de 2008, 18:10:50
jaja

Mi programa esta hecho para direccionar a la memoria 0, asi que deberia funcionar.

No he usado resistencias de 10k. Siempre use 4.7k. Igualmente supondria que deberia funcionar...:(
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 20 de Mayo de 2008, 16:57:19
hola de nuevo BrunoF.

solo hay una cosa de tu programa que no encuentro ni en los datasheet del 16f876 ni en otro datasheet dedicado especificamente con el MSSP.
y es esta linea que te comente anteriormente.

movlw       b'00001011'     ;.11 para 400khz @ 20 mhz   ;3º
movwf       SSPADD            ;400 khz @ 20 mhz   

no se porque se pone este valor.y es que no encuentro ninguna tabla.sera que no existe?

esto es lo que he visto respecto al baud rate generator pero no lo entiendo todo.

in I2C master mode,the reload value for the BRG is located in the lower 7 bits of the SSPADD register.when the BRG is loaded with this value,the BRG counts down
to 0 and stop util another reload has taken place.in I2C master mode,the BRG is reloaded automatically.if clock arbitration is taking place for instance ,the BRG will be reloaded when SCL pin is sampled higt.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 20 de Mayo de 2008, 17:55:46
Hola. El SSPADD es el que define la velocidad del I2C.

clock = Fosc / (4*(SSPADD+1))

Proba cargandole el valor .9 a SSPADD para que funcione a 100khz(@4mhz) o .4(@20mhz) segun tu oscilador.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 20 de Mayo de 2008, 18:59:16
aunque todabia no funciona.

ya he entendido lo que querias decirme.   clock = Fosc / (4*(SSPADD+1))   4Mhz/(4*(9+1))=100Khz

seguire comprobando que es lo que pasa.

saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 21 de Mayo de 2008, 18:59:36

EUREKA¡¡¡.ya me funciona. :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/

tu programa esta perfecto despues de las modificaciones que me has estando diciendo que hiciera.y cambiando algunas
directivas del compilador para este pic 16f876.me ha funcionado en los 24LC16,24LC64 y 24LC256.

el problema era que desde que empeze a modificar tu programa para adaptarlo con este chip,modifque una linea que
luego no me acorde de activarla.ademas de las resistencias de 4K7 que no puse en los pin SCL y SDA a VCC,y entonces cree un nuevo asm y puse los dos ultimos programas que posteastes,y los demas
subprogramas.ademas de modificar todos los B"00000000" por b'00000000' es decir sin las comillas.
y el  (#define    OK   D'0').y eliminar toda referencia hacia lor puertos PORTD y PORTE

abajo pongo el programa que me funciona.

saludos,y muchas gracias por tu tiempo. :-)


progama que graba dato A0 en la direccion 00h de una memoria eeprom externa mediante protocolo I2C

LIST      P=16F876
      #include   "p16F876.INC"
         __CONFIG    _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC & _BODEN_OFF &_LVP_OFF &_CPD_OFF ;&_WRT_ENABLE_OFF   
      ERRORLEVEL   -302

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; CONSTANTES:
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define      CLOCK         D'0'
#define      STROBE         D'2'
#define      SCL         D'3'
#define      SDA         D'4'
#define       OK         D'0'

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;Memoria EEPROM
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; MACROS
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BANK0      MACRO
      BCF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK1      MACRO
      BSF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK2      MACRO
      BSF   STATUS,RP1
      BCF   STATUS,RP0
      ENDM

BANK3      MACRO
      BSF   STATUS,RP1
      BSF   STATUS,RP0
      ENDM

;GPR: GENERAL PURPOSE REGISTERS

;0x20 -> 0x47 Reservados Memoria cartel.

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DIRL      EQU   0X20
DIRH      EQU   0X21   
DATO      EQU   0X22   ;temporar. byte a enviar/dato leido
flag      EQU   0X24
cuenta      EQU   0X25
CONTA0      EQU   0X26
CONTA1      EQU   0X27
DATASSP      EQU      0x70

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



      ORG   0X0000
      GOTO   INICIO

      ORG   0X0004
      return

      ORG   0X0020

INICIO      BANK0
      BSF   STATUS,RP0
      MOVLW   0x06       ;PINS DEL PUERTO A Y PUERTO E TODOS DIGITALES.
      MOVWF   ADCON1
      CLRW
      MOVWF TRISA

      BANK0
      CLRF   PORTA
      BSF      STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISB

      BANK0
      CLRF   PORTB
      BSF      STATUS,RP0
      MOVLW   B'00011000'
      MOVWF   TRISC
   
      BANK0
      MOVLW   B'00010000'
      MOVWF   PORTC
      BSF   STATUS,RP0
      ;MOVLW   0X00
      ;MOVWF   TRISD

      BANK0
      ;CLRF   PORTD
      BSF      STATUS,RP0
      ;MOVLW   0X00
      ;MOVWF   TRISE
   
      BANK0
      ;CLRF   PORTE

      call   i2c_init   ;configurar y encender I2C
      clrf   DIRH      ;cargar paginas de 24LC08B en las cuales escribir
      clrf   DIRL      ;cargar direccion de 24LC08B en las cuales escribir     
      movlw   0xA0
      movwf   DATASSP      ;cargar dato a escribir en la 24LC08B
      call   WriteI2CByte
      btfss   flag,0
      goto   errorcom

      call   DEMORA      ;dar 10ms a que termine la escritura

      clrf   DIRH      ;cargar paginas de 24LC08B de las cuales leer
      clrf   DIRL      ;cargar direccion de 24LC08B de las cuales leer
      call   ReadI2CByte
      btfss   flag,0
      goto   errorcom

      movlw   .1      ;escritura y lectura OK. encender RA0, mostrar dato leido en PuertoB y loop eterno
      movwf   PORTA
      movf   DATO,w
      movwf   PORTB
      nop
      goto   $-1

errorcom   movlw   .3      ;error de escritura o lectura, encender RA0 y RA1 y loop eterno
      movwf   PORTA
      nop
      goto   $-1


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DEMORA
   movlw   .55
   movwf   CONTA0
RET1
   movlw   .181
   movwf   CONTA1
RET2
   nop
   nop
   decfsz   CONTA1,1
   goto   RET2
   decfsz   CONTA0,1
   goto   RET1
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_init

   movlw       b'00011000'
   banksel       TRISC         ;banco 1
   iorwf       TRISC,F
   movlw       b'00001011'      ;.11 para 400khz @ 20 mhz
   movwf       SSPADD         ;400 khz @ 20 mhz   
   clrf       SSPSTAT
   movlw      b'00101000'
   bcf      STATUS,RP0      ;banco 0
   movwf       SSPCON
   CLRF      PIR1
   call      i2c_idle
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_idle

   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W
   goto       $-1

   movf       SSPCON2,w
   andlw       0x1F
   btfss       STATUS,Z
   goto       $-3

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_start
   call      i2c_idle
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,SEN
   btfsc       SSPCON2,SEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF
   goto      $-1

   bcf      PIR1,SSPIF
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_restart

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,RSEN
   btfsc       SSPCON2,RSEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_read

   call      i2c_idle   
   bsf      STATUS,RP0      ;banco 1   
   bsf       SSPCON2,RCEN      ;activar modo lectura
   btfsc       SSPCON2,RCEN      ;termino la recepcion?
   goto       $-1         ;no, esperar

   btfss      SSPSTAT,BF      ;dato disponible en SSPBUF para ser leidos?
   goto      $-1         ;no, esperar

   bcf      STATUS,RP0      ;banco 0
   movf      SSPBUF,W
   movwf      DATO
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_write

   bcf      flag,0         ;inicializar flag como "error"
   call      i2c_idle
   movf      DATO,w         ;mover DATO a W
   movwf       SSPBUF         ;cargar dato en buffer I2C
   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W      ;esperar a que termine el envio
   goto       $-1

   btfss      SSPCON2,ACKSTAT    ;checkear ack
   goto      okack

   bsf       SSPCON2,PEN      ;error ack. enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return               ;volver con flag= 0 error

okack   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF      ;esperar finalizacion del noveno clock
   goto      $-1

   bcf      PIR1,SSPIF
   bsf      flag,0         ;volver con flag = 1 OK!
   return
   
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendack

   bsf      STATUS,RP0      ;banco 1
   bcf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendnack

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_stop
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,PEN      ;enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;WriteI2CByte
;DIRH<1:0>                  ;paginas de la eeprom en las cuales grabar
;DIRL                     ;direccion baja de la posicion de eeprom en las cuales grabar
;DATASSP                  ;dato a grabar
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

WriteI2CByte

   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   movlw      b'10100000'      ;"1010"= identificador EEPROM. "000" = numero EEPROM "0"= Write
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits de paginas admitidas para esta eeprom.
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura
   
   movf      DATASSP,W
   movwf      DATO         ;cargar en DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;ReadI2CByte
;DIRH<1:0>               ;paginas de la eeprom de las cuales leer
;DIRL                  ;direccion baja de la posicion de eeprom de las cuales leer

;devuelve:
;DATASSP                  ;dato leido
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ReadI2CByte
   
   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100000'      ;1010=identificador EEPROM 000= numero EEPROM 0=write
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits admitidos para esta EEPROM
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_restart      ;enviar RESSTART

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1=read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CurrentI2CRead

   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1= read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

         END
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 21 de Mayo de 2008, 19:13:01
Wiiiiiiiiiiii!!!!!!!!!! Ya te tocaba que te funcionara! Como ves...el I2C en assembler hace sudar a uno hasta que funciona(o acaso creias que bromeaba? :D)

Felicitaciones! Y ahora a reventar esas EEPROMs

;)

 :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/ :-/

Un abrazo.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: groundman en 22 de Mayo de 2008, 10:28:56
vaya que si tenias razon,tres semanas liao por falta de tiempo.ahora seguire en el otro hilo que abri,para no saturar este.

intentare simplificarlo un poco,y poner algunas lineas de ayuda.de esta forma me ayudara a comprender mejor el I2C.y que a los demas tambien les
cueste menos su interpretacion.

saludos.

Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 18 de Diciembre de 2008, 12:06:14
Hola gente:

He ensamblado el programa y todo ok.

Ahora el problema es que aún no tengo la 24lc256 fisicamente y me he puesto a simularlo en el PROTEUS, pero  me da error.
Le he incluido unas lineas de más para saber si el error era de escritura  o lectura y para que haga un loop escribiendo y leyendo en bucle cada 1 segundo.
Lo he puesto a 20mhz, .11 en para 400khz en registro , incluso lo he modificado para 100khz pero es peor.
Me da errores erráticos, a veces de escritura (PORTA,1), a veces OK (PORTA,0) , y a veces de lectura (PORTA,2) .

Se debe esto al simulador del proteus? O hay algo que falla en el programa? Le he puesto las resistencias correspondientes de 4k7 a las lineas SDA , SCL y el WP a masa junto con los A0-A2.


Aqui os dejo el programa , a ver si veis algo anormal.

  LIST      P=16F877A
      #include   "p16F877A.INC"
         __CONFIG    _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC & _BODEN_OFF &_LVP_OFF &_CPD_OFF ;&_WRT_ENABLE_OFF   
      ERRORLEVEL   -302

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; CONSTANTES:
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define      CLOCK         D'0'
#define      STROBE         D'2'
#define      SCL         D'3'
#define      SDA         D'4'
#define       OK         D'0'

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;Memoria EEPROM
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; MACROS
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BANK0      MACRO
      BCF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK1      MACRO
      BSF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK2      MACRO
      BSF   STATUS,RP1
      BCF   STATUS,RP0
      ENDM

BANK3      MACRO
      BSF   STATUS,RP1
      BSF   STATUS,RP0
      ENDM

;GPR: GENERAL PURPOSE REGISTERS

;0x20 -> 0x47 Reservados Memoria cartel.

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DIRL      EQU   0X20
DIRH      EQU   0X21   
DATO      EQU   0X22   ;temporar. byte a enviar/dato leido
flag      EQU   0X24
cuenta      EQU   0X25
CONTA0      EQU   0X26
CONTA1      EQU   0X27
 PDel0 equ 0x28; (registro)
 PDel1 equ 0x29 ;(registro)
PDel2 equ 0x2A; (registro)
DATASSP      EQU      0x70

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



      ORG   0X0000
      GOTO   INICIO

      ORG   0X0004
      return

      ORG   0X0020

INICIO      BANK0
      BSF   STATUS,RP0
      MOVLW   0x06       ;PINS DEL PUERTO A Y PUERTO E TODOS DIGITALES.
      MOVWF   ADCON1
      CLRW
      MOVWF TRISA

      BANK0
      CLRF   PORTA
      BSF      STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISB

      BANK0
      CLRF   PORTB
      BSF      STATUS,RP0
      MOVLW   B'00011000'
      MOVWF   TRISC
   
      BANK0
      MOVLW   B'00010000'
      MOVWF   PORTC
      BSF   STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISD

      BANK0
      CLRF   PORTD
      BSF      STATUS,RP0
      MOVLW   0X00
      MOVWF   TRISE
   
      BANK0
      CLRF   PORTE
      call   i2c_init   ;configurar y encender I2C


ini

CLRF PORTB
CLRF PORTA
call DEMORA1s
      clrf   DIRH      ;cargar paginas de 24LC08B en las cuales escribir
      clrf   DIRL      ;cargar direccion de 24LC08B en las cuales escribir     
      movlw   0x55
      movwf   DATASSP      ;cargar dato a escribir en la 24LC08B
      call   WriteI2CByte
      btfss   flag,0
      goto   errorescr

      call   DEMORA      ;dar 10ms a que termine la escritura
call   DEMORA      ;dar 10ms a que termine la escritura
      clrf   DIRH      ;cargar paginas de 24LC08B de las cuales leer
      clrf   DIRL      ;cargar direccion de 24LC08B de las cuales leer
      call   ReadI2CByte
      btfss   flag,0
      goto   errorlect

           
;escritura y lectura OK. encender RA0, mostrar dato leido en PuertoB y loop eterno
      bsf  PORTA,0
      movf   DATO,w
      movwf   PORTB
      call DEMORA1s
      goto   ini

errorescr   bsf PORTA,1
      call DEMORA1s
      goto   ini

errorlect   bsf PORTA,2
      call DEMORA1s
      goto   ini


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DEMORA
   movlw   .55
   movwf   CONTA0
RET1
   movlw   .181
   movwf   CONTA1
RET2
   nop
   nop
   decfsz   CONTA1,1
   goto   RET2
   decfsz   CONTA0,1
   goto   RET1
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_init

   movlw       b'00011000'
   banksel       TRISC         ;banco 1
   iorwf       TRISC,F
   movlw      .11; b'00001011'      ;.9 para 100khz a 4mhz , .11 para 400khz @ 20 mhz
   movwf       SSPADD         ;
   clrf       SSPSTAT
   movlw      b'00101000'
   bcf      STATUS,RP0      ;banco 0
   movwf       SSPCON
   CLRF      PIR1
   call      i2c_idle
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_idle

   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W
   goto       $-1

   movf       SSPCON2,w
   andlw       0x1F
   btfss       STATUS,Z
   goto       $-3

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_start
   call      i2c_idle
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,SEN
   btfsc       SSPCON2,SEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF
   goto      $-1

   bcf      PIR1,SSPIF
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_restart

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,RSEN
   btfsc       SSPCON2,RSEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_read

   call      i2c_idle   
   bsf      STATUS,RP0      ;banco 1   
   bsf       SSPCON2,RCEN      ;activar modo lectura
   btfsc       SSPCON2,RCEN      ;termino la recepcion?
   goto       $-1         ;no, esperar

   btfss      SSPSTAT,BF      ;dato disponible en SSPBUF para ser leidos?
   goto      $-1         ;no, esperar

   bcf      STATUS,RP0      ;banco 0
   movf      SSPBUF,W
   movwf      DATO
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_write

   bcf      flag,0         ;inicializar flag como "error"
   call      i2c_idle
   movf      DATO,w         ;mover DATO a W
   movwf       SSPBUF         ;cargar dato en buffer I2C
   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W      ;esperar a que termine el envio
   goto       $-1

   btfss      SSPCON2,ACKSTAT    ;checkear ack
   goto      okack
   bsf       SSPCON2,PEN      ;error ack. enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return               ;volver con flag= 0 error

okack

  bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF      ;esperar finalizacion del noveno clock
   goto      $-1
   bcf      PIR1,SSPIF
   bsf      flag,0         ;volver con flag = 1 OK!
   return
   
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendack

   bsf      STATUS,RP0      ;banco 1
   bcf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendnack

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_stop
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,PEN      ;enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;WriteI2CByte
;DIRH<1:0>                  ;paginas de la eeprom en las cuales grabar
;DIRL                     ;direccion baja de la posicion de eeprom en las cuales grabar
;DATASSP                  ;dato a grabar
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

WriteI2CByte
bsf PORTC,0
   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   movlw      b'10100000'      ;"1010"= identificador EEPROM. "000" = numero EEPROM "0"= Write
   movwf      DATO


   call      i2c_write
   btfss      flag,OK   ;;volver. error de escritura
   return
bcf PORTC,0
   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits de paginas admitidas para esta eeprom.
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura
   
   movf      DATASSP,W
   movwf      DATO         ;cargar en DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;ReadI2CByte
;DIRH<1:0>               ;paginas de la eeprom de las cuales leer
;DIRL                  ;direccion baja de la posicion de eeprom de las cuales leer

;devuelve:
;DATASSP                  ;dato leido
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ReadI2CByte
   
   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100000'      ;1010=identificador EEPROM 000= numero EEPROM 0=write
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits admitidos para esta EEPROM
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_restart      ;enviar RESSTART

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1=read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CurrentI2CRead

   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1= read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!


DEMORA1s  movlw     .14       ; 1 set numero de repeticion  (C)
        movwf     PDel0     ; 1 |
PLoop0  movlw     .72       ; 1 set numero de repeticion  (B)
        movwf     PDel1     ; 1 |
PLoop1  movlw     .247      ; 1 set numero de repeticion  (A)
        movwf     PDel2     ; 1 |
PLoop2  clrwdt              ; 1 clear watchdog
        decfsz    PDel2, 1  ; 1 + (1) es el tiempo 0  ? (A)
        goto      PLoop2    ; 2 no, loop
        decfsz    PDel1,  1 ; 1 + (1) es el tiempo 0  ? (B)
        goto      PLoop1    ; 2 no, loop
        decfsz    PDel0,  1 ; 1 + (1) es el tiempo 0  ? (C)
        goto      PLoop0    ; 2 no, loop
PDelL1  goto PDelL2         ; 2 ciclos delay
PDelL2  clrwdt              ; 1 ciclo delay
        return              ; 2+2 Fin.
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

         END



Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 19 de Diciembre de 2008, 17:02:10
Hola! Te basaste en mi programa o en el de groundman para hacerlo? Mira que si te basaste en el mio, la memoria que use yo es muchisimo mas chica y la de 256 tiene mas bits para direccionar la posicion de memoria a utilizar.

Puede que el simulador no ande bien, no sería raro. Yo no recuerdo haberlo probado. Si podés no hay nada como probarlo en la vida real.

Por lo pronto a mi me ha funcionado bien durante mucho tiempo, sin fallas. A gran demanda de velocidad. Y a groundman también le ha funcionado por lo que ha comentado.

Espero novedades.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 19 de Diciembre de 2008, 17:02:50
P.D.

Si has leido bien el hilo, pos ya sabras entonces que con el I2C vas a tener que renegar..quieras o no...:D

;)
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 20 de Diciembre de 2008, 11:09:13
Descartado el I2c

He conseguido simular con una 25LC256 que es SPI y me va de muerte. Super rápida y mucho menos liosa.
Luego subo el código porque estoy en casa.

Ahora voy a por el DS1305 :) .
He encontrado en la página de MAXIM una aplicación para éste , pero que raro, han hecho el programa bit banging en vez de usar el SPI de hardware.
Ya os pediré ayuda seguramente :)
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 21 de Diciembre de 2008, 03:27:06
Me alegro. Entonces éxito en tu nuevos rumbos.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 21 de Diciembre de 2008, 07:55:01
Una dudita:

Cómo escribo toda la memoria?

Según entiendo la página del 25LC256 es de 64 bytes. Si le mando el comando escribir byte y no levanto el CS puedo seguir metiendo datos hasta llegar a 64, luego levanto CS y testeo el WIP del registro STATUS de la memoria para ver que finalizó la grabación de los datos.
Y luego?
Cómo salto a la próxima página? Lo hace automáticamente o debo manualmente enviarle la dirección de inicio de la próxima página?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 21 de Diciembre de 2008, 16:31:21
Hola, saludos al foro soy nuevo por aquí. Mi pregunta es: una vez visto el asm que han presentado los compañeros para el 16f877 y para el 16f876 en el cual se escribe y representa A0  en el puerto B, ¿Como se haría para escribir y sacar por el puerto B una secuencia de 4 bytes que empezase en la dirección 00 de la primera página de memoria?. Gracias y perdonar mi ignorancia llevo poco con esto de los pics.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 21 de Diciembre de 2008, 17:12:46
Según lo que he leído simplemente activas CS, mandas palabra de comando de escritura, mandas los 2 bytes de dirección (00h ambos en tu caso), mandas el byte de datos 1 , el byte de datos 2, el byte de datos 3, el byte de datos 4, levantas CS y esperas entre 5-10 ms.
Ahora para leer : CS, comando de lectura, 2 bytes de dirección del dato 1, lees dato 1, levantas CS . Muestras en puerto B el dato que tienes en el buffer. Haces una pausa para visualizarlo.
Y repite para el resto de datos, incrementando en 1 byte de dirección baja.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 21 de Diciembre de 2008, 18:30:50
Según lo que he leído simplemente activas CS, mandas palabra de comando de escritura, mandas los 2 bytes de dirección (00h ambos en tu caso), mandas el byte de datos 1 , el byte de datos 2, el byte de datos 3, el byte de datos 4, levantas CS y esperas entre 5-10 ms.
Ahora para leer : CS, comando de lectura, 2 bytes de dirección del dato 1, lees dato 1, levantas CS . Muestras en puerto B el dato que tienes en el buffer. Haces una pausa para visualizarlo.
Y repite para el resto de datos, incrementando en 1 byte de dirección baja.


¿No podrias poner algun ejemplo integrado en el asm de este mismo post?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 21 de Diciembre de 2008, 20:48:19
Me he atrevido a realizar modificaciones sobre el programa de Brunof, para que escriba en memoria AA y lo presente en puerta B,
realiza una temporización de 5s y borra puerta B, a continuación escribe en memoria (se supone que en la siguiente posición) A0
y lo presenta en puerta B, temporiza otros 5s y finalmente lo borra. ¿Que os parece?.








;programa que graba dato AA en la direccion 00h y A0 en la siguiente posición de memoria de una memoria eeprom externa
;mediante protocolo I2C pic 16f876 24LC256

           LIST      P=16F876
           #include   "p16F876.INC"
           __CONFIG    _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC & _BODEN_OFF &_LVP_OFF &_CPD_OFF ;&_WRT_ENABLE_OFF   
           ERRORLEVEL   -302

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; CONSTANTES:
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define      CLOCK       D'0'
#define      STROBE      D'2'
#define      SCL         D'3'
#define      SDA         D'4'
#define       OK         D'0'

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;Memoria EEPROM
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
; MACROS
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BANK0      MACRO
      BCF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK1      MACRO
      BSF   STATUS,RP0
      BCF   STATUS,RP1
      ENDM

BANK2      MACRO
      BSF   STATUS,RP1
      BCF   STATUS,RP0
      ENDM

BANK3      MACRO
      BSF   STATUS,RP1
      BSF   STATUS,RP0
      ENDM

;GPR: GENERAL PURPOSE REGISTERS

;0x20 -> 0x47 Reservados Memoria cartel.

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DIRL        EQU     0X20
DIRH        EQU     0X21   
DATO        EQU     0X22          ;temporar. byte a enviar/dato leido
flag        EQU     0X24
cuenta      EQU     0X25
CONTA0      EQU     0X26
CONTA1      EQU     0X27
R_ContA     EQU     0x28
R_ContB     EQU     0x29
R_ContC     EQU     0x30
DATASSP     EQU     0x70

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



            ORG     0X0000
            GOTO    INICIO

            ORG     0X0004
            return

            ORG     0X0020

INICIO      BANK0
            BSF     STATUS,RP0
            MOVLW   0x06          ;PINS DEL PUERTO A Y PUERTO C TODOS DIGITALES.
            MOVWF   ADCON1
            CLRW
            MOVWF   TRISA

            BANK0
            CLRF    PORTA
            BSF     STATUS,RP0
            MOVLW   0X00
            MOVWF   TRISB

            BANK0
            CLRF    PORTB
            BSF     STATUS,RP0
            MOVLW   B'00011000'
            MOVWF   TRISC
   
            BANK0
            MOVLW   B'00010000'
            MOVWF   PORTC
            BSF     STATUS,RP0
   

            call    i2c_init      ;configurar y encender I2C
            clrf    DIRH          ;cargar paginas de 24LC08B en las cuales escribir
            clrf    DIRL          ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   0xAA
            movwf   DATASSP       ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA        ;dar 10ms a que termine la escritura

            clrf    DIRH          ;cargar paginas de 24LC08B de las cuales leer
            clrf    DIRL          ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB
            incf    DIRL,F

            call    Retardo_5s
            clrf    PORTB


            call    i2c_init      ;configurar y encender I2C
            clrf    DIRH          ;cargar paginas de 24LC08B en las cuales escribir
            clrf    DIRL          ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   0xA0
            movwf   DATASSP       ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA        ;dar 10ms a que termine la escritura

            clrf    DIRH          ;cargar paginas de 24LC08B de las cuales leer
            clrf    DIRL          ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB

           
            call    Retardo_5s
            clrf    PORTB

            nop
            goto    $-1



;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DEMORA
            movlw   .55
            movwf   CONTA0
RET1
            movlw   .181
            movwf   CONTA1
RET2
            nop
            nop
            decfsz   CONTA1,1
            goto   RET2
            decfsz   CONTA0,1
            goto   RET1
            return

;****************************************************************************************************************************

Retardo_5s                                        ;
         movlw    d'50'                           ;
         goto     Retardo_1Decima

Retardo_1Decima
         movwf    R_ContC                         ;
R1Decima_BucleExterno2
         movlw    d'100'                          ;
         movwf    R_ContB                         ;
R1Decima_BucleExterno
         movlw    d'249'                          ;
         movwf    R_ContA                         ;
R1Decima_BucleInterno     
         nop                                      ;
         decfsz   R_ContA,F                       ;
         goto     R1Decima_BucleInterno           ;
         decfsz   R_ContB,F                       ;
         goto     R1Decima_BucleExterno           ;
         decfsz   R_ContC,F                       ;
         goto     R1Decima_BucleExterno2          ;
         return




;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_init

   movlw       b'00011000'
   banksel       TRISC         ;banco 1
   iorwf       TRISC,F
   movlw       b'00001011'      ;.11 para 400khz @ 20 mhz
   movwf       SSPADD         ;400 khz @ 20 mhz   
   clrf       SSPSTAT
   movlw      b'00101000'
   bcf      STATUS,RP0      ;banco 0
   movwf       SSPCON
   CLRF      PIR1
   call      i2c_idle
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_idle

   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W
   goto       $-1

   movf       SSPCON2,w
   andlw       0x1F
   btfss       STATUS,Z
   goto       $-3

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_start
   call      i2c_idle
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,SEN
   btfsc       SSPCON2,SEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF
   goto      $-1

   bcf      PIR1,SSPIF
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_restart

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,RSEN
   btfsc       SSPCON2,RSEN
   goto       $-1

   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_read

   call      i2c_idle   
   bsf      STATUS,RP0      ;banco 1   
   bsf       SSPCON2,RCEN      ;activar modo lectura
   btfsc       SSPCON2,RCEN      ;termino la recepcion?
   goto       $-1         ;no, esperar

   btfss      SSPSTAT,BF      ;dato disponible en SSPBUF para ser leidos?
   goto      $-1         ;no, esperar

   bcf      STATUS,RP0      ;banco 0
   movf      SSPBUF,W
   movwf      DATO
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_write

   bcf      flag,0         ;inicializar flag como "error"
   call      i2c_idle
   movf      DATO,w         ;mover DATO a W
   movwf       SSPBUF         ;cargar dato en buffer I2C
   bsf      STATUS,RP0      ;banco 1
   btfsc       SSPSTAT,R_W      ;esperar a que termine el envio
   goto       $-1

   btfss      SSPCON2,ACKSTAT    ;checkear ack
   goto      okack

   bsf       SSPCON2,PEN      ;error ack. enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return               ;volver con flag= 0 error

okack   bcf      STATUS,RP0      ;banco 0
   btfss      PIR1,SSPIF      ;esperar finalizacion del noveno clock
   goto      $-1

   bcf      PIR1,SSPIF
   bsf      flag,0         ;volver con flag = 1 OK!
   return
   
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendack

   bsf      STATUS,RP0      ;banco 1
   bcf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_sendnack

   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,ACKDT
   bsf       SSPCON2,ACKEN
   bcf      STATUS,RP0      ;banco 0
   return

;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

i2c_stop
   bsf      STATUS,RP0      ;banco 1
   bsf       SSPCON2,PEN      ;enviar STOP
   bcf      STATUS,RP0      ;banco 0
   return


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;WriteI2CByte
;DIRH<1:0>                  ;paginas de la eeprom en las cuales grabar
;DIRL                     ;direccion baja de la posicion de eeprom en las cuales grabar
;DATASSP                  ;dato a grabar
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

WriteI2CByte

   call      i2c_start      ;enviar START, esperar a que se libere el BUS
   movlw      b'10100000'      ;"1010"= identificador EEPROM. "000" = numero EEPROM "0"= Write
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits de paginas admitidas para esta eeprom.
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura
   
   movf      DATASSP,W
   movwf      DATO         ;cargar en DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;ReadI2CByte
;DIRH<1:0>               ;paginas de la eeprom de las cuales leer
;DIRL                  ;direccion baja de la posicion de eeprom de las cuales leer

;devuelve:
;DATASSP                  ;dato leido
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ReadI2CByte
   
   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100000'      ;1010=identificador EEPROM 000= numero EEPROM 0=write
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   movf      DIRH,W
   andlw      b'01111111'      ;solo 7 bits admitidos para esta EEPROM
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return

   movf      DIRL,W
   movwf      DATO
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_restart      ;enviar RESSTART

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1=read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!


;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CurrentI2CRead

   call      i2c_start      ;enviar START, esperar a que se libere el BUS

   movlw      b'10100001'      ;1010=identificador EEPROM 000= numero EEPROM 1= read
   movwf      DATO         ;cargar byte en variable a enviar(DATO)
   call      i2c_write
   btfss      flag,OK
   return                  ;volver. error de escritura

   call      i2c_read
   call      i2c_sendnack
   call      i2c_stop
   return                  ;flag = 1 OK!
;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   END
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 22 de Diciembre de 2008, 05:47:03
Perdona pero es que no tenía el programa en casa.

Muy buen trabajo. Lo has probado si funciona?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 22 de Diciembre de 2008, 06:17:43
e he atrevido a realizar modificaciones sobre el programa de Brunof...

Hola!

Bueno, la subrutina i2c_init debería ser llamada sólo la primera vez. Volver a llamarla puede provocar efectos indeseados.

...a continuación escribe en memoria (se supone que en la siguiente posición) A0
y lo presenta en puerta B, temporiza otros 5s y finalmente lo borra. ¿Que os parece?.

Lamentablemente supones mal. Y con esto voy a responderte a ti y a pibe.

Estas memorias pueden ser leidas de 3 maneras: Random Read, Current Access Read y  Sequential Read. La Random Read implica que uno le pasa como parametros también la dirección que se desea leer, pudiendo elegir entre cualquiera presente en la memoria. Current Read implica que se leerá la posición de memoria a la cual apunte su puntero interno. ¿Que valor posee el puntero interno?

Luego de realizar una Random Read, el valor del puntero interno es el valor de la posición que se acaba de leer + 1. Es decir que el puntero se autoincrementa según la última posición a la cual se ha accedido.

Ejemplos:

Si realizo primero un Random Read de la posición 125 y luego realizo un Current Access Read, la memoria leerá el valor de la posición 126. Si realizo otro Current Access  Read, leerá la posición 127.

Sequential Read sirve para leer muchas posiciones de memoria CONSECUTIVAS. Podés leer toda la memoria si querés. La diferencia es que leer de esta manera es muchísimo más rápido que en los otros dos modos.

Para escribir, hay dos modos: Byte Write(el que usan en mi ejemplo) y Block Write(que creo que no he publicado el algoritmo).

El byte write que es el que se usa para escribir un byte en la RAM, siempre exige que se defina la posición a escribir. Por lo que es necesario que se le pase la posición a la cual se desea acceder. Todas las operaciones afectan al puntero interno que es el que indica cual es la posicion actual a leer/escribir.

Ejemplo:

Escribo posición 0. (Luego de eso, el puntero interno valdrá 1)
Leo posición 0. Debo hacerlo usando el Random Read indicandole que quiero leer la posición 0.(si usase en su lugar el Current Access Read o Block Read, el primer byte leido seria el de la posicion 1).

Escribo posición 1. (Luego de eso, el puntero interno valdrá 2)
Leo posición 1. Nuevamente debo hacerlo usando el Random Read indicandole que quiero leer la posición 1.(si usase en su lugar el Current Access Read o Block Read, el primer byte leido seria el de la posicion 2).

Si se fijan bien en el protocolo, el Random Read comienza exáctamente igual que un Byte Write. Esto es porque de esta manera se logra modificar el puntero interno. Luego en la lectura se interrumpe la escritura y se procede a leer.

Se entendió?
Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 22 de Diciembre de 2008, 07:12:29
Gracias Bruno por la aclaración.
Una pregunta: En el secuencial byte read, puedo leer toda la memoria con una sola instrucción mientras le sigo mandando reloj y CS? O sólo los primeros 64 bytes de la página?
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 22 de Diciembre de 2008, 15:33:43
Perdona pero es que no tenía el programa en casa.

Muy buen trabajo. Lo has probado si funciona?


En el Proteus funciona, aun así he seguido el consejo de Brunof de solo hacer una llamada  "call    i2c_init", que tambien he probado y funciona. Ahora solo queda asegurar que lo que se escribe y se lee es desde una posición conocida y esa información sale linea tras linea desde esa posición de memoria..............bufffffff, que entretenido es esto, por cierto la intrucción "goto    $-1" es salto incondicional a.......¿$-1?, que es...es que he pasado de un pic 16f84a a este otro pic y no estoy muy suelto. El código ahora queda así:



ORG     0X0000
            GOTO    INICIO

            ORG     0X0004
            return

            ORG     0X0020

INICIO      BANK0
            BSF     STATUS,RP0
            MOVLW   0x06          ;PINS DEL PUERTO A Y PUERTO C TODOS DIGITALES.
            MOVWF   ADCON1
            CLRW
            MOVWF   TRISA

            BANK0
            CLRF    PORTA
            BSF     STATUS,RP0
            MOVLW   0X00
            MOVWF   TRISB

            BANK0
            CLRF    PORTB
            BSF     STATUS,RP0
            MOVLW   B'00011000'
            MOVWF   TRISC
   
            BANK0
            MOVLW   B'00010000'
            MOVWF   PORTC
            BSF     STATUS,RP0
   

            call    i2c_init                  ;configurar y encender I2C
            clrf    DIRH                     ;cargar paginas de 24LC08B en las cuales escribir
            clrf    DIRL                     ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   0xAA
            movwf   DATASSP          ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA               ;dar 10ms a que termine la escritura

            clrf    DIRH                    ;cargar paginas de 24LC08B de las cuales leer
            clrf    DIRL                     ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB
            incf    DIRL,F

            call    Retardo_5s
            clrf    PORTB


           
            clrf    DIRH                      ;cargar paginas de 24LC08B en las cuales escribir
            clrf    DIRL                      ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   0xA0
            movwf   DATASSP           ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA                ;dar 10ms a que termine la escritura

            clrf    DIRH                     ;cargar paginas de 24LC08B de las cuales leer
            clrf    DIRL                      ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB

           
            call    Retardo_5s
            clrf    PORTB

            nop
            goto    $-1



Solo pongo la parte del programa sobre la que estoy trabajando porque supongo que el resto sufrira pocos cambios o ninguno (creo yo, a lo mejor me equivoco, je, je, je).
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 22 de Diciembre de 2008, 19:07:30
goto $-1 es volver a la instruccion anterior. Tambien puedes hacer -2 , -3, -4 etc
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 22 de Diciembre de 2008, 21:02:58
goto $-1 es volver a la instruccion anterior. Tambien puedes hacer -2 , -3, -4 etc


Gracias.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 22 de Diciembre de 2008, 22:38:29
Gracias Bruno por la aclaración.
Una pregunta: En el secuencial byte read, puedo leer toda la memoria con una sola instrucción mientras le sigo mandando reloj y CS? O sólo los primeros 64 bytes de la página?

Hola! No. Podés leer toda la memoria entera. Eso si, tene en cuenta que empezarás a leer desde la posición siguiente a la última que has leído. Es decir que primero deberías hacer un random access read a la posicion 0 por ejemplo, y dsps ya usar el secuential read y leer desde la 1 en adelante para asegurarte donde "estas parado".

antimason:

Tu programa escribe y lee siempre la posición 0. Si querés grabar la segunda vez en la posicion 1(que creo que esa era la idea), tenés que indicarlo en DIRH/DIRL antes de leer y grabar por segunda vez.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 25 de Diciembre de 2008, 21:59:37
¿Como se podría implementar el protocolo i2c por software para comunicar un pic16f84a con una memoria externa?.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 27 de Diciembre de 2008, 11:37:46
Estoy intentando escribir en dos posiciones consecutivas de memoria de la misma pagina el 1 y el 2 en binario y lo saco por leds, pues bien en la simulación sale el 1 se borra y acontinuación en vez del 2 se encienden todos los leds = 255 ¿que estoy haciendo mal?. Este es el código:



dato_1      call    i2c_init                 ;configurar y encender I2C
            clrf    DIRH                     ;cargar paginas de 24LC08B en las cuales escribir
            clrf    DIRL                     ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   b'00000001'              ;1 en código binario
            movwf   DATASSP                  ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA                   ;dar 10ms a que termine la escritura

            clrf    DIRH                     ;cargar paginas de 24LC08B de las cuales leer
            clrf    DIRL                     ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB
            incf    DIRL,F

            call    Retardo_5s
            clrf    PORTB


           
dato_2      clrf    DIRH                     ;cargar paginas de 24LC08B en las cuales escribir
            movlw   b'00000001'              ;Dirección 1 de página 0x00
            movwf   DIRL                     ;cargar direccion de 24LC08B en las cuales escribir     
            movlw   b'00000010'              ;2 en código binario
            movwf   DATASSP                  ;cargar dato a escribir en la 24LC08B
            call    WriteI2CByte

            call    DEMORA                   ;dar 10ms a que termine la escritura

            clrf    DIRH                     ;cargar paginas de 24LC08B de las cuales leer
            movlw   b'00000001'
            movwf   DIRL                     ;cargar direccion de 24LC08B de las cuales leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB

           
            call    Retardo_5s
            clrf    PORTB

            nop
            goto    $-1
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 27 de Diciembre de 2008, 22:35:50
Si no me equivoco, una vez has leido el puntero se incrementa automaticamente. Por eso , al hacer incf DIRL le estás diciendo que se salte una direccion de memoria , por lo tanto te lee FF que es el default que llevan grabadas las memorias.
Entonces, deberias leer el dato en 00h, no incrementes, vuelves a leer dato.
A ver si te sale.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 28 de Diciembre de 2008, 08:28:48
Si no me equivoco, una vez has leido el puntero se incrementa automaticamente. Por eso , al hacer incf DIRL le estás diciendo que se salte una direccion de memoria , por lo tanto te lee FF que es el default que llevan grabadas las memorias.
Entonces, deberias leer el dato en 00h, no incrementes, vuelves a leer dato.
A ver si te sale.


Gracias majo, lo haré.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 28 de Diciembre de 2008, 08:46:48
  Aquí está el código en el que le digo que el segundo dato lo lea en la dirección 0x00 (se supone que mas el puntero será 1), pues bien, al simularlo en el proteus presenta el 1 en binario y se apaga esta vez sin que se enciendan todos otra vez como antes ¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿??????????????????????¡QUIERO QUE SALGA EL 2!.....................DESESPERACIÓN, ¿SERÁ EL PROTEUS?.         




            call    i2c_init                ;configurar y encender I2C
            clrf    DIRH                  ;Pagina 0x00
            clrf    DIRL                   ;Dirección 0x00
            movlw   0x01               ;00000001
            movwf   DATASSP        ;cargar dato a escribir en la 24LC256
            call    WriteI2CByte
            call    DEMORA             ;dar 10ms a que termine la escritura
           
            clrf    DIRH                  ;Pagina 0x00 a leer
            clrf    DIRL                   ;Dirección 0x00 a leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB            ;Lo saca por puerta B

            call    Retardo_5s
            clrf    PORTB


            movlw   0x00
            movwf   DIRH              ;Pagina 0x00
            movlw   0x00
            movwf   DIRL              ;Dirección 0x00
            movlw   0x02              ;00000010
            movwf   DATASSP       ;cargar dato a escribir en la 24LC256
            call    WriteI2CByte
            call    DEMORA            ;dar 10ms a que termine la escritura
           
            clrf    DIRH                 ;Pagina 0x00 a leer
            clrf    DIRL                  ;Dirección 0x00 a leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB           ;Lo saca por puerta B

            call    Retardo_5s
            clrf    PORTB

            nop
            goto    $-1                 ;vuelve a línea anterior (nop)
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: pibe en 28 de Diciembre de 2008, 16:51:01
 
Aqui grabas el primer byte (1) en la posicion 00 00 h

            call    i2c_init                ;configurar y encender I2C
            clrf    DIRH                  ;Pagina 0x00
            clrf    DIRL                   ;Dirección 0x00
            movlw   0x01               ;00000001
            movwf   DATASSP        ;cargar dato a escribir en la 24LC256
            call    WriteI2CByte
            call    DEMORA             ;dar 10ms a que termine la escritura
   
Y aquí lo lees
        
            clrf    DIRH                  ;Pagina 0x00 a leer
            clrf    DIRL                   ;Dirección 0x00 a leer
            call    ReadI2CByte
            movf    DATO,w
            movwf   PORTB            ;Lo saca por puerta B
            call    Retardo_5s
            clrf    PORTB

AQUI SOBREESCRIBES en la misma dirección 00 00h pero con dato (2)

            movlw   0x00
            movwf   DIRH              ;Pagina 0x00
            movlw   0x00
            movwf   DIRL              ;Dirección 0x00
            movlw   0x02              ;00000010
            movwf   DATASSP       ;cargar dato a escribir en la 24LC256
            call    WriteI2CByte
            call    DEMORA            ;dar 10ms a que termine la escritura
   
Y aqui lo lees
        
            clrf    DIRH                 ;Pagina 0x00 a leer
            clrf    DIRL                  ;Dirección 0x00 a leer
            call    ReadI2CByte

            movf    DATO,w
            movwf   PORTB           ;Lo saca por puerta B

            call    Retardo_5s
            clrf    PORTB

            nop
            goto    $-1                 ;vuelve a línea anterior (nop)

Yo es que si lees un post anterior mío, he desistido con el I2c porque no hubo manera que me funcionara. Me he volcado por la SPI que no tuve problemas.
Supongo que las maneras de manejar los datos y direcciones serán los mismos.
Ahora, lo que tendrías que hacer es :
GRABAR un dato en dirección 00 00
GRABAR un dato en dirección 00 01

Luego lees el dato en dirección 00 00 y lo muestras, luego lees el dato en dirección 00 01 y lo muestras.
Creo que incluso puedes leer ambos datos consecutivos sin dejar de enviarle reloj : Lees el dato en dirección 00 00 y la dirección se incrementa automáticamente y lees el dato 2 sin cortar el reloj, inmediatamente después de leer el dato 1.

O sea:
Grabas ambos datos en distintas direcciones.
Envias comando lectura
dirección 00 00
Lees byte 1
guardar en variable 1
Lees byte 2
guardar en variable 2

Mostrar variable 1
pausa
Mostrar variable 2


El truco aqui es que guardes en una variable cada byte leído, porque no puedes cortar el reloj para mostrar los datos.

Prueba y me cuentas


Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 28 de Diciembre de 2008, 21:37:38



Pibe te he hecho caso en lo de escribir los dos datos consecutivamente en memoria, pero no en lo de usar variables pues debo declararlas y ocupar memoria de programa, imagínate miles de datos en memoria con miles de variables declaradas (a lo mejor he dicho una burrada pero creo que es así), posteriormente he sacado los datos uno tras otro, pero al sacar el segundo dato se me ha ocurrido poner otra vez el "call    i2c_init", y mira por donde ahora si me funciona, (¿que opinará Brunof?). De momento esto ya funciona, pero seguiré buscando otra estructura de programa que funcione, aquí el código pibe:                 


                 






escribo_dato1               call    i2c_init                  ;configurar y encender I2C
                                   clrf    DIRH                     ;Pagina 0x00
                                   clrf    DIRL                      ;Dirección 0x00
                                   movlw   0x01                  ;00000001
                                   movwf   DATASSP           ;cargar dato a escribir en la 24LC256
                                   call    WriteI2CByte
                                   call    DEMORA                ;dar 10ms a que termine la escritura
   
         


escribo_dato2                movlw   0x00
                                    movwf   DIRH                 ;Pagina 0x00
                                    movlw   0x01
                                    movwf   DIRL                  ;Dirección 0x01
                                    movlw   0x02                  ;00000010
                                    movwf   DATASSP           ;cargar dato a escribir en la 24LC256
                                    call    WriteI2CByte
                                    call    DEMORA                ;dar 10ms a que termine la escritura
   
         
leo_primer_dato            clrf    DIRH                      ;Pagina 0x00 a leer
                                   clrf    DIRL                       ;Dirección 0x00 a leer
                                   call    ReadI2CByte
             
                                   movf    DATO,w
                                   movwf   PORTB                 ;Lo saca por puerta B

                                   call    Retardo_5s
                                   clrf    PORTB
                                   call    Retardo_5s
         

leo_segundo_dato         call    i2c_init                     ;configurar y encender I2C
                                   clrf    DIRH                        ;Pagina 0X00 a leer
                                   movlw   0x01
                                   movwf   DIRL                    ;Direccion 0X01 a leer
                                   clrw
                                   call    ReadI2CByte
             
                                   movf    DATO,w
                                   movwf   PORTB                 ;Lo saca por puerta B

                                   call    Retardo_5s
                                   clrf    PORTB

                                   nop
                                   goto    $-1                        ;vuelve a línea anterior (nop)

Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 30 de Diciembre de 2008, 03:03:02
Hola. Mira, yo creo que debe ser un error del Proteus. Al menos esa es mi opinión porque estás haciendo los pasos correctamente. Tal vez sea hora de probarlo en la realidad si tienes la posibilidad.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 30 de Diciembre de 2008, 10:33:55
Hola. Mira, yo creo que debe ser un error del Proteus. Al menos esa es mi opinión porque estás haciendo los pasos correctamente. Tal vez sea hora de probarlo en la realidad si tienes la posibilidad.

Saludos.

Gracias, ¿pero te refieres al último código que he puesto o al anterior?.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 30 de Diciembre de 2008, 14:47:05
Sin el segundo i2c_init debería funcionar también asi que creo que me podría referir a cualquiera de ambos.

Saludos
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: antimason en 31 de Diciembre de 2008, 09:54:42
He creado un archivo .bin para simularlo en el proteus. El siguiente código solo pretende leer lo que hay en memoria en las páginas y direcciones asignadas,
supongo que funcionaria en la realidad (grabando previamente en la eeprom externa claro), pero con el proteus que tengo no hay manera.






eo_primer_dato          call    i2c_init                   ;configurar y encender I2C
                                 clrf    DIRH                      ;Pagina 0x00 a leer
                                 clrf    DIRL                       ;Dirección 0x00 a leer
                                 call    ReadI2CByte
             
                                 movf    DATO,w
                                 movwf   PORTB                 ;Lo saca por puerta B

                                 call    Retardo_5s
                                 clrf    PORTB
                                 call    Retardo_5s
         

leo_segundo_dato       clrf     DIRH                  ;Pagina 0X00 a leer
                                 movlw   0x01
                                 movwf   DIRL                  ;Direccion 0X01 a leer
                                 clrw
                                 call    ReadI2CByte
             
                                 movf    DATO,w
                                 movwf   PORTB                 ;Lo saca por puerta B

                                 call    Retardo_5s
                                 clrf    PORTB

                                nop
                                goto    $-1                   ;vuelve a línea anterior (nop)
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: alogic.on en 17 de Enero de 2009, 19:45:27
hola, me he tomado la lbertad de intentar usar el ejemplo de Bruno para utilizar el bus i2c con una memoria 24lc256 que son las que tengo a mano. La intencion es copiar 256bytes de esta, guardarlos en la eeprom y viceversa, para ello estoy preparando esta macro de momento la de lectura

Código: ASM
  1. CONFIG_I2C              MACRO
  2. ;RC4=SDA
  3. ;RC3=SCL                Y LOS DOS COMO ENTRADA??
  4.                 movlw   B'00011000'
  5.                 banksel TRISC         ;banco 1
  6.                 iorwf   TRISC,F
  7.                 BANKSEL SSPSTAT                        
  8.                 MOVLW   B'00000000'                     ;7----> SMP     0=VELOCIDAD 400KHZ
  9.                                                                         ;6----> CKE     0=EL DATO SE TRANSMITE EN FLANCO DE SUBIDA
  10.                                                                         ;5----> D/A     1=INDICA QUE EL ULTIMO DATO REC/TRANSMITIDO ERA UN DATO
  11.                                                                         ;                               0=INDICA QUE ERA UNA DIRECCION
  12.                                                                         ;4----> P       1=INDICA QUE HA SIDO DETECTADA UNA CONDICION DE STOP
  13.                                                                         ;                               0=NO SE HA DETECTADO STOP
  14.                                                                         ;3----> S       1=SE HA DETECTADO UNA CONDICION DE START
  15.                                                                         ;                               0=NO SE HA DETECTADO UNA CONDICION DE START
  16.                                                                         ;2----> R_W     1=TRANSMISION EN PROGRESO
  17.                                                                         ;                               0=TRANSMISION FINALIZADA
  18.                                                                         ;1----> UA      SOLO EN I2C DIRECCION 10BITS
  19.                                                                         ;0----> BF              1=LA TRANSMISION ESTA EN PROGRESO SSPBUF LLENO
  20.                                                                         ;                               0=LA TRANSMISION HA FINALIZADO SSPBUF VACIO
  21.                 MOVWF   SSPSTAT
  22.         ;-------------------------------
  23.                 BANKSEL SSPCON
  24.                 MOVLW   B'00101000'                     ;7----> WCOL    0=NO HAY COLISION
  25.                                                                         ;                               1=SE HA ESCRITO SSPBUF MIENTRAS SE HACIA UNA TRANSMISION       
  26.                                                                         ;6----> SSPOV   0=NO HAY OVERFLOW
  27.                                                                         ;                               1=UN BYTE SE HA RECIBIDO SIN LEER EL ANTERIOR   dEBE SER BORRADO POR SOFT                      
  28.                                                                         ;5----> SSPEN   1=HABILITA EL I2C Y LOS PINES SDA SCL
  29.                                                                         ;4----> CKP     0=MANTIENE EL RELOJ EN ESTADO BAJO
  30.                                                                         ;                               1=HABILITA EL RELOJ
  31.                                                                         ;3-0--> SSPM3-0 1000=MAESTRO reloj=f_osc/4*(sspadd+1)
  32.                 MOVWF   SSPCON
  33.         ;-------------------------------
  34.                 BANKSEL SSPCON2
  35.                 MOVLW   B'00010000'
  36.                                                                         ;7----> GCEN    SOLO EN ESCLAVO
  37.                                                                         ;6----> ACKSTAT EN MODO MASTER TRANSMISION, EL ESCLAVO ENVIA EL ACK CUANDO HA RECIBIDO EL DATO
  38.                                                                         ;                               1=NO RECIBIDO ACK DEL ESCLAVO
  39.                                                                         ;                               0=ACK RECIBIDO DEL ESCLAVO
  40.                                                                         ;5----> ACKDT   EN MODO MASTER RECEPCION, EL MASTER ENVIA UN ACK CUANDO HA TERMINADO DE RECIBIR
  41.                                                                         ;                               1=NO ACK
  42.                                                                         ;                               0=SI ACK
  43.                                                                         ;4----> ACKEN   EN MODO MASTER RECEPCION
  44.                                                                         ;                               1= INICIA LA SECUENCIADE SDA SCL, Y TRANMITE EL ACKDT BORRADO POR HARDWARE
  45.                                                                         ;                               0=DESHABILITADO
  46.                                                                         ;3----> RCEN    EN MASTER I2C
  47.                                                                         ;                               1= RECEPCION HABILITADA
  48.                                                                         ;                               0= RECEPCION DESHABILITADA
  49.                                                                         ;2----> PEN             SOLO EN I2C MASTER
  50.                                                                         ;                               1=INICIA UNA SECUENCIA DE STOP BORRADO POR HARD
  51.                                                                         ;                               0=DESHABILITADA
  52.                                                                         ;1----> RSEN    SOLO EN I2C MASTER START REPETIDO
  53.                                                                         ;                               1=INICIA CONDICION DE SR BORRADO POR HARD
  54.                                                                         ;                               0=DESHABILITADO
  55.                                                                         ;0----> SEN             SOLO EN I2C MASTER
  56.                                                                         ;                               1=INICIA LA CONDICION START EN SCL SDA BORRADO POR HARD
  57.                                                                         ;                               0=DESHABILITADO
  58.  
  59.                 MOVWF   SSPCON2
  60.                 banksel SSPADD
  61.                 movlw   b'00001011'             ;.11 para 400khz @ 20 mhz
  62.                 movwf   SSPADD                  ;400 khz @ 20 mhz
  63.                 ENDM
  64. I2C_BUS                 MACRO
  65.  
  66.                 CALL    RESET_DIRECCION ;APUNTA AL PAD 00, HABRA QUE BUSCAR LA FORMA DE SELECIONAR ENTRE VARIOS CADA 255 BYTES
  67. I2C_MEMO_READ
  68.                 BANKSEL SSPCON
  69.                 BSF             SSPCON, CKP     ;PRIMERO INICIA EL RELOJ
  70.                 CALL    IIC_START               ;ENVIA LA CONDICION DE START
  71.                 MOVLW   B'10100001'             ;CONTROL BYTE--> |STARTBIT|1|0|1|0|A2|A1|A0|RW|ACK
  72.                 CALL    IIC_ENVIA               ;Y SE LO ENVIA A LA EEPROM
  73.                 CALL    IIC_ADRESS              ;MANDA DIRH,ESPERA ACK,MANDA DIRL, ESPERA ACK, RETURN
  74. SIGUE_READ
  75.                 BANKSEL SSPCON2
  76.                 BSF     SSPCON2,RCEN    ;activar modo lectura
  77.                 BTFSC   SSPCON2,RCEN    ;termino la recepcion? 
  78.                 GOTO    $-1
  79.                 BTFSS   SSPSTAT,BF      ;dato disponible en SSPBUF para ser leido?
  80.             GOTO    $-1                 ;no, esperar
  81.                 BANKSEL DIRL
  82.                 INCFSZ  DIRL,F                  ;UNA VEZ LLEGA A 255 SALE DE LA RUTINA
  83.                 GOTO    GUARDA_PADS
  84. IIC_STOP       
  85.                 BANKSEL SSPCON2
  86.                 BSF             SSPCON2,PEN
  87.                 BTFSC   SSPCON2,PEN
  88.                 GOTO    $-1
  89.                 BANKSEL SSPCON
  90.                 BCF             SSPCON, CKP     ;APAGA EL RELOJ
  91.                 RETURN                                 
  92.  
  93. GUARDA_PADS
  94.                 BANKSEL SSPBUF
  95.                 MOVF    SSPBUF,W
  96.                 BANKSEL REG_MUESTRA
  97.                 MOVWF   REG_MUESTRA
  98.                 CALL    ESCRITURA_EEPROM_IIC    ;Y GUARDA EL DATO EN LA EEPROM
  99.                 GOTO    SIGUE_READ
  100.  
  101. IIC_IDLE
  102.                 BANKSEL SSPSTAT
  103.                 BTFSC   SSPSTAT,R_W
  104.                 GOTO    $-1
  105.  ;  movf       SSPCON2,w ; POR QUE SE HACE ESTO
  106.  ;  andlw       0x1F
  107.  ;  btfss       STATUS,Z
  108.  ;  goto       $-3
  109.  
  110.                 RETURN
  111.  
  112. ESCRITURA_EEPROM_IIC
  113.                 BANKSEL DIRL
  114.                 MOVF    DIRL,W                  ;Data Memory
  115.                 BANKSEL EEADR
  116.                 MOVWF   EEADR                   ;Address to write
  117.                 CLRW
  118.                 ADDWF   EEADR,F                 ;DE ESTA FORMA SE COMIENZA A CONTAR DESDE EL REGISTRO DE POTES
  119.                 GOTO    CONTINUA_ESCRITURA     
  120.                
  121. IIC_ADRESS
  122.                 BANKSEL DIRH
  123.                 MOVF    DIRH,W
  124.                 CALL    IIC_ENVIA
  125.                 BANKSEL DIRL
  126.                 MOVF    DIRL,W
  127.                 CALL    IIC_ENVIA
  128.                 RETURN
  129. IIC_ENVIA
  130.                 CALL    IIC_IDLE                ;ESERA A QUE TERMINE LA ULTIMA TRANSMISION
  131.                 BANKSEL SSPBUF                 
  132.                 MOVWF   SSPBUF
  133.                 BANKSEL SSPCON2
  134.                 RETURN
  135.  
  136. RESET_DIRECCION
  137.                 BANKSEL DIRH                    ;CARGAMOS EN LOS REGISTROS DE DIRECCION A LA QUE QUEREMOS ACCEDER
  138.                 CLRF    DIRH                    ;DE MOMENTO DIRECCION 00
  139.                 CLRF    DIRL
  140.                 RETURN         
  141.  
  142. IIC_START
  143.                 CALL    IIC_IDLE
  144.                 BANKSEL SSPCON2
  145.                 BSF             SSPCON2, SEN    ;INICIA START
  146.                 BTFSC   SSPCON2,SEN
  147.                 GOTO    $-1
  148.                 BANKSEL PIR1
  149.                 BTFSS   PIR1,SSPIF
  150.                 GOTO    $-1
  151.                 BCF             PIR1,SSPIF
  152.                 RETURN
  153.                 ENDM
  154.         ;------------------------------------------

pero hay una cosa que no entiendo de la rutina i2c_idle
Código: ASM
  1. i2c_idle
  2.  
  3.    bsf      STATUS,RP0      ;banco 1
  4.    btfsc       SSPSTAT,R_W
  5.    goto       $-1
  6.  
  7.    movf       SSPCON2,w
  8.    andlw       0x1F
  9.    btfss       STATUS,Z
  10.    goto       $-3
  11.  
  12.    bcf      STATUS,RP0      ;banco 0
  13.    return
para que se suma SSPCON2+0x1F en W y testeas Z ?? perdona pero no me entero de esto. para conocer si el bufer esta lleno, no basta testear el bit R_W

y otra dudilla, he visto en el ejemplo que poneis SDA y SCL como entradas, es así?, los configura el modulo segun se este recibiendo o enviando??

un saludo y gracias
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 23 de Enero de 2009, 15:16:21
Hola. No es una suma..es una AND. No se si te referías a eso. Si miras en el datasheet, verás que para saber si el bus está en estado IDLE todos los bits: 0,1,2,3 y 4 del registro SSPCON2 deben estar en bajo. Por eso se hace una AND que filtra los bits 7,6 y 5.

Cita del datasheet:

Citar
Note: For bits ACKEN, RCEN, PEN, RSEN, SEN: If the I2C module is not in the IDLE mode, this bit may not be set (no spooling), and the SSPBUF may not be written (or writes to the SSPBUF are disabled).

Con respecto a la configuración E/S de los pines, no te preocupes. El uC los administra y configura según corresponda.

Saludos.
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: alogic.on en 24 de Enero de 2009, 07:10:31
 :mrgreen: :mrgreen: hola y gracias Bruno :-/ :-/
creo que ya ta, la rutina que vuelca 255bytes en la eeprom. ahora solo me falta al verres, copiar el pad en la eeprom y la forma de seleccionar entre varias posiciones, donde guardar diferentes configuraciones de los potes y botones. a seguir currando¡¡

Código: ASM
  1. CONFIG_IIC              MACRO
  2.                 BANKSEL SSPCON
  3.                 MOVLW   B'00101000'                     ;7----> WCOL    0=NO HAY COLISION
  4.                                                                         ;                               1=SE HA ESCRITO SSPBUF MIENTRAS SE HACIA UNA TRANSMISION       
  5.                                                                         ;6----> SSPOV   0=NO HAY OVERFLOW
  6.                                                                         ;                               1=UN BYTE SE HA RECIBIDO SIN LEER EL ANTERIOR   dEBE SER BORRADO POR SOFT                      
  7.                                                                         ;5----> SSPEN   1=HABILITA EL I2C Y LOS PINES SDA SCL
  8.                                                                         ;4----> CKP     0=MANTIENE EL RELOJ EN ESTADO BAJO
  9.                                                                         ;                               1=HABILITA EL RELOJ
  10.                                                                         ;3-0--> SSPM3-0 1000=MAESTRO reloj=f_osc/4*(sspadd+1)
  11.                 banksel SSPADD
  12.                 movlw   b'00001011'             ;.11 para 400khz @ 20 mhz
  13.                 movwf   SSPADD                  ;400 khz @ 20 mhz
  14.                 ENDM
Código: ASM
  1. IIC_BUS                 MACRO
  2. BULK_PATCH_IIC
  3.                 CALL    DEMORA_20MS
  4.                 CALL    RECARGA2
  5.                 BTFSC   DATO
  6.                 RETURN
  7.                 bcf             INTCON,GIE              ;DESACTIVAMOS LAS INTERRUPCIONES
  8.                 CALL    RESET_DIRECCION ;APUNTA AL PAD 00, HABRA QUE BUSCAR LA FORMA DE SELECIONAR ENTRE VARIOS CADA 255 BYTES
  9. IIC_MEMO_READ
  10.                 BANKSEL SSPCON
  11.                 CALL    IIC_START               ;ENVIA LA CONDICION DE START
  12.                 MOVLW   B'10100001'             ;CONTROL BYTE--> |STARTBIT|1|0|1|0|A2|A1|A0|1 AUNQUE EN EL MANUAL ESTA A 0 PARA R/W |ACK<---este lo devuelve el esclavo|
  13.                 CALL    IIC_ENVIA               ;Y SE LO ENVIA A LA EEPROM                                                                     
  14.                 CALL    IIC_ADRESS              ;MANDA DIRH,ESPERA ACK,MANDA DIRL, ESPERA ACK = |0|0|0|0|0|0|0|0|ACK|0|0|0|0|0|0|0|0|ACK|_DATO_8BITS_|ACK|_DATO_8BITS_|ACK|
  15. SIGUE_READ
  16.                 BANKSEL SSPCON
  17.                 BSF             SSPCON, CKP             ;INICIA EL RELOJ
  18.                 BANKSEL SSPCON2
  19.                 BSF     SSPCON2,RCEN    ;activa la recepcion
  20.                 BTFSC   SSPCON2,RCEN    ;ESPERA A TERMINAR LA RECEPCION
  21.                 GOTO    $-1
  22.                 BTFSS   SSPSTAT,BF      ;dato disponible en SSPBUF para ser leido?
  23.             GOTO    $-1                 ;no, esperar
  24.                 CALL    IIC_SEND_ACK    ;DEVUELVE EL ACK PARA QUE SEA VALIDO
  25.                 BANKSEL SSPCON
  26.                 BCF             SSPCON, CKP             ;Y APAGA EL RELOJ
  27.                 BANKSEL DIRL
  28.                 INCFSZ  DIRL,F                  ;UNA VEZ LLEGA DE 255-0 SALE DE LA RUTINA
  29.                 GOTO    GUARDA_PADS
  30.                 CALL    IIC_STOP
  31.                 BSF             INTCON,GIE
  32.  
  33. IIC_STOP       
  34.                 BANKSEL SSPCON2
  35.                 BSF             SSPCON, CKP             ;INICIA EL RELOJ
  36.                 BSF             SSPCON2,PEN             ;INICIA EL ESTADO STOP EN SDA SCL
  37.                 BTFSC   SSPCON2,PEN
  38.                 GOTO    $-1                             ;ESPERA A QUE TERMINE
  39.                 BANKSEL SSPCON
  40.                 BCF             SSPCON, CKP             ;Y APAGA EL RELOJ
  41.                 RETURN
  42.                                        
  43. IIC_SEND_NACK
  44.                 BANKSEL SSPCON2
  45.                 BSF     SSPCON2,ACKDT   ;A UNO PARA NO-ACK
  46.                 BSF     SSPCON2,ACKEN   ;CON ESTO ACTIVAMOS LA SECUENCIA DE ACKDT(ANTERIOR)
  47.                 BTFSC   SSPCON2,ACKEN
  48.                 GOTO    $-1                             ;Y ESPERAMOS A QUE LA TERMINE
  49.                 RETURN                                  ;VUELVE
  50.  
  51. IIC_SEND_ACK
  52.                 BANKSEL SSPCON2
  53.                 BCF     SSPCON2,ACKDT   ;A CERO PARA ACK
  54.                 BSF     SSPCON2,ACKEN   ;CON ESTO ACTIVAMOS LA SECUENCIA DE ACKDT(ANTERIOR)
  55.                 BTFSC   SSPCON2,ACKEN
  56.                 GOTO    $-1                             ;Y ESPERAMOS A QUE LA TERMINE
  57.                 RETURN                                  ;VUELVE
  58.  
  59. GUARDA_PADS
  60.                 BANKSEL SSPBUF
  61.                 MOVF    SSPBUF,W
  62.                 BANKSEL REG_MUESTRA
  63.                 MOVWF   REG_MUESTRA
  64.                 CALL    ESCRITURA_EEPROM_IIC    ;Y GUARDA EL DATO EN LA EEPROM
  65.                 GOTO    SIGUE_READ
  66.  
  67. IIC_IDLE
  68.                 BANKSEL SSPSTAT
  69.                 BTFSC   SSPSTAT,R_W
  70.                 GOTO    $-1
  71.                 movf    SSPCON2,w ; POR QUE SE HACE ESTO SI POR UN CASUAL LA PRIMERA VEZ NO SE PONE A UNO Z A LA SIGUIENTE TAMPOCO
  72.                 andlw   0x1F
  73.                 btfss   STATUS,Z
  74.                 goto    $-3
  75.  
  76.                 RETURN
  77.  
  78. ESCRITURA_EEPROM_IIC
  79.                 BANKSEL DIRL
  80.                 MOVF    DIRL,W                  ;Data Memory
  81.                 BANKSEL EEADR
  82.                 MOVWF   EEADR                   ;Address to write
  83.                 CLRW
  84.                 ADDWF   EEADR,F                 ;DE ESTA FORMA SE COMIENZA A CONTAR DESDE EL REGISTRO DE POTES
  85.                 GOTO    CONTINUA_ESCRITURA     
  86.                
  87. IIC_ADRESS
  88.                 BANKSEL DIRH
  89.         ;       MOVF    DIRH,W
  90.                 clrw
  91.                 CALL    IIC_ENVIA
  92.                 BANKSEL DIRL
  93.         ;       MOVF    DIRL,W
  94.                 clrw
  95.                 CALL    IIC_ENVIA
  96.                 RETURN
  97. IIC_ENVIA
  98.                 CALL    IIC_IDLE                ;ESERA A QUE TERMINE LA ULTIMA TRANSMISION
  99.                 BANKSEL SSPBUF                 
  100.                 MOVWF   SSPBUF                  ;CARGA EL DATO EN SSPBUFF
  101.                 BSF             SSPCON, CKP             ;NO HABRIA QUE ACTIVAR AQUÍ EL RELOJ PARA QUE EMPIEZE A ENVIAR
  102.                 BANKSEL SSPSTAT                
  103.                 btfsc   SSPSTAT,R_W      ;esperar a que termine el envio
  104.                 goto    $-1
  105.  
  106.                 btfss   SSPCON2,ACKSTAT   ;checkear ack
  107.                 GOTO    NO_ACK 
  108. SALE_NCK
  109.                 BANKSEL PIR1
  110.                 btfss   PIR1,SSPIF      ;esperar finalizacion del noveno clock
  111.                 goto    $-1
  112.  
  113.                 bcf      PIR1,SSPIF             ;BAJA LA BANDERA
  114.                 BCF             SSPCON, CKP             ;Y TRAS TERMINAR DE RRECONOCER EL ACK APAGAR EL RELOJ
  115.                 RETURN
  116. NO_ACK
  117.                 BANKSEL DIRL
  118.                 MOVLW   .255
  119.                 MOVWF   DIRL
  120.                 goto    SALE_NCK                                ;ESTO OBLIGA A SALIR DE LA RUTINA AL SOBREPASAR LOS 255
  121. RESET_DIRECCION
  122.                 BANKSEL DIRH                    ;CARGAMOS EN LOS REGISTROS DE DIRECCION A LA QUE QUEREMOS ACCEDER
  123.                 CLRF    DIRH                    ;DE MOMENTO DIRECCION 00
  124.                 CLRF    DIRL
  125.                 RETURN         
  126.  
  127. IIC_START
  128.                 CALL    IIC_IDLE
  129.                 BANKSEL SSPCON2
  130.                 BSF             SSPCON, CKP             ;PRIMERO INICIA EL RELOJ
  131.                 BSF             SSPCON2, SEN    ;INICIA START
  132.                 BTFSC   SSPCON2,SEN             ;
  133.                 GOTO    $-1                             ;ESPERA A QUE TERMINE
  134.                 BANKSEL PIR1
  135.                 BTFSS   PIR1,SSPIF              ;ESPERA A LA BANDERA POR INTRRUPCION
  136.                 GOTO    $-1
  137.                 BCF             PIR1,SSPIF              ;Y LA BAJA
  138.                 BCF             SSPCON, CKP             ;Y APAGA EL RELOJ
  139.                 RETURN
  140.                 ENDM
  141.         ;------------------------------------------

un saludo y gracias
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: ivanovic en 17 de Mayo de 2013, 10:46:33
Hey que tal, muy útil la explicación de tu programa!! Una enorme pregunta, ¿tendrás la simulación de esto en proteus? Gracias Un saludo!
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: BrunoF en 23 de Mayo de 2013, 01:50:50
Hola!

Lamentablemente no tengo la simulación, pero no debería ser dificil de hacerla!

Saludos!
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: inventor1967 en 09 de Julio de 2013, 03:17:37
Hola Cordial Saludo soy nuevo en el foro
Estoy tratando de controlar una 24c512 con un 18f4550 y no ha sido posible alguien lo ha logrado?
por favor si alguien logra encontrar donde estoy fallando le Agradeceré, adjunto la parte del código.
Código: [Seleccionar]
LEER MOVLW 0X01
CALL COMLC ;borra la patalla lcd
CALL INIVAR ;iniciar las varables
CALL INI2C ;para inicializar el puerto i2c
NLEER BCF PIR1,3
BSF SSPCON2,SEN ;CONDICION DE ARANQUE

BTFSS PIR1,SSPIF
GOTO NLEER


BCF PIR1,SSPIF
MOVLW 0XA1 ;Direccion de la memoria con la para leer
MOVWF DATOF,1 ;regeistro para almacenar lo que se enviara
CALL TRANSMT



MOVF DIREC2,W
MOVWF DATOF
CALL TRANSMT

MOVF UG,W
MOVWF DATOF
CALL TRANSMT


BSF SSPCON2,RCEN ;activa recepcion
YLLE BTFSC SSPCON2,RCEN
GOTO YLLE
MOVF SSPBUF,W
CALL ENCAJA ;llama subrrutina para visualizar en la lcd



MOVLW 0X35
CPFSEQ UG
GOTO NLEERE


YP NOP
GOTO YP
NLEERE INCF UG,1
MOVF UG,W
CALL CARLC
GOTO NLEER
;********************************************************
; *
;RUTINA PARA ENVIAR DIRECCIONES Y DATOS A LA MEM *
; *
;********************************************************
TRANSMT

MOVF DATOF,W
MOVWF SSPBUF
FTRA BTFSS PIR1,SSPIF
GOTO FTRA



SREC BTFSC SSPCON2,ACKSTAT
GOTO SREC

RETURN

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
; rutina para inicializar variables
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
INIVAR
MOVLW 0X00
MOVWF DIREC2
MOVLW 0X30
CLRF UG
MOVWF DIREC1,1
MOVLW 0X47
MOVWF M


;>>>>>>>>>>>>>>>>>>>>>>>
;
; rutina para inicializar el puerto
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

INI2C CLRF LATB
CLRF TRISB

CLRF SSPSTAT
BSF SSPSTAT,SMP
BSF SSPCON1,SSPM3
BSF SSPCON1,SSPEN

MOVLW 0X31

MOVWF SSPADD

MOVLW 0X28
MOVWF SSPCON1

CLRF SSPCON2

BSF TRISB,0
BSF TRISB,1
RETURN

;<><><<><>><>>>>>>>>>>><<<<<><<<>
Título: Re: Ejemplo de utilizacion del Modulo I2C del 16F877a
Publicado por: lucas0214 en 30 de Octubre de 2013, 21:18:01
Buen día, como andan veo que hace tiempo que no se sigue esta conversación pero estoy renegando con una 24c16 que no puedo grabar bien, y mi primer duda con respecto al programa subido es porque utilizan DIRH y DIRL para direccionar la memoria, que según lo leido en la hoja de datos solo se envia una byte para ubicarse en la posición de la memoria a leer/escribir

Desde ya muchas gracias por el aporte de siempre!!!!