TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: XTOPIC en 18 de Noviembre de 2009, 10:55:54

Título: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 18 de Noviembre de 2009, 10:55:54
Alguien tiene por favor un assembler para que un PIC16F73 trabaje como esclavo en una comunicación I2C?
Es muy simple lo que necesito, tengo que mandar 2 bytes desdde un PIC 16F73 Maestro (ese programa ya lo hice y funciona bien), hacia varios PIC16F73 esclavos (por ahora pruebo con uno solo pero no consigo hacerlo funcionar).
Ya me leí todo: AN734 (que tiene errores), y he buscado por todas partes pero no encontré nada que funcione y no logro que el PIC esclavo reconozca ni siquiera el bit de Start del Maestro.
El PIC16F73 no tiene módulo MSSP sino que tiene un módulo SSP para I2C pero debería funcionar igual para una recepción de 7 bits de address.
Nada ..... no lo consigo y se me están quemando todos los fusibles de la cabeza  :shock:
Agradezco cualquier ayuda al respecto .... es muy dificil trabajar solo en assembler !

Muchas Gracias
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 18 de Noviembre de 2009, 11:00:53
Muéstranos el código del esclavo haber si podemos detectar algún error.


Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 18 de Noviembre de 2009, 16:48:06
Gracias Suki por tu tiempo,

Ahi van IC2Master es el assembler del MAster e IC2Slave
IC2Slave
;   I2C_SLAVE.ASM ----------------------------------------------------

  list      p=16F73           
 #include <p16F73.inc>       
   
 __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
      ERRORLEVEL -302
      ERRORLEVEL -305

  #DEFINE NODE_ADDR   0x22    ; I2C address of this node
   
reset    ORG     0x000                   ; processor reset vector
         goto    inicio                  ; go to beginning of program
         ORG     0x004                   ; interrupt vector
         goto    ISR                     ;
inicio
        call    Setup
       
Main    NOP
        goto    Main       ; Loop forever.       

; ------------------------------------SUBRUTINAS ------------------------------------------
Setup   ; Initializa variables y registros
   
    banksel PORTC       
    clrf    PIR1
    clrf    SSPBUF
    clrf    PORTB
    movlw   NODE_ADDR
    banksel SSPADD
    movwf   SSPADD
    clrf    SSPSTAT
    clrf    TRISB
    MOVLW   0xFF
    movwf   TRISC                  ; ALL INPUTS (RC3 & RC4 MUST BE INPUTS)
    bsf     PIE1,SSPIE
    bsf     INTCON,PEIE            ; Enable all peripheral interrupts
    bsf     INTCON,GIE             ; Enable global interrupts
    bcf     STATUS,RP0
    movlw   0x36                   ; Setup SSP module for 7-bit, Enable Clock Start Stop Int. Enabled
    movwf   SSPCON                ; address, slave mode
    return

; ******************* INTERRUPT **********************************************
ISR
   
    banksel PIR1
    btfss   PIR1,SSPIF  ; Is this an I2C interrupt?
    goto    salida           ; No, just trap here.
   
    call    I2C_Handler  ; Yes, service I2C interrupt.
    bcf     PIR1,SSPIF
salida
    retfie              ; Return from interrupt.
I2C_Handler 
    banksel SSPSTAT
    movf    SSPSTAT,W
    banksel PORTB
    MOVWF   PORTB
   
    return

 ; INCLUDES  *****************************************************************
    ; #include  <I2C_SLAVE.inc>      ; subrutinas de manejo de BUS I2C
    #include  <RETARDOS.inc>      ; subrutinas de manejo de BUS I2C
    end

IC2Master *********************************************************************
    list      p=16F73            ; list directive to define processor
   #include <p16F73.inc>        ; processor specific variable definitions
   
   __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
      ERRORLEVEL -302
      ERRORLEVEL -305
; las variables comienzan en 20´h *****************************************************
    CBLOCK      0X20
      
   ENDC
    #DEFINE LED     PORTA,2
    #DEFINE BEEP    PORTA,5

reset   ORG     0x000                   ; processor reset vector
        goto    inicio                  ; go to beginning of program
        ORG     0x004                   ; interrupt vector
        goto    RBI_Interrupcion ;
inicio
        ; seteo del PORTA
        banksel ADCON1      ; bank1
        movlw   0x06
        movwf   ADCON1      ; todos digitales
        clrf    TRISA       ; todas salidas
        banksel PORTA
        clrf    PORTA
        bsf       STATUS,RP0      ; select page 1 y de ahora en más queda en el BANK 1
        call    InitI2CBus_Master
        movlw   0x22        ; Slave Address
        movwf   SlaveAddr     
trigger       
        bcf       STATUS,RP0      ; select page 0
        call    beeper          ; para sincronizar el osciloscopio
      bsf       STATUS,RP0      ; select page 1
      
        call    SendStartBit
       
        call    SendSlaveAddr
        ; check for true or false
        btfsc   Bus_Status,4    ;  _Txmt_Success 
        goto    Fallo_de_TX
       
        call    SendStopBit
       
       
lazo    bcf     STATUS,RP0      ; select page 0
      bsf     LED
        call    Retardo_500ms
        bcf     LED
        call    Retardo_500ms
        goto    trigger
Fallo_de_TX
        bcf     STATUS,RP0      ; select page 0
      bsf     LED
        call    Retardo_200ms
        bcf     LED
        call    Retardo_200ms
        goto    trigger     

; aca termina el loop principal ***********************************************************

; ------------------------------------SUBRUTINAS ------------------------------------------

; BEEPER*** ******************************************************************************       
beeper
        bsf     BEEP
        call    Retardo_50ms
        bcf     BEEP
        return
; ******************* SUBRUTINA DE INTERRUPT **********************************************

RBI_Interrupcion
   clrf    INTCON          ; pare todas las interrupciones
   bsf     BEEP
    call    Retardo_1s
    bcf     BEEP
    retfie
      
 ; INCLUDES  *****************************************************************
     
    #include  <RETARDOS.inc>        ; subrutinas de retardo
    #include  <I2C_MASTER.inc>      ; subrutinas de manejo de BUS I2C
    end 
       
 Perdón porque algunos comentarios están en Inglés .
Pregunta: se puede simular I2C para el Slave en el MPLAB? existe algún simulador mejor y más práctico.

Gracias por tu ayuda

Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 18 de Noviembre de 2009, 17:48:37
Buenas, un simulador más practico puede ser Proteus o el PIC Simulator. En proteus probé el código slave y funciona correctamente  :-/ Si envías correctamente la dirección setea el bit R/W donde se indica que acción se quiere realizar.
Cuando digo que se envía correctamente la dirección es, en los bits 1 a 7 va la dirección y en el bit 0 la acción, osea que si la dirección del esclavo es 0x22, para escribir en él se debe enviar 0x45, pero si se quiere leer 0x44.

Lo único que cambie fue:
Código: ASM
  1. I2C_Handler
  2.     banksel SSPBUF
  3.     movf    SSPBUF,W
  4.     banksel PORTB
  5.     MOVWF   PORTB

Porque es en SSPBUF donde se recibe el dato y es necesario leerlo para que se borre el bit BF, sino se activará el bit de sobre-escritura.

Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 18 de Noviembre de 2009, 20:17:50
 :) Nuevamente Gracias Suki por probar el Slave (ahora que me fijo no te mandé el IC2_Master.INC que va con el assembler del Master), ahi va:
(Si me contestas , por favor dime como poner el código en ese recuadro gris que no ocupa tanto lugar)
; ////////////////////// I2C_MASTER.INC ////////////////////////////////////////////////
; VARIABLES LOCALES ******************************************************************
    CBLOCK      0xA0    ; TODAS LAS VARIABLES DEL I2C ESTAN EN EL BANK 1 !!!!!
       Bus_Status      ; Status Reg of I2C Bus for both TXMT & RCVE
      Bus_Control      ; control Register of I2C Bus
       DataByte      ; load this reg with the data to be transmitted
      BitCount      ; The bit number (0:7) transmitted or received
      DelayCount
      SlaveAddr
   ENDC
; ******************** DEFINICIONES **************************************************
    #DEFINE     I2C_SCL     TRISA,3     ; I2C Clock
      #DEFINE     I2C_SDA     TRISA,4     ; I2C Data
      #DEFINE     _SCL        PORTA,3     ; I2C Clock Estado del Bus
      #DEFINE     _SDA        PORTA,4     ; I2C Data Estado del Bus
; NO SE TRABAJA CON BSF NI BCF SOBRE EL PORT !!!!!
; SE PONEN AMBOS PORT LATCHS EN CERO, PULLUPS EXTERNOS DE 4K7 Y SE TRABAJA CON TRIS
; Si TRIS es 0 (output) entonces pone cero (lo que tenía en el latch).
; Si TRIS es 1 (input) entonces deja que el pullup levante a 1 (el port que High Z).
;*************************************************************************************
;         I2C Bus Status Reg Bit Definitions
;*************************************************************************************
#define   _Bus_Busy       Bus_Status,0
#define   _Abort          Bus_Status,1
#define   _Txmt_Progress   Bus_Status,2
#define   _Rcv_Progress   Bus_Status,3
#define   _Txmt_Success   Bus_Status,4
#define   _Rcv_Success   Bus_Status,5
#define   _Fatal_Error   Bus_Status,6
#define   _ACK_Error       Bus_Status,7

;*************************************************************************************
;         I2C Bus Control Register
;*************************************************************************************
#define   _10BitAddr       Bus_Control,0
#define   _Slave_RW       Bus_Control,1
#define   _Last_Byte_Rcv   Bus_Control,2
#define   _SlaveActive   Bus_Control,6
#define   _TIME_OUT_       Bus_Control,7

;*************************************************************************************
;*************************************************************************************
RELEASE_BUS   MACRO    ; pone el port en Input y deja que actue el pullup externo de 4k7
   
         bsf     STATUS,RP0      ; select page 1
         bsf       I2C_SDA          ; tristate SDA
         bsf       I2C_SCL          ; tristate SCL
         ENDM                    ; fin de la Macro. OJO queda en Bank 1 !!

;**************************************************************************************
     
; EQUIVALENCIAS ***********************************************************************
TRUE   equ   1
FALSE   equ   0
;*************************************************************************************
;                   SINGLE  MASTER, MULTIPLE SLAVES
;*************************************************************************************
;            I2C Bus Initialization
;*************************************************************************************
InitI2CBus_Master
       bcf       STATUS,RP0  ; bank 0
       movf   PORTA,W
       andlw   0xE7      ; do not use BSF & BCF on Port Pins
       movwf   PORTA      ; set SDA & SCL to zero. From Now on, simply play with TRIS
        RELEASE_BUS         ; MACRO
       clrf   Bus_Status   ; reset status reg
       clrf   Bus_Control   ; clear the Bus_Control Reg, reset to 8 bit addressing
       return
;***************************************************************************************
;            Send Start Bit
;***************************************************************************************
SendStartBit
      bsf       I2C_SDA          ; set SDA high
      bsf       I2C_SCL          ; set SCL high
       call    Delay10uS       ; only necessary for setup time
        bcf       I2C_SDA          ; give a falling edge on SDA while clock is high
      call    Delay10uS       ; only necessary for START HOLD time
      bsf       _Bus_Busy       ; on a start condition bus is busy
      return

;****************************************************************************************
;            Send Stop Bit
;****************************************************************************************
SendStopBit
      bsf       STATUS,RP0   ; select page 1
      bcf       I2C_SCL      
      bcf       I2C_SDA      ; set SDA low
      bsf       I2C_SCL      ; Clock is pulled up
      call    Delay10uS
      bsf       I2C_SDA      ; give a rising edge on SDA while CLOCK is high
         bcf       _Bus_Busy   ; on a stop condition bus is considered Free
      return   

;*****************************************************************************************
;               Abort Transmission / Send STOP Bit & set Abort Flag
;*****************************************************************************************
AbortTransmission
      call   SendStopBit
      bsf       _Abort
      return   
;*****************************************************************************************
;            Transmit Address (1st Byte)& Put in Read/Write Operation
;  Transmits Slave Addr On the 1st byte and set LSB to R/W operation
;  Slave Address must be loaded into SlaveAddr reg
;  On Success, return TRUE in WREG, else FALSE in WREG
;   If desired, the failure may tested by the bits in Bus Status Reg
;*******************************************************************************************
SendSlaveAddr
       bcf       _ACK_Error          ; reset Acknowledge error bit
      movf   SlaveAddr,W
       movwf   DataByte      ; load addr to Data Byte for transmission
       call   SendData      ; send 8 bits of address
; if successfully transmitted, expect an ACK bit
_AddrSendTest
       btfss   _Txmt_Success      ; skip if successful
       goto   _AddrSendFail
       retlw   TRUE
_AddrSendFail
       btfss   _ACK_Error
       retlw   FALSE         ; Addr Txmt Unsuccessful, so return 0
; Address Not Acknowledged, so send STOP bit
       call   SendStopBit
       retlw   FALSE         ; Addr Txmt Unsuccessful, so return 0
;*******************************************************************************************
;            TRANSMIT A BYTE OF DATA
; The data to be transmitted must be loaded into DataByte Reg
;*******************************************************************************************
SendData                        ; send 8 bits & wait for ACK

      bsf       _Txmt_Progress   ; set Bus status for txmt progress
      bcf       _Txmt_Success   ; reset status bit
      movlw   0x08
      movwf   BitCount
      
TxmtNextBit
      bcf       I2C_SCL         ; set clock low
      rlf     DataByte, F       ; MSB first, Note DataByte Is Lost
        bcf       I2C_SDA
      btfsc   STATUS,C
      bsf       I2C_SDA
      call    Delay10uS
      bsf       I2C_SCL          ; set clock high
; check if clock is high, else clock is being stretched
      call    Delay10uS
      decfsz   BitCount, F
      goto   TxmtNextBit
; Check For Acknowledge
      bcf       I2C_SCL          ; set clock low
      bsf       I2C_SDA          ; Release SDA line for Slave to pull down
      call    Delay10uS
      bsf       I2C_SCL          ; clock for slave to ACK
      call    Delay10uS
      
      bcf       STATUS,RP0      ; select PAGE 0 to test PortA pin SDA
      btfsc   _SDA          ; SDA should be pulled low by slave if OK
        goto   _TxmtErrorAck

      bsf       STATUS,RP0      ; select page 1
      bcf   _Txmt_Progress   ; reset TXMT bit in Bus Status
      bsf   _Txmt_Success   ; transmission successful
      bcf   _ACK_Error       ; ACK OK
      return
_TxmtErrorAck
      RELEASE_BUS
      bcf   _Txmt_Progress   ; reset TXMT bit in Bus Status
      bcf   _Txmt_Success   ; transmission NOT successful
      bsf   _ACK_Error       ; No ACK From Slave
      return
;********************************************************************************************
;         General Purpose Delay Routine
;********************************************************************************************
Delay10uS       ; 2us for the Call + 8 nops + 2us for return = 10us
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   return      
;********************************************************************************************

Por otra parte, no entendí bien el tema del address. Si la dirección del Slave es 0x22 , cómo es que hay que poner 0x44 para escribir un byte en él?
Saludos y  :-/ gracias
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 18 de Noviembre de 2009, 20:52:41
Porque no usas el módulo para el master? Te facilita las cosas y además tendras menos código. Con respecto a la dirección lo explico en el mismo mensaje, lee detalladamente y lee por aquí (http://infopic-suky.blogspot.com/2009/04/buses-de-comunicacion.html) un tutorial sobre el protocolo I2C


Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 19 de Noviembre de 2009, 09:35:31
Hola Suki
Según la hoja de datos del PIC16F73, el módulo SSP es sólo para cuando actua como Slave.
Para que funcione como Master, se debe hacer por firmware.
No lo conozco a fondo, pero creo que el 16F877 tiene módulo MSSP y ese si puede funcionar como Master.
Estoy tratando de conseguir el Proteus.

Gracias por tus comentarios.
Saludos
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 19 de Noviembre de 2009, 09:59:43
 :oops: Perdón, di por hecho que se podía trabajar en modo master con el hardware, el 16F873 tiene módulo MSSP.

Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 19 de Noviembre de 2009, 12:33:30
Nada de que avergonzarse, yo tengo 53 años y me reinicié en esto de los micros ahora. Cuando estudiaba ingenieria electrónica el Intel 8080 estaba en pañales , y encima necesitaba 3 tensiones de alimentación !! una locura. En fin, de a poco me voy poniendo a tono con todo esto.
A propósito, ya entendí eso de las direcciones del esclavo. Era fácil, son sólo los 7 primeros bits y luego agregar cero o uno segun quieras escribir o leer.
Traté de simular el Slave con el PICSIMulator pero no hay caso, no marca el bit de START en el SSPSTAT.
Sin embargo, si lo pude lograr en el circuito  :-) ... por fin !!  es increible, los electrónicos nos ponemos felices cuando prende un led !!  :lol:
Bueno, ahora sigo con la reedición del Master a ver que puedo lograr. El manual de lmicro dice que se puede controlar el módulo por firmware pero no aclara bien como.
Todo este firmware en realidad forma parte de un proyecto más grande en el que un Master actualiza datos en varios Slaves para que cambien sus parámetros. Los Slaves controlan motores paso a paso que a su vez cambian la velocidad de acuerdo con la posición de un joystick.
Espero terminar algún día.
Cualquier novedad te comento....
Ah! cómo hago para poner código en el rectángulo gris?

Saludos y gracias
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 19 de Noviembre de 2009, 13:12:12
Probé el master y también funciona dentro de todo bien, lo único que debes cambiar es el testeo de btfsc   Bus_Status,4 a btfss   Bus_Status,4 dado que si ha ocurrido el proceso el bit se setea a 1.

Para colocar código debes ponerlo entre [ code ] Aquí código [ /code ] (Sin los espacios) y para colocarlo coloreado [ code=asm ] Aquí código [ /code ]

Saludos!!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 20 de Noviembre de 2009, 16:40:58
Bueno, por fin he arribado a algo  :D
Al final te envío los assemblers del Master (Send Addres solo.asm con sus INC) y el de l Slave (TodoPIC Slave.asm).
Ahora el Master lee del PORTB la dirección del Slave (para poder ir cambiándola y ver que pasa), y la envía cíclicamente hacia el Slave.
De acuerdo con que reciba un ACK del Slave o no, enciende el LED verde (ACK recibido) o el LED rojo (ACK no recibido).
Las señales SCL y SDA salen del los pines 3 y 4 del PORT A

Mis comentarios y dudas son los siguientes:
- En el Master las señales SCL y SDA hacia el Slave hay que manejarlas cargando esos pines del port A con 0 , poner un pulll up externo y después mover la señal con BSF y BCF pero sobre el TRIS de ese pin y no BSF y BCF directamente sobre el pin . Si usas BSF o BCF directamente sobre cualquier pin de ese port (PORTA en este caso), entonces el Master deja de transmitir y quedan las señales en 1  :shock:
Si te fijas, en el caso de no recibir ACK el programa va a: Fallo_de_TX si aquí intento encender el LED directamente con bsf PORTA,0 el programa sigue corriendo (hace el loop entre vuelta .... goto vuelta), pero los pines RA3 y RA4 quedan en 1.
En cambio, mientras todo está andando bien (recibiendo el ACK del Slave), prendo el LED verde con bsf pero sobre el TRIS del PORTA,2. El programa sigue reciclando entre vuelta y goto vuelta y en cada ciclo reeenvía START ADDRESS y STOP sin problemas.
Al final, probé prendiendo el LED rojo desde otro port (el PORTC), directamente con bsf PORTC,0 y no hubo ningún problema, si el Master detecta que no le llega un ACK prende el LED rojo y sigue enviando todo cada ciclo.
 :huh: mi pregunta es ; porqué pasa esto? El PIC no sabe que está trabajando en I2C (por lo menos el Master), porqué no puedo mover los otros pines de ese port con bsf o bcf directamente sobre el pin?
Si es así, entonces tengo que cambiar todo el manejo de ese port en el progrma general ya que tengo colgado un teclado y un LCD.
Ahora seguiré trabajando sobre ambos (Master y Slave), para lograr enviar 2 bytes de datos del Master al Slave.
Aquí van los programas:
MASTER
Código: ASM
  1. list      p=16F73            ; list directive to define processor
  2.         #include <p16F73.inc>        ; processor specific variable definitions
  3.    
  4.    
  5.         __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
  6.       ERRORLEVEL -302
  7.       ERRORLEVEL -305
  8. ; las variables comienzan en 20´h *****************************************************
  9.     CBLOCK      0X20
  10.            
  11.         ENDC
  12.     #DEFINE     RED_LED     PORTC,0
  13.     #DEFINE     GREEN_LED   TRISA,2
  14.     #DEFINE     I2C_SCL     TRISA,3     ; I2C Clock
  15.         #DEFINE     I2C_SDA     TRISA,4     ; I2C Data
  16.         #DEFINE     BEEP        TRISA,5     ; trigger del osciloscopio
  17.    
  18. reset   ORG     0x000                   ; processor reset vector
  19.                 goto    inicio                  ; go to beginning of program
  20.         ORG     0x004                   ; interrupt vector
  21.                 goto    RBI_Interrupcion ;
  22. inicio
  23.         ; seteo del PORTA
  24.         banksel ADCON1      ; bank1
  25.         movlw   0x06
  26.         movwf   ADCON1      ; todos digitales
  27.         clrf    TRISA       ; todas salidas
  28.         movlw   0xFF
  29.         movwf   TRISB       ; todas entradas para leer el SLAVE Address
  30.         clrf    TRISC       ; todas salidas
  31.         banksel PORTA
  32.         movlw   b'00100100' ; bit 5 on for osc. trigger
  33.         movwf   PORTA
  34.         clrf    PORTC
  35.         bsf         STATUS,RP0          ; select page 1 y de ahora en más queda en el BANK 1
  36.         bsf     GREEN_LED       ; pone 0 en GREEN_LED
  37.        
  38.         call    InitI2CBus_Master
  39.        
  40. vuelta        
  41.         banksel PORTB
  42.         movf    PORTB,W         ; lee PORTB
  43.         banksel  SlaveAddr
  44.         movwf   SlaveAddr       ; carga Slave Address
  45.        
  46.         bsf         STATUS,RP0          ; select page 1
  47.         call    trigger          ; para sincronizar el osciloscopio
  48.                
  49.         call    SendStartBit
  50.         call    SendSlaveAddr
  51.        
  52.         btfss   Bus_Status,4    ; check for true or false  (_Txmt_Success)
  53.         goto    Fallo_de_TX
  54.         call    SendStopBit
  55.                        
  56. lazo    
  57.                 bcf     GREEN_LED       ; pone 1 en GREEN_LED
  58.         call    Retardo_50ms
  59.         bsf     GREEN_LED       ; pone 0 en GREEN_LED
  60.         call    Retardo_50ms
  61.         goto    vuelta
  62. Fallo_de_TX
  63.                 banksel PORTC
  64.                 bsf     RED_LED
  65.         call    Retardo_50ms
  66.         bcf     RED_LED
  67.         call    Retardo_50ms
  68.         goto    vuelta    
  69.  
  70. ; aca termina el loop principal ***********************************************************
  71.  
  72. ; ------------------------------------SUBRUTINAS ------------------------------------------
  73.  
  74. ; BEEPER*** ******************************************************************************        
  75. trigger
  76.         bsf     BEEP
  77.         call    Delay10uS
  78.         bcf     BEEP
  79.         return
  80. ; ******************* SUBRUTINA DE INTERRUPT **********************************************
  81.  
  82. RBI_Interrupcion
  83.  
  84.     retfie
  85.            
  86.  ; INCLUDES  *****************************************************************
  87.      
  88.     #include  <RETARDOS.inc>        ; subrutinas de retardo
  89.     #include  <I2C_MASTER.inc>      ; subrutinas de manejo de BUS I2C
  90.     end

I2C_MASTER.INC

Código: [Seleccionar]
; ////////////////////// I2C_MASTER.INC ////////////////////////////////////////////////
; VARIABLES LOCALES ******************************************************************
    CBLOCK      0xA0    ; TODAS LAS VARIABLES DEL I2C ESTAN EN EL BANK 1 !!!!!
    Bus_Status ; Status Reg of I2C Bus for both TXMT & RCVE
DataByte ; load this reg with the data to be transmitted
BitCount ; The bit number (0:7) transmitted or received
SlaveAddr
ENDC
; ******************** DEFINICIONES **************************************************
    ; #DEFINE     I2C_SCL     TRISA,3     ; I2C Clock
    ; #DEFINE     I2C_SDA     TRISA,4     ; I2C Data
    #DEFINE     _SCL        PORTA,3     ; I2C Clock Estado del Bus
    #DEFINE     _SDA        PORTA,4     ; I2C Data Estado del Bus
; NO SE TRABAJA CON BSF NI BCF SOBRE EL PORT !!!!!
; SE PONEN AMBOS PORT LATCHS EN CERO, PULLUPS EXTERNOS DE 4K7 Y SE TRABAJA CON TRIS
; Si TRIS es 0 (output) entonces pone cero (lo que tenía en el latch).
; Si TRIS es 1 (input) entonces deja que el pullup levante a 1 (el port que High Z).
;*************************************************************************************
; I2C Bus Status Reg Bit Definitions
;*************************************************************************************
#define _Bus_Busy     Bus_Status,0
#define _Abort     Bus_Status,1
#define _Txmt_Progress Bus_Status,2
#define _Rcv_Progress Bus_Status,3
#define _Txmt_Success Bus_Status,4
#define _Rcv_Success Bus_Status,5
#define _Fatal_Error Bus_Status,6
#define _ACK_Error     Bus_Status,7

;*************************************************************************************
RELEASE_BUS MACRO    ; pone el port en Input y deja que actue el pullup externo de 4k7

bsf     STATUS,RP0 ; select page 1
bsf     I2C_SDA     ; tristate SDA
bsf     I2C_SCL     ; tristate SCL
ENDM                    ; fin de la Macro. OJO queda en Bank 1 !!

;**************************************************************************************
 
; EQUIVALENCIAS ***********************************************************************
TRUE equ 1
FALSE equ 0
;*************************************************************************************
;                 SINGLE  MASTER, MULTIPLE SLAVES
;*************************************************************************************
; I2C Bus Initialization
;*************************************************************************************
InitI2CBus_Master
    bcf     STATUS,RP0  ; bank 0
    movf PORTA,W
    andlw 0xE7 ; do not use BSF & BCF on Port Pins
    movwf PORTA ; set SDA & SCL to zero. From Now on, simply play with TRIS
        RELEASE_BUS         ; MACRO
    clrf Bus_Status ; reset status reg
    return
;***************************************************************************************
; Send Start Bit
;***************************************************************************************
SendStartBit
bsf     I2C_SDA     ; set SDA high
bsf     I2C_SCL     ; set SCL high
    call    Delay10uS       ; only necessary for setup time
        bcf     I2C_SDA     ; give a falling edge on SDA while clock is high
call    Delay10uS     ; only necessary for START HOLD time
bsf     _Bus_Busy       ; on a start condition bus is busy
return

;****************************************************************************************
; Send Stop Bit
;****************************************************************************************
SendStopBit
bsf     STATUS,RP0 ; select page 1
bcf     I2C_SCL
bcf     I2C_SDA ; set SDA low
bsf     I2C_SCL ; Clock is pulled up
call    Delay10uS
bsf     I2C_SDA ; give a rising edge on SDA while CLOCK is high
    bcf     _Bus_Busy ; on a stop condition bus is considered Free
return

;*****************************************************************************************
; Abort Transmission / Send STOP Bit & set Abort Flag
;*****************************************************************************************
AbortTransmission
call SendStopBit
bsf     _Abort
return
;*****************************************************************************************
; Transmit Address (1st Byte)& Put in Read/Write Operation
;  Transmits Slave Addr On the 1st byte and set LSB to R/W operation
;  Slave Address must be loaded into SlaveAddr reg
;  On Success, return TRUE in WREG, else FALSE in WREG
;   If desired, the failure may tested by the bits in Bus Status Reg
;*******************************************************************************************
SendSlaveAddr
    bcf     _ACK_Error     ; reset Acknowledge error bit
movf SlaveAddr,W
    movwf DataByte ; load addr to Data Byte for transmission
    call SendData ; send 8 bits of address
; if successfully transmitted, expect an ACK bit
_AddrSendTest
    btfss _Txmt_Success ; skip if successful
    goto _AddrSendFail
    retlw TRUE
_AddrSendFail
    btfss _ACK_Error
    retlw FALSE ; Addr Txmt Unsuccessful, so return 0
; Address Not Acknowledged, so send STOP bit
    call SendStopBit
    retlw FALSE ; Addr Txmt Unsuccessful, so return 0
;*******************************************************************************************
; TRANSMIT A BYTE OF DATA
; The data to be transmitted must be loaded into DataByte Reg
;*******************************************************************************************
SendData                        ; send 8 bits & wait for ACK

bcf     _Txmt_Success ; reset status bit
movlw 0x08
movwf BitCount

TxmtNextBit
bcf     I2C_SCL         ; set clock low
call    Delay10uS
rlf     DataByte, F     ; MSB first, Note DataByte Is Lost
        bcf     I2C_SDA
btfsc STATUS,C
bsf     I2C_SDA
call    Delay10uS
bsf     I2C_SCL     ; set clock high
; check if clock is high, else clock is being stretched
call    Delay10uS
decfsz BitCount, F
goto TxmtNextBit
; Check For Acknowledge
bcf     I2C_SCL     ; set clock low
bsf     I2C_SDA     ; Release SDA line for Slave to pull down
call    Delay10uS
bsf     I2C_SCL     ; clock for slave to ACK
call    Delay10uS

bcf     STATUS,RP0 ; select PAGE 0 to test PortA pin SDA
btfsc _SDA     ; SDA should be pulled low by slave if OK
        goto _TxmtErrorAck

bsf     STATUS,RP0      ; select page 1
bcf _Txmt_Progress ; reset TXMT bit in Bus Status
bsf _Txmt_Success ; transmission successful
bcf _ACK_Error     ; ACK OK
return
_TxmtErrorAck
RELEASE_BUS
bcf _Txmt_Progress ; reset TXMT bit in Bus Status
bcf _Txmt_Success ; transmission NOT successful
bsf _ACK_Error     ; No ACK From Slave
return
;********************************************************************************************
; General Purpose Delay Routine
;********************************************************************************************
Delay10uS       ; 2us for the Call + 8 nops + 2us for return = 10us
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
return
;********************************************************************************************


RETARDOS.INC

Código: [Seleccionar]
;**************************** Librería "RETARDOS.INC" *********************************
;
; ===================================================================
;   Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;   E. Palacios, F. Remiro y L. López.
;   Editorial Ra-Ma.  www.ra-ma.es
; ===================================================================
;
; Librería con múltiples subrutinas de retardos, desde 4 microsegundos hasta 20 segundos.
; Además se pueden implementar otras subrutinas muy fácilmente.
;
; Se han calculado para un sistema microcontrolador con un PIC trabajando con un cristal
; de cuarzo a 4 MHz. Como cada ciclo máquina son 4 ciclos de reloj, resulta que cada
; ciclo máquina tarda 4 x 1/4MHz = 1 µs.
;
; En los comentarios, "cm" significa "ciclos máquina".
;
; ZONA DE DATOS *********************************************************************

CBLOCK  0x20
R_ContA ; Contadores para los retardos.
R_ContB
R_ContC
ENDC
;
; RETARDOS de 4 hasta 10 microsegundos ---------------------------------------------------
;
; A continuación retardos pequeños teniendo en cuenta que para una frecuencia de 4 MHZ,
; la llamada a subrutina "call" tarda 2 ciclos máquina, el retorno de subrutina
; "return" toma otros 2 ciclos máquina y cada instrucción "nop" tarda 1 ciclo máquina.
;
Retardo_10micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
Retardo_5micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
Retardo_4micros ; La llamada "call" aporta 2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
; RETARDOS de 20 hasta 500 microsegundos ------------------------------------------------
;
Retardo_500micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'164' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_200micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'64' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_100micros ; La llamada "call" aporta 2 ciclos máquina.
movlw d'31' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_50micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'14' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_20micros ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "K".
;
; El próximo bloque "RetardoMicros" tarda:
; 1 + (K-1) + 2 + (K-1)x2 + 2 = (2 + 3K) ciclos máquina.
;
RetardoMicros
movwf R_ContA ; Aporta 1 ciclo máquina.
Rmicros_Bucle
decfsz R_ContA,F ; (K-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto Rmicros_Bucle ; Aporta (K-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_500micros: 2 + 1 + 1 + 2 + (2 + 3K) = 500 cm = 500 µs. (para K=164 y 4 MHz).
; - Retardo_200micros: 2 + 1 + 1 + 2 + (2 + 3K) = 200 cm = 200 µs. (para K= 64 y 4 MHz).
; - Retardo_100micros: 2     + 1 + 2 + (2 + 3K) = 100 cm = 100 µs. (para K= 31 y 4 MHz).
; - Retardo_50micros : 2 + 1 + 1 + 2 + (2 + 3K) =  50 cm =  50 µs. (para K= 14 y 4 MHz).
; - Retardo_20micros : 2     + 1     + (2 + 3K) =  20 cm =  20 µs. (para K=  5 y 4 MHz).
;
; RETARDOS de 1 ms hasta 200 ms. --------------------------------------------------------
;
Retardo_200ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'200' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_100ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'100' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_50ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'50' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_20ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'20' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_10ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'10' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_5ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_2ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'2' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_1ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'1' ; Aporta 1 ciclo máquina. Este es el valor de "M".
;
; El próximo bloque "Retardos_ms" tarda:
; 1 + M + M + KxM + (K-1)xM + Mx2 + (K-1)Mx2 + (M-1) + 2 + (M-1)x2 + 2 =
; = (2 + 4M + 4KM) ciclos máquina. Para K=249 y M=1 supone 1002 ciclos máquina
; que a 4 MHz son 1002 µs = 1 ms.
;
Retardos_ms
movwf R_ContB ; Aporta 1 ciclo máquina.
R1ms_BucleExterno
movlw d'249' ; Aporta Mx1 ciclos máquina. Este es el valor de "K".
movwf R_ContA ; Aporta Mx1 ciclos máquina.
R1ms_BucleInterno
nop ; Aporta KxMx1 ciclos máquina.
decfsz R_ContA,F ; (K-1)xMx1 cm (cuando no salta) + Mx2 cm (al saltar).
goto R1ms_BucleInterno ; Aporta (K-1)xMx2 ciclos máquina.
decfsz R_ContB,F ; (M-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto R1ms_BucleExterno ; Aporta (M-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_200ms: 2 + 1 + 2 + (2 + 4M + 4KM) = 200007 cm = 200 ms. (M=200 y K=249).
; - Retardo_100ms: 2 + 1 + 2 + (2 + 4M + 4KM) = 100007 cm = 100 ms. (M=100 y K=249).
; - Retardo_50ms : 2 + 1 + 2 + (2 + 4M + 4KM) =  50007 cm =  50 ms. (M= 50 y K=249).
; - Retardo_20ms : 2 + 1 + 2 + (2 + 4M + 4KM) =  20007 cm =  20 ms. (M= 20 y K=249).
; - Retardo_10ms : 2 + 1 + 2 + (2 + 4M + 4KM) =  10007 cm =  10 ms. (M= 10 y K=249).
; - Retardo_5ms  : 2 + 1 + 2 + (2 + 4M + 4KM) =   5007 cm =   5 ms. (M=  5 y K=249).
; - Retardo_2ms  : 2 + 1 + 2 + (2 + 4M + 4KM) =   2007 cm =   2 ms. (M=  2 y K=249).
; - Retardo_1ms  : 2 + 1     + (2 + 4M + 4KM) =   1005 cm =   1 ms. (M=  1 y K=249).
;
; RETARDOS de 0.5 hasta 20 segundos ---------------------------------------------------
;
Retardo_20s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'200' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_10s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'100' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_5s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'50' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_2s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'20' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_1s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'10' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_500ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "N".
;
; El próximo bloque "Retardo_1Decima" tarda:
; 1 + N + N + MxN + MxN + KxMxN + (K-1)xMxN + MxNx2 + (K-1)xMxNx2 +
;   + (M-1)xN + Nx2 + (M-1)xNx2 + (N-1) + 2 + (N-1)x2 + 2 =
; = (2 + 4M + 4MN + 4KM) ciclos máquina. Para K=249, M=100 y N=1 supone 100011
; ciclos máquina que a 4 MHz son 100011 µs = 100 ms = 0,1 s = 1 décima de segundo.
;
Retardo_1Decima
movwf R_ContC ; Aporta 1 ciclo máquina.
R1Decima_BucleExterno2
movlw d'100' ; Aporta Nx1 ciclos máquina. Este es el valor de "M".
movwf R_ContB ; Aporta Nx1 ciclos máquina.
R1Decima_BucleExterno
movlw d'249' ; Aporta MxNx1 ciclos máquina. Este es el valor de "K".
movwf R_ContA ; Aporta MxNx1 ciclos máquina.
R1Decima_BucleInterno         
nop ; Aporta KxMxNx1 ciclos máquina.
decfsz R_ContA,F ; (K-1)xMxNx1 cm (si no salta) + MxNx2 cm (al saltar).
goto R1Decima_BucleInterno ; Aporta (K-1)xMxNx2 ciclos máquina.
decfsz R_ContB,F ; (M-1)xNx1 cm (cuando no salta) + Nx2 cm (al saltar).
goto R1Decima_BucleExterno ; Aporta (M-1)xNx2 ciclos máquina.
decfsz R_ContC,F ; (N-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto R1Decima_BucleExterno2 ; Aporta (N-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_20s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 20000807 cm = 20 s.
; (N=200, M=100 y K=249).
; - Retardo_10s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 10000407 cm = 10 s.
; (N=100, M=100 y K=249).
; - Retardo_5s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  5000207 cm =  5 s.
; (N= 50, M=100 y K=249).
; - Retardo_2s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  2000087 cm =  2 s.
; (N= 20, M=100 y K=249).
; - Retardo_1s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  1000047 cm =  1 s.
; (N= 10, M=100 y K=249).
; - Retardo_500ms: 2 + 1     + (2 + 4N + 4MN + 4KMN) =   500025 cm = 0,5 s.
; (N=  5, M=100 y K=249).

; ===================================================================
;   Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;   E. Palacios, F. Remiro y L. López.
;   Editorial Ra-Ma.  www.ra-ma.es
; ===================================================================





SLAVE

Código: [Seleccionar]
;   I2C_SLAVE.ASM ----------------------------------------------------

  list      p=16F73           
 #include <p16F73.inc>       
   
 __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
      ERRORLEVEL -302
      ERRORLEVEL -305

  #DEFINE NODE_ADDR   0x22 ; I2C address of this node
   
reset    ORG     0x000                   ; processor reset vector
         goto    inicio                  ; go to beginning of program
         ORG     0x004                   ; interrupt vector
         goto    ISR                     ;
inicio
        call    Setup
       
Main    NOP
        goto    Main ; Loop forever.       

; ------------------------------------SUBRUTINAS ------------------------------------------
Setup   ; Initializa variables y registros
   
    banksel PORTC       
    clrf    PIR1
    clrf    SSPBUF
    clrf    PORTB
    movlw   NODE_ADDR
    banksel SSPADD
    movwf   SSPADD
    clrf    SSPSTAT
    clrf    TRISB
    MOVLW   0xFF
    movwf   TRISC                  ; ALL INPUTS (RC3 & RC4 MUST BE INPUTS)
    bsf     PIE1,SSPIE
    bsf     INTCON,PEIE            ; Enable all peripheral interrupts
    bsf     INTCON,GIE             ; Enable global interrupts
    bcf     STATUS,RP0
    movlw   0x36                   ; Setup SSP module for 7-bit
    movwf   SSPCON                ; address, slave mode
    return

; ******************* INTERRUPT **********************************************
ISR
    banksel PIR1
    btfss   PIR1,SSPIF      ; Is this an I2C interrupt?
    goto    salida          ; No, salga.
    call    I2C_Handler     ; Yes, service I2C interrupt.
    banksel PIR1
    bcf     PIR1,SSPIF
salida
    retfie                  ; Return from interrupt.

I2C_Handler 
    banksel SSPBUF
    movf    SSPBUF,W
    movwf   PORTB
    bcf     SSPCON,SSPOV ; SSPCON<6> =0 ----> No Overflow
    banksel SSPSTAT         ; Bank 1
    bcf     SSPSTAT,BF ; SSPSTAT<0> Buffer Full
    return

 ; INCLUDES  *****************************************************************
    ; #include  <I2C_SLAVE.inc>      ; subrutinas de manejo de BUS I2C
   
    end

Espero haber aprendido como se mandan los archivos dentro de esa cajita gris

Saludos y gracias por tu ayuda :-)
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 20 de Noviembre de 2009, 21:59:52
 :shock: Por lo visto al actuar sobre cualquier pin se debe modificar (En hardware) el valor del pin que en ese momento esta como entrada (I2C inactivo), Quedaría actualizar a 0 los bits del PORTA utilizados por I2C antes de comenzar algún proceso en él  :?


Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 24 de Noviembre de 2009, 14:22:01
Hola Suki.
Bueno parece que tenías razón  :-/ antes de mover algún pin del PORT A, primero tuve que mandar los que usaba para SDA y SCL a 1 y el TRISA 3 y 4 como salidas. Luego de eso te permite comandar las salidas de los pines del port con BSF y BCF directamente sobre el pin y sigue funcionando todo normal.
 :shock: :shock: :shock:  :?: :?: :?:sigo sin entender porqué pasa esto pero: creer o reventar :D
Achiqué bastante las rutinas para lograr algo más compacto y que no ocupe tanto espacio (  8) soy viejo y ahorro bytes de programa  :lol: ).
Ah, antes que me olvide, si pones en el Slave un dirección en el SSPADD (x ej: 0x22), hay que transmitirle exactamente ese valor para que reconozca la transmisión, o sea 0x22  y no 0x44 como pensábamos.
Ya terminé los dos programas (Master y Slave), y se comunican muy bien. Le envío el address y dos bytes de datos sin ningún problema. Y si cambio el address en el Master o en el Slave no hay comunicación.
Si a alguien le interesan los programas los puedo postear.
Lo único que no funcionaría en un entrorno I2C Bus sería la llamada general (se supone que si mandas Address = 00, todos los Slave tienen que "escuchar" la transmisión como si fuera para ellos.
Bien, de nuevo Suki, muchas gracias por tu ayuda y hasta pronto  :-) :-) :-) :-/
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 24 de Noviembre de 2009, 15:02:08
Hola Suki.
Bueno parece que tenías razón  :-/ antes de mover algún pin del PORT A, primero tuve que mandar los que usaba para SDA y SCL a 1 y el TRISA 3 y 4 como salidas. Luego de eso te permite comandar las salidas de los pines del port con BSF y BCF directamente sobre el pin y sigue funcionando todo normal.
 :shock: :shock: :shock:  :?: :?: :?:sigo sin entender porqué pasa esto pero: creer o reventar :D

Debe ser como trabaja el hardware, y como los pines están como entradas se actualizan  ;-)

Ah, antes que me olvide, si pones en el Slave un dirección en el SSPADD (x ej: 0x22), hay que transmitirle exactamente ese valor para que reconozca la transmisión, o sea 0x22  y no 0x44 como pensábamos.

Seguro? mira que enviando 0x22 no sabes que operación quieres hacer en el slave, por eso en el protocolo I2C se estable la dirección en los 7 bits mas significativos y el bit LSb (0) para indicar la operación. Fue exactamente lo que comprobé en la prueba anterior, donde al enviar 0x44 o 0x45 se setea el bit R/W del registro SSPSTAT. En el slave, al recibir el primer byte se debe rotar a la derecha con carry 0 y comprobar la dirección, luego leer el bit R/W para saber que operación se solicita.

Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 24 de Noviembre de 2009, 15:30:47
Estoy seguro. Cuando el SSP del Slave recibe 0x22 lo compara con lo que ya tiene almacenado en SSPADD y si los 7 bits más significativos coinciden, entonces - si está habilitado - genera un interrupt. En ese momento es que hay que decidir que es lo que quiere el  MASTER porque si llegó 0x22 (último bit 3n cero), entonces quiere decir que el Master quiere escribir datos en el Salve (prepararse para recibir datos hasta que llegue un Stop).
Si en cambio, el Slave recibe un 0x23, entonces el SSP del Slave también genera un interrupt (los 7 bits más significativos también coinciden), pero en éste caso el Master está queriendo leer datos del Salve y el programa debe cargar SSPBUF y esperar que el Master lo lea.
Las direcciones pares son para escribir en el Slave y las direcciones impares son para leer del Salve. Por eso es que sólo hay 127 direcciones posibles (en realidad según la Norma de I2C bus hay sólo 112 direcciones posibles porque algunas están reservadas, como por ejemplo: 0x00 que es la llamada general).
En mi caso por ahora, no estoy leyendo del Slave pero la escritura funciona bien de esta forma.
Si hay otra explicación estoy abierto a escucharla (la información siempre enriquece  :) )
Saludos :-/ :-/ :-/
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 24 de Noviembre de 2009, 20:52:55
Lo que pasa es que entonces la dirección del slave no es 0x22 !!  Y otra cosa, el microcontrolador siempre se interrumpe al recibir un dato, sea o no sea correcta la dirección, es por firmware que se debe controlar la recepción de datos  ;-)

Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 25 de Noviembre de 2009, 09:46:16
Hola Suki
Ya conseguí el Proteus. Me podrías enviar al archivo con el circuito donde has probado el Slave para ir aprendiendo cómo trabajar con él?
Aqui te envío los finales de Master y  Slave.
MASTER
Código: ASM
  1. ; ************ XTO_I2C_MASTER.ASM *****************************************************
  2.  
  3.     list      p=16F73            ; list directive to define processor
  4.         #include <p16F73.inc>        ; processor specific variable definitions
  5.        
  6.         __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
  7.       ERRORLEVEL -302
  8.       ERRORLEVEL -305
  9. ; las variables comienzan en 20´h *****************************************************
  10.     CBLOCK      0X20
  11.            Primer_byte
  12.            Segundo_byte
  13.            Current_Driver
  14.            Master_Data1
  15.            Master_Data2
  16.            Slave_Address
  17.            Kont1
  18.            Driver_map
  19.         ENDC
  20.    
  21.     ; #DEFINE       Master_Data1        b'00010010'
  22.         ; #DEFINE     Master_Data2        b'10000100'
  23.     #DEFINE     RED_LED     PORTA,0
  24.     #DEFINE     GREEN_LED   PORTA,2
  25.     #DEFINE     I2C_SCL     TRISA,3     ; I2C Clock
  26.         #DEFINE     I2C_SDA     TRISA,4     ; I2C Data
  27.         #DEFINE     BEEP        PORTA,5     ; trigger del osciloscopio
  28.         #DEFINE     _SCL        PORTA,3     ; I2C Clock Estado del Bus
  29.         #DEFINE     _SDA        PORTA,4     ; I2C Data Estado del Bus
  30. ;*************************************************************************************
  31. TEST_ACK        MACRO
  32.                     sublw   0x00        ; para mover STATUS REG
  33.                     btfsc   STATUS,Z
  34.                     goto    ACK_FAIL
  35.                 ENDM
  36. ;*************************************************************************************
  37. SEND_TO_DRIVER  MACRO    ; Envía datos (address o Data), al Driver
  38.                         call    SendData
  39.                         TEST_ACK
  40.                     ENDM     ; fin de la Macro. OJO queda en Bank 1 !!
  41. ;**************************************************************************************    
  42.        
  43. ;**************************************************************************************    
  44. reset   ORG     0x000                   ; processor reset vector
  45.                 goto    inicio                  ; go to beginning of program
  46.         ORG     0x004                   ; interrupt vector
  47.                 goto    RBI_Interrupcion ;
  48. inicio
  49.         ; seteo del PORTA
  50.         banksel ADCON1      ; bank1
  51.         movlw   0x06
  52.         movwf   ADCON1      ; todos digitales
  53.         clrf    TRISA       ; todas salidas
  54.         movlw   0xFF
  55.         movwf   TRISB       ; todas entradas para leer el SLAVE Address
  56.         banksel PORTA
  57.         movlw   b'00100000' ; bit 5 on for osc. trigger
  58.         movwf   PORTA
  59.         movlw   b'00010010'
  60.         movwf   Primer_byte
  61.         movlw   b'10000100'
  62.         movwf   Segundo_byte
  63.  
  64.  
  65. vuelta
  66.         banksel PORTB
  67.         movf    PORTB,W
  68.         movwf   Current_Driver
  69.         call    trigger
  70.        
  71.         bsf     STATUS,RP0
  72.         call    InitI2CBus_Master
  73.         call    SendStartBit
  74.         movf    Current_Driver,W
  75.         call    SendData
  76.         sublw   0x00        ; para mover STATUS REG
  77.         btfsc   STATUS,Z
  78.         goto    Fallo_ACK
  79.         movf    Primer_byte,W
  80.         call    SendData
  81.         sublw   0x00        ; para mover STATUS REG
  82.         btfsc   STATUS,Z
  83.         goto    Fallo_ACK
  84.         movf    Segundo_byte,W
  85.         call    SendData
  86.         sublw   0x00        ; para mover STATUS REG
  87.         btfsc   STATUS,Z
  88.         goto    Fallo_ACK
  89.         call    SendStopBit
  90.        
  91.         bsf     GREEN_LED       ; pone 1 en GREEN_LED
  92.         call    Retardo_50ms
  93.         bcf     GREEN_LED       ; pone 0 en GREEN_LED
  94.         call    Retardo_50ms
  95.         goto    vuelta
  96.  
  97. Fallo_ACK
  98.                 bcf     STATUS,RP0      ; Bank 0
  99.                 bsf     RED_LED
  100.         call    Retardo_50ms
  101.         bcf     RED_LED
  102.         call    Retardo_50ms
  103.         goto    vuelta    
  104.  
  105.  
  106. ; BEEPER*** ******************************************************************************        
  107. trigger
  108.         bsf     BEEP
  109.         call    Delay10uS
  110.         bcf     BEEP
  111.         return
  112. ; ******************* SUBRUTINA DE INTERRUPT **********************************************
  113.  
  114. RBI_Interrupcion
  115.  
  116.     retfie
  117.            
  118.  ; INCLUDES  *****************************************************************
  119.      
  120.     #include  <RETARDOS.inc>            ; subrutinas de retardo
  121.     #include  <XTO_I2C_MASTER.inc>      ; subrutinas de manejo de BUS I2C
  122.     end
INCs del Master
Código: ASM
  1. ; ////////////////////// XTO_I2C_MASTER.INC ////////////////////////////////////////////////
  2. ; VARIABLES LOCALES ******************************************************************
  3.     CBLOCK      0xA0    ; TODAS LAS VARIABLES DEL I2C ESTAN EN EL BANK 1 !!!!!
  4.             DataByte            ; load this reg with the data to be transmitted
  5.                 BitCount                ; The bit number (0:7) transmitted or received
  6.         ENDC
  7. ; ******************** DEFINICIONES **************************************************
  8.     ; #DEFINE     I2C_SCL     TRISA,3     ; I2C Clock
  9.         ; #DEFINE     I2C_SDA     TRISA,4     ; I2C Data
  10.         ; #DEFINE     _SCL        PORTA,3     ; I2C Clock Estado del Bus
  11.         ; #DEFINE     _SDA        PORTA,4     ; I2C Data Estado del Bus
  12. ; NO SE TRABAJA CON BSF NI BCF SOBRE EL PORT !!!!!
  13. ; SE PONEN AMBOS PORT LATCHS EN CERO, PULLUPS EXTERNOS DE 4K7 Y SE TRABAJA CON TRIS
  14. ; Si TRIS es 0 (output) entonces pone cero (lo que tenía en el latch).
  15. ; Si TRIS es 1 (input) entonces deja que el pullup levante a 1(el port queda en High Z)
  16.  
  17. ; EQUIVALENCIAS ***********************************************************************
  18.     TRUE        equ     1
  19.     FALSE       equ     0
  20. ;*************************************************************************************
  21. ;*************************************************************************************
  22. RELEASE_BUS     MACRO    ; pone el port en Output
  23.                 bcf         STATUS,RP0      ; bank 0
  24.                 movf    PORTA,W
  25.                 iorlw   b'00011000'         ; set SCL & SDA to 1
  26.                 movwf   PORTA               ;
  27.                 bsf     STATUS,RP0              ; bank 1
  28.                 bcf     I2C_SDA         ; RA4 as Output high level
  29.                 bcf     I2C_SCL         ; RA3 as Output high level
  30.                 bcf         STATUS,RP0      ; bank 0
  31.                         ENDM                    
  32. ;**************************************************************************************
  33. ;                       SINGLE  MASTER, MULTIPLE SLAVES
  34. ;*************************************************************************************
  35. ;                               I2C Bus Initialization
  36. ;*************************************************************************************
  37. InitI2CBus_Master
  38.         bcf         STATUS,RP0  ; bank 0
  39.         movf    PORTA,W
  40.         andlw   0xE7            ; do not use BSF & BCF on Port Pins
  41.         movwf   PORTA           ; set SDA & SCL to zero. From Now on, simply play with TRIS
  42.         bsf     STATUS,RP0              ; bank 1
  43.                 ; pone el port en Input y deja que actue el pullup externo de 4k7
  44.                 bsf         I2C_SDA                 ; tristate SDA
  45.                 bsf         I2C_SCL                 ; tristate SCL
  46.         return                  ; OJO queda en Bank 1 !!
  47. ;***************************************************************************************
  48. ;                               Send Start Bit
  49. ;***************************************************************************************
  50. SendStartBit
  51.                 bsf         I2C_SDA                 ; set SDA high
  52.                 bsf         I2C_SCL                 ; set SCL high
  53.             call    Delay10uS       ; only necessary for setup time
  54.         bcf         I2C_SDA                 ; give a falling edge on SDA while clock is high
  55.                 call    Delay10uS           ; only necessary for START HOLD time
  56.                 bcf     STATUS,RP0      ; Bank 0
  57.                 return
  58. ;****************************************************************************************
  59. ;                               Send Stop Bit
  60. ;****************************************************************************************
  61. SendStopBit
  62.                 bsf         STATUS,RP0  ; select page 1
  63.                 bcf         I2C_SCL            
  64.                 bcf         I2C_SDA             ; set SDA low
  65.                 bsf         I2C_SCL             ; Clock is pulled up
  66.                 call    Delay10uS
  67.                 bsf         I2C_SDA             ; give a rising edge on SDA while CLOCK is high
  68.                 RELEASE_BUS         ; MACRO
  69.                 return 
  70. ;*****************************************************************************************
  71. ;                               TRANSMIT A BYTE OF DATA
  72. ; The data to be transmitted must be loaded into WREG
  73. ; if successfully transmitted, expect an ACK bit
  74. ;*******************************************************************************************
  75. SendData                        ; send 8 bits & wait for ACK
  76.                 bsf     STATUS,RP0      ; Bank1
  77.                 movwf   DataByte
  78.                 movlw   0x08
  79.                 movwf   BitCount
  80. TxmtNextBit
  81.                 bcf         I2C_SCL         ; set clock low
  82.                 call    Delay10uS
  83.                 rlf     DataByte, F         ; MSB first, Note DataByte Is Lost
  84.         bcf         I2C_SDA
  85.                 btfsc   STATUS,C
  86.                 bsf         I2C_SDA
  87.                 call    Delay10uS
  88.                 bsf         I2C_SCL                 ; set clock high
  89. ; here could check if clock is high, else clock is being stretched
  90.                 call    Delay10uS
  91.                 decfsz  BitCount, F
  92.                 goto    TxmtNextBit
  93. ; Check For Acknowledge
  94.                 bcf         I2C_SCL                 ; set clock low
  95.                 bsf         I2C_SDA                 ; Release SDA line for Slave to pull down
  96.                 call    Delay10uS
  97.                 bsf         I2C_SCL                 ; clock for slave to ACK
  98.                 call    Delay10uS
  99.                 bcf         STATUS,RP0          ; select PAGE 0 to test PortA pin SDA
  100.                 btfsc   _SDA                ; SDA should be pulled low by slave if OK
  101.         goto    ACK_ERROR
  102.                 bcf         STATUS,RP0      ; Bank 0
  103.         retlw   TRUE
  104. ACK_ERROR                       ;Abort Transmission / Send STOP Bit & return (WREG)= FALSE
  105.                 call    SendStopBit
  106.                 RELEASE_BUS
  107.                 retlw   FALSE
  108. ;********************************************************************************************
  109. ;                       General Purpose Delay Routine
  110. ;********************************************************************************************
  111. Delay10uS       ; 2us for the Call + 8 nops + 2us for return = 10us
  112.         NOP
  113.         NOP
  114.         NOP
  115.         NOP
  116.         NOP
  117.         NOP
  118.         NOP
  119.         NOP
  120.         return         
  121. ;********************************************************************************************
Retardos.inc
Código: ASM
  1. ;**************************** Librería "RETARDOS.INC" *********************************
  2. ;
  3. ;       ===================================================================
  4. ;         Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
  5. ;         E. Palacios, F. Remiro y L. López.
  6. ;         Editorial Ra-Ma.  www.ra-ma.es
  7. ;       ===================================================================
  8. ;
  9. ; Librería con múltiples subrutinas de retardos, desde 4 microsegundos hasta 20 segundos.
  10. ; Además se pueden implementar otras subrutinas muy fácilmente.
  11. ;
  12. ; Se han calculado para un sistema microcontrolador con un PIC trabajando con un cristal
  13. ; de cuarzo a 4 MHz. Como cada ciclo máquina son 4 ciclos de reloj, resulta que cada
  14. ; ciclo máquina tarda 4 x 1/4MHz = 1 µs.
  15. ;
  16. ; En los comentarios, "cm" significa "ciclos máquina".
  17. ;
  18. ; ZONA DE DATOS *********************************************************************
  19.  
  20.         CBLOCK  
  21.         R_ContA                         ; Contadores para los retardos.
  22.         R_ContB
  23.         R_ContC
  24.         ENDC
  25. ;
  26. ; RETARDOS de 4 hasta 10 microsegundos ---------------------------------------------------
  27. ;
  28. ; A continuación retardos pequeños teniendo en cuenta que para una frecuencia de 4 MHZ,
  29. ; la llamada a subrutina "call" tarda 2 ciclos máquina, el retorno de subrutina
  30. ; "return" toma otros 2 ciclos máquina y cada instrucción "nop" tarda 1 ciclo máquina.
  31. ;
  32. Retardo_10micros                                ; La llamada "call" aporta 2 ciclos máquina.
  33.         nop                             ; Aporta 1 ciclo máquina.
  34.         nop                             ; Aporta 1 ciclo máquina.
  35.         nop                             ; Aporta 1 ciclo máquina.
  36.         nop                             ; Aporta 1 ciclo máquina.
  37.         nop                             ; Aporta 1 ciclo máquina.
  38. Retardo_5micros                         ; La llamada "call" aporta 2 ciclos máquina.
  39.         nop                             ; Aporta 1 ciclo máquina.
  40. Retardo_4micros                         ; La llamada "call" aporta 2 ciclos máquina.
  41.         return                          ; El salto del retorno aporta 2 ciclos máquina.
  42. ;
  43. ; RETARDOS de 20 hasta 500 microsegundos ------------------------------------------------
  44. ;
  45. Retardo_500micros                               ; La llamada "call" aporta 2 ciclos máquina.
  46.         nop                             ; Aporta 1 ciclo máquina.
  47.         movlw   d'164'                  ; Aporta 1 ciclo máquina. Este es el valor de "K".
  48.         goto    RetardoMicros           ; Aporta 2 ciclos máquina.
  49. Retardo_200micros                               ; La llamada "call" aporta 2 ciclos máquina.
  50.         nop                             ; Aporta 1 ciclo máquina.
  51.         movlw   d'64'                   ; Aporta 1 ciclo máquina. Este es el valor de "K".
  52.         goto    RetardoMicros           ; Aporta 2 ciclos máquina.
  53. Retardo_100micros                               ; La llamada "call" aporta 2 ciclos máquina.
  54.         movlw   d'31'                   ; Aporta 1 ciclo máquina. Este es el valor de "K".
  55.         goto    RetardoMicros           ; Aporta 2 ciclos máquina.
  56. Retardo_50micros                                ; La llamada "call" aporta 2 ciclos máquina.
  57.         nop                             ; Aporta 1 ciclo máquina.
  58.         movlw   d'14'                   ; Aporta 1 ciclo máquina. Este es el valor de "K".
  59.         goto    RetardoMicros           ; Aporta 2 ciclos máquina.
  60. Retardo_20micros                                ; La llamada "call" aporta 2 ciclos máquina.
  61.         movlw   d'5'                    ; Aporta 1 ciclo máquina. Este es el valor de "K".
  62. ;
  63. ; El próximo bloque "RetardoMicros" tarda:
  64. ; 1 + (K-1) + 2 + (K-1)x2 + 2 = (2 + 3K) ciclos máquina.
  65. ;
  66. RetardoMicros
  67.         movwf   R_ContA                 ; Aporta 1 ciclo máquina.
  68. Rmicros_Bucle
  69.         decfsz  R_ContA,F               ; (K-1)x1 cm (cuando no salta) + 2 cm (al saltar).
  70.         goto    Rmicros_Bucle           ; Aporta (K-1)x2 ciclos máquina.
  71.         return                          ; El salto del retorno aporta 2 ciclos máquina.
  72. ;
  73. ;En total estas subrutinas tardan:
  74. ; - Retardo_500micros:  2 + 1 + 1 + 2 + (2 + 3K) = 500 cm = 500 µs. (para K=164 y 4 MHz).
  75. ; - Retardo_200micros:  2 + 1 + 1 + 2 + (2 + 3K) = 200 cm = 200 µs. (para K= 64 y 4 MHz).
  76. ; - Retardo_100micros:  2     + 1 + 2 + (2 + 3K) = 100 cm = 100 µs. (para K= 31 y 4 MHz).
  77. ; - Retardo_50micros :  2 + 1 + 1 + 2 + (2 + 3K) =  50 cm =  50 µs. (para K= 14 y 4 MHz).
  78. ; - Retardo_20micros :  2     + 1     + (2 + 3K) =  20 cm =  20 µs. (para K=  5 y 4 MHz).
  79. ;
  80. ; RETARDOS de 1 ms hasta 200 ms. --------------------------------------------------------
  81. ;
  82. Retardo_200ms                           ; La llamada "call" aporta 2 ciclos máquina.
  83.         movlw   d'200'                  ; Aporta 1 ciclo máquina. Este es el valor de "M".
  84.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  85. Retardo_100ms                           ; La llamada "call" aporta 2 ciclos máquina.
  86.         movlw   d'100'                  ; Aporta 1 ciclo máquina. Este es el valor de "M".
  87.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  88. Retardo_50ms                            ; La llamada "call" aporta 2 ciclos máquina.
  89.         movlw   d'50'                   ; Aporta 1 ciclo máquina. Este es el valor de "M".
  90.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  91. Retardo_20ms                            ; La llamada "call" aporta 2 ciclos máquina.
  92.         movlw   d'20'                   ; Aporta 1 ciclo máquina. Este es el valor de "M".
  93.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  94. Retardo_10ms                            ; La llamada "call" aporta 2 ciclos máquina.
  95.         movlw   d'10'                   ; Aporta 1 ciclo máquina. Este es el valor de "M".
  96.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  97. Retardo_5ms                             ; La llamada "call" aporta 2 ciclos máquina.
  98.         movlw   d'5'                    ; Aporta 1 ciclo máquina. Este es el valor de "M".
  99.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  100. Retardo_2ms                             ; La llamada "call" aporta 2 ciclos máquina.
  101.         movlw   d'2'                    ; Aporta 1 ciclo máquina. Este es el valor de "M".
  102.         goto    Retardos_ms             ; Aporta 2 ciclos máquina.
  103. Retardo_1ms                             ; La llamada "call" aporta 2 ciclos máquina.
  104.         movlw   d'1'                    ; Aporta 1 ciclo máquina. Este es el valor de "M".
  105. ;
  106. ; El próximo bloque "Retardos_ms" tarda:
  107. ; 1 + M + M + KxM + (K-1)xM + Mx2 + (K-1)Mx2 + (M-1) + 2 + (M-1)x2 + 2 =
  108. ; = (2 + 4M + 4KM) ciclos máquina. Para K=249 y M=1 supone 1002 ciclos máquina
  109. ; que a 4 MHz son 1002 µs = 1 ms.
  110. ;
  111. Retardos_ms
  112.         movwf   R_ContB                 ; Aporta 1 ciclo máquina.
  113. R1ms_BucleExterno
  114.         movlw   d'249'                  ; Aporta Mx1 ciclos máquina. Este es el valor de "K".
  115.         movwf   R_ContA                 ; Aporta Mx1 ciclos máquina.
  116. R1ms_BucleInterno
  117.         nop                             ; Aporta KxMx1 ciclos máquina.
  118.         decfsz  R_ContA,F               ; (K-1)xMx1 cm (cuando no salta) + Mx2 cm (al saltar).
  119.         goto    R1ms_BucleInterno               ; Aporta (K-1)xMx2 ciclos máquina.
  120.         decfsz  R_ContB,F               ; (M-1)x1 cm (cuando no salta) + 2 cm (al saltar).
  121.         goto    R1ms_BucleExterno       ; Aporta (M-1)x2 ciclos máquina.
  122.         return                          ; El salto del retorno aporta 2 ciclos máquina.
  123. ;
  124. ;En total estas subrutinas tardan:
  125. ; - Retardo_200ms:      2 + 1 + 2 + (2 + 4M + 4KM) = 200007 cm = 200 ms. (M=200 y K=249).
  126. ; - Retardo_100ms:      2 + 1 + 2 + (2 + 4M + 4KM) = 100007 cm = 100 ms. (M=100 y K=249).
  127. ; - Retardo_50ms :      2 + 1 + 2 + (2 + 4M + 4KM) =  50007 cm =  50 ms. (M= 50 y K=249).
  128. ; - Retardo_20ms :      2 + 1 + 2 + (2 + 4M + 4KM) =  20007 cm =  20 ms. (M= 20 y K=249).
  129. ; - Retardo_10ms :      2 + 1 + 2 + (2 + 4M + 4KM) =  10007 cm =  10 ms. (M= 10 y K=249).
  130. ; - Retardo_5ms  :      2 + 1 + 2 + (2 + 4M + 4KM) =   5007 cm =   5 ms. (M=  5 y K=249).
  131. ; - Retardo_2ms  :      2 + 1 + 2 + (2 + 4M + 4KM) =   2007 cm =   2 ms. (M=  2 y K=249).
  132. ; - Retardo_1ms  :      2 + 1     + (2 + 4M + 4KM) =   1005 cm =   1 ms. (M=  1 y K=249).
  133. ;
  134. ; RETARDOS de 0.5 hasta 20 segundos ---------------------------------------------------
  135. ;
  136. Retardo_20s                             ; La llamada "call" aporta 2 ciclos máquina.
  137.         movlw   d'200'                  ; Aporta 1 ciclo máquina. Este es el valor de "N".
  138.         goto    Retardo_1Decima         ; Aporta 2 ciclos máquina.
  139. Retardo_10s                             ; La llamada "call" aporta 2 ciclos máquina.
  140.         movlw   d'100'                  ; Aporta 1 ciclo máquina. Este es el valor de "N".
  141.         goto    Retardo_1Decima         ; Aporta 2 ciclos máquina.
  142. Retardo_5s                              ; La llamada "call" aporta 2 ciclos máquina.
  143.         movlw   d'50'                   ; Aporta 1 ciclo máquina. Este es el valor de "N".
  144.         goto    Retardo_1Decima         ; Aporta 2 ciclos máquina.
  145. Retardo_2s                              ; La llamada "call" aporta 2 ciclos máquina.
  146.         movlw   d'20'                   ; Aporta 1 ciclo máquina. Este es el valor de "N".
  147.         goto    Retardo_1Decima         ; Aporta 2 ciclos máquina.
  148. Retardo_1s                              ; La llamada "call" aporta 2 ciclos máquina.
  149.         movlw   d'10'                   ; Aporta 1 ciclo máquina. Este es el valor de "N".
  150.         goto    Retardo_1Decima         ; Aporta 2 ciclos máquina.
  151. Retardo_500ms                           ; La llamada "call" aporta 2 ciclos máquina.
  152.         movlw   d'5'                    ; Aporta 1 ciclo máquina. Este es el valor de "N".
  153. ;
  154. ; El próximo bloque "Retardo_1Decima" tarda:
  155. ; 1 + N + N + MxN + MxN + KxMxN + (K-1)xMxN + MxNx2 + (K-1)xMxNx2 +
  156. ;   + (M-1)xN + Nx2 + (M-1)xNx2 + (N-1) + 2 + (N-1)x2 + 2 =
  157. ; = (2 + 4M + 4MN + 4KM) ciclos máquina. Para K=249, M=100 y N=1 supone 100011
  158. ; ciclos máquina que a 4 MHz son 100011 µs = 100 ms = 0,1 s = 1 décima de segundo.
  159. ;
  160. Retardo_1Decima
  161.         movwf   R_ContC                 ; Aporta 1 ciclo máquina.
  162. R1Decima_BucleExterno2
  163.         movlw   d'100'                  ; Aporta Nx1 ciclos máquina. Este es el valor de "M".
  164.         movwf   R_ContB                 ; Aporta Nx1 ciclos máquina.
  165. R1Decima_BucleExterno
  166.         movlw   d'249'                  ; Aporta MxNx1 ciclos máquina. Este es el valor de "K".
  167.         movwf   R_ContA                 ; Aporta MxNx1 ciclos máquina.
  168. R1Decima_BucleInterno          
  169.         nop                             ; Aporta KxMxNx1 ciclos máquina.
  170.         decfsz  R_ContA,F               ; (K-1)xMxNx1 cm (si no salta) + MxNx2 cm (al saltar).
  171.         goto    R1Decima_BucleInterno   ; Aporta (K-1)xMxNx2 ciclos máquina.
  172.         decfsz  R_ContB,F               ; (M-1)xNx1 cm (cuando no salta) + Nx2 cm (al saltar).
  173.         goto    R1Decima_BucleExterno   ; Aporta (M-1)xNx2 ciclos máquina.
  174.         decfsz  R_ContC,F               ; (N-1)x1 cm (cuando no salta) + 2 cm (al saltar).
  175.         goto    R1Decima_BucleExterno2  ; Aporta (N-1)x2 ciclos máquina.
  176.         return                          ; El salto del retorno aporta 2 ciclos máquina.
  177. ;
  178. ;En total estas subrutinas tardan:
  179. ; - Retardo_20s:        2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 20000807 cm = 20 s.
  180. ;                       (N=200, M=100 y K=249).
  181. ; - Retardo_10s:        2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 10000407 cm = 10 s.
  182. ;                       (N=100, M=100 y K=249).
  183. ; - Retardo_5s:         2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  5000207 cm =  5 s.
  184. ;                       (N= 50, M=100 y K=249).
  185. ; - Retardo_2s:         2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  2000087 cm =  2 s.
  186. ;                       (N= 20, M=100 y K=249).
  187. ; - Retardo_1s:         2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) =  1000047 cm =  1 s.
  188. ;                       (N= 10, M=100 y K=249).
  189. ; - Retardo_500ms:      2 + 1     + (2 + 4N + 4MN + 4KMN) =   500025 cm = 0,5 s.
  190. ;                       (N=  5, M=100 y K=249).
  191.  
  192. ;       ===================================================================
  193. ;         Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
  194. ;         E. Palacios, F. Remiro y L. López.
  195. ;         Editorial Ra-Ma.  www.ra-ma.es
  196. ;       ===================================================================

Slave.asm
Código: ASM
  1. ;   XTO_I2C_SLAVE.ASM ----------------------------------------------------
  2.  
  3.   list      p=16F73            
  4.  #include <p16F73.inc>      
  5.    
  6.  __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
  7.       ERRORLEVEL -302
  8.       ERRORLEVEL -305
  9.    
  10.     CBLOCK  0x20
  11.     Direction
  12.     V_max
  13.     RAMP
  14.     FLANK
  15.     Sent_Address
  16.     ENDC
  17.  
  18. reset    ORG     0x000                   ; processor reset vector
  19.          goto    inicio                  ; go to beginning of program
  20.          ORG     0x004                   ; interrupt vector
  21.          goto    SSP_Interrupt                     ;
  22. inicio
  23.         call    Setup
  24.        
  25. Main    
  26.         clrf    PORTB
  27.         call    Retardo_500ms
  28.         movf    Sent_Address,W
  29.         movwf   PORTB       ; muestra lo que hay en el BUFFER
  30.         call    Retardo_500ms
  31.          
  32.         movf    Direction,W
  33.         movwf   PORTB       ; muestra lo que hay en el Direction
  34.         bsf     PORTB,4
  35.         call    Retardo_500ms
  36.          
  37.         movf    V_max,W
  38.         movwf   PORTB       ; muestra lo que hay en el Direction
  39.         bsf     PORTB,5
  40.         call    Retardo_500ms
  41.          
  42.         movf    RAMP,W
  43.         movwf   PORTB       ; muestra lo que hay en el Direction
  44.         bsf     PORTB,6
  45.         call    Retardo_500ms
  46.          
  47.         movf    FLANK,W
  48.         movwf   PORTB       ; muestra lo que hay en el Direction
  49.         bsf     PORTB,7
  50.         call    Retardo_500ms
  51.        
  52.         goto    Main            ; Loop forever.        
  53.  
  54. ; ------------------------------------SUBRUTINAS ------------------------------------------
  55. Setup   ; Initializa variables y registros
  56.    
  57.         banksel PORTB      
  58.         clrf    PIR1
  59.         clrf    SSPBUF
  60.         clrf    PORTB
  61.        
  62.         banksel SSPSTAT
  63.         clrf    SSPSTAT
  64.         clrf    TRISB                   ; PORTB Output
  65.         MOVLW   0xFF
  66.         movwf   TRISC                  ; ALL INPUTS (RC3 & RC4 MUST BE INPUTS)
  67.         bsf     PIE1,SSPIE
  68.        
  69.         banksel PORTC                   ; Bank 0
  70.         bcf     STATUS,C
  71.         movf    PORTC,F                 ; read HW SLAVE Address
  72.         rlf     PORTC,W
  73.         andlw   b'00001110'             ; only RC0, RC1 & RC2 (x2)
  74.        
  75.         banksel SSPADD
  76.         movwf   SSPADD                  ; SW SLAVE ADDRESS <0, 2 ,4 ....,14>
  77.         bsf     INTCON,PEIE            ; Enable all peripheral interrupts
  78.         bsf     INTCON,GIE             ; Enable global interrupts
  79.        
  80.         banksel SSPCON
  81.         movlw   0x36                   ; Setup SSP module for 7-bit address, slave mode
  82.         movwf   SSPCON
  83.         clrf    V_max
  84.         clrf    Direction
  85.         clrf    RAMP
  86.         clrf    FLANK              
  87.         return
  88.  
  89.  ; INCLUDES  *****************************************************************
  90.         #include  <XTO_I2C_SLAVE.inc>      ; subrutinas de manejo de BUS I2C
  91.         #include  <RETARDOS.inc>  
  92.     end
Inc del Slave
Código: ASM
  1. ; ////////////////////// XTO_I2C_SLAVE.INC ////////////////////////////////////////////////
  2. ; VARIABLES LOCALES ******************************************************************
  3.     CBLOCK      
  4.             Master_Index
  5.             SSP_Temp
  6.         ENDC
  7. ; ******************** DEFINICIONES **************************************************
  8.    
  9. ; ******************* SSP INTERRUPT **********************************************
  10. SSP_Interrupt
  11.     banksel PIR1
  12.     btfss   PIR1,SSPIF      ; Is this an I2C interrupt?
  13.     goto    salida_SSP      ; No, salga.
  14. ;---------------------------------------------------------------------
  15. ; The I2C code below checks for 2 states:
  16. ;---------------------------------------------------------------------
  17. ; State 1: I2C write operation, last byte was an address byte.
  18. ; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
  19. ; State 2: I2C write operation, last byte was a data byte.
  20. ; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
  21. ;----------------------------------------------------------------------
  22.         banksel SSPSTAT
  23.         movf    SSPSTAT,W       ; Get the value of SSPSTAT
  24.         andlw   b'00101101'     ; Mask out unimportant bits in SSPSTAT.
  25.         banksel SSP_Temp        ; Put masked value in SSP_Temp
  26.         movwf   SSP_Temp        ; for comparision checking.
  27. State1                          ; Write operation, last byte was an address.
  28.         movlw   b'00001001'     ; buffer is full.
  29.         xorwf   SSP_Temp,W      
  30.         btfss   STATUS,Z        ; Are we in State1?
  31.         goto    State2          ; No, check for next state.....
  32.         banksel SSPBUF          ; Do a dummy read of the SSPBUF.
  33.         movf    SSPBUF,W
  34.         movwf   Sent_Address
  35.         clrf    Master_Index
  36.         goto    presalida_SSP
  37. State2                          ; Write operation, last byte was data,
  38.         movlw   b'00101001'     ; buffer is full.
  39.         xorwf   SSP_Temp,W
  40.         btfss   STATUS,Z        ; Are we in State2?
  41.         goto    Fallo           ; No, check for next state.....
  42.         banksel SSPBUF          ; Get the byte from the SSP.
  43.         btfsc   Master_Index,0    ; first byte?
  44.         goto    second_byte     ; No, goto 2nd byte
  45. first_byte                      ; Direction - SPEED
  46.         movlw   b'00001111'     ; lower nibble V_max DATA
  47.         andwf   SSPBUF,W
  48.         movwf   V_max
  49.         swapf   SSPBUF,W        ; get Direction DATA
  50.         andlw   b'00001111'
  51.         movwf   Direction
  52.         incf    Master_Index,F
  53.         goto    presalida_SSP
  54. second_byte                     ; FLANK - RAMP
  55.         movlw   b'00001111'     ; lower nibble RAMP Data
  56.         andwf   SSPBUF,W
  57.         movwf   RAMP
  58.         swapf   SSPBUF,W        ; get FLANK Data
  59.         andlw   b'00001111'
  60.         movwf   FLANK
  61.         clrf    Master_Index
  62.         goto    presalida_SSP
  63. Fallo                           ; Algo falló
  64.         movlw   0xFF
  65.  
  66. presalida_SSP
  67.        
  68.         banksel SSPSTAT         ; Bank 1
  69.         bcf     SSPSTAT,BF              ; SSPSTAT<0> Buffer Full
  70.         banksel PIR1            ; Bank 0
  71.         bcf     SSPCON,SSPOV    ; SSPCON<6> =0 ----> No Overflow
  72.         bcf     PIR1,SSPIF
  73.        
  74. salida_SSP
  75.         retfie                  ; Return from interrupt.

Muchas gracias. :)
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: Suky en 25 de Noviembre de 2009, 09:50:01
Ok! Adjunto...


Saludos!
Título: Re: I2C Esclavo con un PIC16F73
Publicado por: XTOPIC en 26 de Noviembre de 2009, 11:43:52
No se que pasó , pero no podía acceder a este post en particular (estaba trabado).
Recién bajé el archivo y ya estoy disfrutando de "ver" como funciona esto. A primera vista: Es fantástico!
Vuelvo más tarde con mis comentarios.
Muchas gracias !  :-/