Autor Tema: ayuda con pics 16f84  (Leído 3017 veces)

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

Desconectado raptor200

  • PIC10
  • *
  • Mensajes: 39
ayuda con pics 16f84
« en: 30 de Mayo de 2005, 06:40:00 »
hola a todos.
me puede decir alguien si se pueden conectar dos pics como maestro esclavo por medio de dos calbes de comunicación, estoy atorado y necesito ayuda gracias

Desconectado antoniof

  • Moderadores
  • PIC24F
  • *****
  • Mensajes: 729
RE: ayuda con pics 16f84
« Respuesta #1 en: 30 de Mayo de 2005, 13:18:00 »
Mediante el bus I2C que tiene un pin de datos y otro para el reloj. Tendrás que programar todo el protocolo tanto en el maestro como en el esclavo, ya que los 16F84 no tienen módulo SSP

Desconectado Eggar_Felipe

  • PIC10
  • *
  • Mensajes: 45
RE: ayuda con pics 16f84
« Respuesta #2 en: 02 de Junio de 2005, 01:57:00 »
Antoniof, puedes de favor explicar eso que escribiste con peras y manzanas. De favor, a mi tambien me intereza Giño, o bien me puedes facilitar información sobre eso, algun documento que me puedas enviar o una pag.

Saludos.

Eggar.

Desconectado piriots

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 609
RE: ayuda con pics 16f84
« Respuesta #3 en: 02 de Junio de 2005, 13:48:00 »
La verdad es que a mi tampoco me vindria mal algun ejemplillo de comunicacion I2c master-slave en ccs ya que llevo bastantes intentos sin éxito.

Salu2 y gracias de antemano.

Desconectado cucaracha

  • PIC24H
  • ******
  • Mensajes: 1409
    • CUCAWEB
RE: ayuda con pics 16f84
« Respuesta #4 en: 02 de Junio de 2005, 17:46:00 »
Ahí va un ejemplo para CCS de 2 esclavos y un maestro.


ESCLAVO 1:
Codigo:

///////////////////////////////////////////////////////////////////////////
////                         EX_SLAVE.C                                ////



#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)  // Jumpers: 8 to 11, 7 to 12


#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0)

typedef enum {NOTHING, CONTROL_READ,
              ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;

I2C_STATE fState;
byte address, buffer[0x10];
short chivato_mamon=0;

#INT_SSP
void ssp_interupt ()
{
   byte incoming;/////es donde recibo el byte que me manda

   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {  //i2c_poll() returns false on the
         i2c_write (buffer[address]);//interupt receiving the second
         fState = NOTHING;           //command byte for random read operation
      }
   }
   else {
      incoming = i2c_read();

      if (fState == NOTHING){
         fState = CONTROL_READ;
      }
      else if (fState == CONTROL_READ) {
         address = incoming;
         fState = ADDRESS_READ;
      }
      else if (fState == ADDRESS_READ) {
         buffer[address] = incoming;
         fState = NOTHING;
         chivato_mamon=1;
      }
   }
}


void main ()
{
   int i;

   fState = NOTHING;
   address = 0x00;
   for (i=0;i<0x10;i++)
      buffer = 0x00;

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);
   
   while(1){
      while (chivato_mamon==1) {
         if (buffer[1]==2){
            output_high(pin_d1);
            chivato_mamon=0;
         }
         else if (buffer[1]==3){
            output_low(pin_d1);
            chivato_mamon=0;
         }
      }
   }
}




ESCLAVO 2:
Codigo:
///////////////////////////////////////////////////////////////////////////
////                         EX_SLAVE.C                                ////



#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)  // Jumpers: 8 to 11, 7 to 12


#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xb0)

typedef enum {NOTHING, CONTROL_READ,
              ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;

I2C_STATE fState;
byte address, buffer[0x10];
short chivato_mamon=0;



#INT_SSP
void ssp_interupt ()
{
   byte incoming;/////es donde recibo el byte que me manda

   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {  //i2c_poll() returns false on the
         i2c_write (buffer[address]);//interupt receiving the second
         fState = NOTHING;           //command byte for random read operation
      }
   }
   else {
      incoming = i2c_read();

      if (fState == NOTHING){
         fState = CONTROL_READ;
      }
      else if (fState == CONTROL_READ) {
         address = incoming;
         fState = ADDRESS_READ;
      }
      else if (fState == ADDRESS_READ) {
         buffer[address] = incoming;
         fState = NOTHING;
         chivato_mamon=1;
      }
   }
}


void main ()
{
   int i;

   fState = NOTHING;
   address = 0x00;
   for (i=0;i<0x10;i++)
      buffer = 0x00;

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);

   while(1){
      while (chivato_mamon==1) {
         if (buffer[1]==2){
            output_high(pin_d1);
            chivato_mamon=0;
         }
         else if (buffer[1]==3){
            output_low(pin_d1);
            chivato_mamon=0;
         }
      }
   }

}



MASTER:
Codigo:
#include <16F877.h>
#device adc=8
#use delay(clock=8000000)
#fuses HS, NOWDT, BROWNOUT, NOPUT, NOPROTECT, NOLVP, NOCPD, NOWRT, NODEBUG
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)

#use fast_io(a)
#use fast_io(B)
#use fast_io(C)
#use fast_io(d)
#use fast_io(e)


#int_SSP
SSP_isr()
{
printf("recibo algo    ");
}

void inicializa (){
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_counters(RTCC_INTERNAL,WDT_18MS);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   enable_interrupts(INT_SSP);
   enable_interrupts(global);




   set_tris_a(0b00000000);//1 entrada 0 salida
   set_tris_b(0b00000000);
   set_tris_c(0b00000000);
   set_tris_d(0b00000000);
   set_tris_e(0b00000000);

output_low(pin_d1);

}


void main()
{
byte dato=0;

inicializa ();






//printf("mando     ");


i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x02);// High byte of command
i2c_stop();     // Stop condition

i2c_start();    // Start condition
i2c_write(0xb0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x02);// High byte of command
i2c_stop();     // Stop condition

delay_ms(2000);

i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x03);// High byte of command
i2c_stop();     // Stop condition

i2c_start();    // Start condition
i2c_write(0xb0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x03);// High byte of command
i2c_stop();     // Stop condition

delay_ms(2000);

i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x02);// High byte of command
i2c_stop();     // Stop condition

i2c_start();    // Start condition
i2c_write(0xb0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x02);// High byte of command
i2c_stop();     // Stop condition

delay_ms(2000);

i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x03);// High byte of command
i2c_stop();     // Stop condition

i2c_start();    // Start condition
i2c_write(0xb0);// Device address
i2c_write(0x01);// Low byte of command
i2c_write(0x08);// High byte of command
i2c_stop();     // Stop condition


output_high(pin_d1);
delay_ms(2000);


i2c_start();    // Start condition
i2c_write(0xb0);// Device address
i2c_write(0x01);// Low byte of command
i2c_start();
i2c_write(0xb1);// High byte of command
dato=i2c_read(0);
i2c_stop();     // Stop condition

if(dato==8) output_low(pin_d1);
delay_ms(2000);

i2c_start();    // Start condition
i2c_write(0xa0);// Device address
i2c_write(0x01);// Low byte of command
i2c_start();
i2c_write(0xa1);// High byte of command
dato=i2c_read(0);
i2c_stop();     // Stop condition

if (dato==3){
      output_high(pin_d1);
}


while(1){
}

}



Fué probado en su día, debido a que en Proteus no funcionaba.. Y como el proteus ya me defraudó pues... Nada, que funciona bien montado físicamente.
En el ejemplo podeis ver que viene configurado para usar el puerto serie.. pero nada.. En este ejemplo se dejó con unos simples led para testear. Quitad lo que no os sirva y listo.

Saludos y suerte!!!
Saludos desde Huelva (ESPAÑA)

Desconectado antoniof

  • Moderadores
  • PIC24F
  • *****
  • Mensajes: 729
RE: ayuda con pics 16f84
« Respuesta #5 en: 02 de Junio de 2005, 18:39:00 »
Bueno. Pues para los que programar los PICs en C les suene a chino mandarino como a mi (es mi batalla pendiente), aqui les dejo el protocolo del maestro en asm.
Siento mucho no poder ofreceros el esclavo porque nunca hice un PIC como esclavo I2C, pero seguro que por la red y sobre todo en www.microchip.com hay ruinas para PIC que hagan de esclavo I2C por software.

Codigo:
;SUBRRUTINA "START":
;Realiza la condición de inicio de transmisión del protocolo I2C.      ********* COMPROBADA ********

start   bsf   p_i2c,sda
   bsf   p_i2c,scl
   nop         ;Comprueba que SDA y SCL estén en alto
   bcf   p_i2c,sda
   nop         ;Baja SDA
   bcf   p_i2c,scl
   nop         ;BAJA SCL
   return

;SUBRRUTINA "STOP":
;Realiza la condición de fin de transmisión del protocolo I2C.         ********* COMPROBADA ********

stop   bcf   p_i2c,sda
   bcf   p_i2c,scl
   nop         ;Comprueba que SCL y SDA estén en bajo
   bsf   p_i2c,scl
   nop         ;Sube SCL
   bsf   p_i2c,sda
   nop         ;Sube SDA
   return

;SUBRRUTINA "TX_BYTE": Transmite un byte.
;El byte a transmitir viene en el registro "w".               ********* COMPROBADA ********

tx_byte   movwf   temp1      ;Salva el byte a transmitir en el registro temporal "temp1"
   movlw   0x08
   movwf   temp2      ;Inicializa el contador
bck_txb   bsf   p_i2c,sda   ;Sube sda
   btfss   temp1,7      ;Comprueba el bit y lo baja si es cero
   bcf   p_i2c,sda
   nop         ;Envia el SDA
   bsf   p_i2c,scl
   nop         ;Da un pulso de reloj
   bcf   p_i2c,scl
   nop
   rlf   temp1,f      ;Rotamos a la izquierda "temp1"
   decfsz   temp2,f      ;Comprobamos el contador, para ver si hemos enviado los 8 bits
   goto   bck_txb      ;Si no, repetimos el bucle
   call   rx_ack      ;Espera el envio del ACK
   return         ;Terminamos

;SUBRRUTINA "RX_BYTE": Recibe un byte.
;El byte que es recibido se devuelve en el registro "w".         ********* COMPROBADA ********

rx_byte   movlw   0x08      ;Inicializamos el contador
   movwf   temp2
   bsf   status,5   ;SDA como entrada
   bsf   p_i2c,sda
   bcf   status,5
bck_rxb   bsf   p_i2c,scl   
   nop         ;Subimos SCL
   rlf   temp1,f      ;Rota el registro "temp1", donde vamos a guardar el byte recibido
   bsf   temp1,0      ;Subimos el bit
   btfss   p_i2c,sda   ;Comprobamos que no es cero
   bcf   temp1,0
   bcf   p_i2c,scl
   nop         ;Bajamos SCL
   decfsz   temp2,f      ;Vemos si hemos recivido ya los 8 bits
   goto   bck_rxb      
   bsf   status,5   ;SDA como salida
   bcf   p_i2c,sda
   bcf   status,5
   movf   temp1,w      ;Devolvemos el byte en el registro "w"
   return         ;Fin

;SUBRRUTINA "TX_ACK": Trasmite el bit de reconocimiento "ack".         ********* COMPROBADA ********

tx_ack   bcf   p_i2c,sda
   nop         ;Baja SDA
   bsf   p_i2c,scl
   nop         ;Sube SCL
   bcf   p_i2c,scl
   nop         ;Baja SCL
   bsf   p_i2c,sda      
   nop         ;Sube SDA
   return         ;Fin

;SUBRRUTINA "NO_ACK": Envía un "1" como bit de "ack".            ********* COMPROBADA ********

no_ack   bsf   p_i2c,sda
   nop         ;Sube SDA
   bsf   p_i2c,scl
   nop         ;Sube SCL
   bcf   p_i2c,scl
   nop         ;Baja SCL
   bsf   p_i2c,sda      
   nop         ;Sube SDA
   return         ;Fin

;SUBRRUTINA "RX_ACK": Espera el bit de agradecimiento "ack".         ********* COMPROBADA ********

rx_ack   bsf   status,5   ;SDA como entrada
   bsf   p_i2c,sda
   bcf   status,5
   movlw    d"50"      ;Inicializa el "temp2" que nos sirve de temporizador para no
   movwf   temp2      ;esperar el ACK indefinidamente
   bcf   temp3,7      ;Borra el bit de error
bck_rxa   btfss   p_i2c,sda   ;Espera el ACK
   goto   no_err
   decfsz   temp2,f      ;Decrementa el "temp2"
   goto   bck_rxa
   bsf   temp3,7      ;Si pasa mucho tiempo pone a uno el bit error y sale de la rutina
   bsf   status,5
   bcf   p_i2c,sda   ;SDA como salida
   bcf   status,5
   return         ;Fin
no_err   bsf   p_i2c,scl   ;Si no hay error
   nop         ;Manda un pulso de reloj
   bcf   p_i2c,scl
   nop
   bsf   status,5
   bcf   p_i2c,sda   ;SDA como salida
   bcf   status,5
   return         ;Fin


Las rutinas funcionan perfectamente. Hay que definir tres registros temporales temp1, temp2 y temp3 y definir el puerto que se vaya a utilizar para la comunicación como p_i2c, y los bits del puerto que se vayan a utilizar como sda (para los datos) y scl (para el reloj). Hay va un ejemplo:

Codigo:
sda   equ   0x00   ;Bits de control del bus I2C  en el puerto A
scl   equ   0x01
porta   equ   0x05   ;Define el puerto A
p_i2c   equ   0x05   ;Define el puerto donde esta el bus I2C (Puerto A)
temp1   equ   0x20
temp2   equ   0x21
temp3   equ   0x22

Desconectado piriots

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 609
RE: ayuda con pics 16f84
« Respuesta #6 en: 04 de Junio de 2005, 07:05:00 »
Gracias antoniof, con estos ejemplos me queda mas claro, pero ahun tengo una duda, cuando el maestro escribe, donde pone  //high byte of command  y  //Low byte of command, como funciona esto, es que manda los byte de pacs de 4 bits o como es??

Salu2

Desconectado antoniof

  • Moderadores
  • PIC24F
  • *****
  • Mensajes: 729
RE: ayuda con pics 16f84
« Respuesta #7 en: 04 de Junio de 2005, 18:49:00 »
Cuando el maestro escribe o recibe siempre lo hace en bytes (8 bits consecutivos). Lo que en el ejemplo de cucaracha se refiere, es que la aplicación para la que se ha hecho ese programa necesitará escribir dos comandos, de 8 bits cada uno,  en un dispositivo I2C y por eso pone lo de high y low command, es decir, el dispositivo esclavo, necesitará un comando de 16 bits para realizar una operación en concreto. No se si lo entiendes.

En una aplicación normal, se envía la condición START, luego la dirección del esclavo(que incluye el bit de lectura/escritura), luego se espera por el ACK, luego el/los comandos necesarios para la operación deseada seguidos de sus correspondientes ACKs y, por último, la condición STOP. Tanto la dirección, como los comandos son todos de 8 bits.

Codigo:
up_DSP   call   start      ;Inicio
   movlw   0x68      ;Dirección de dispositivo
   call   tx_byte
   movlw   0x40      ;Dirección del registro que se va a escribir (Analog Control Register)
   call   tx_byte
   movlw   0x00      ;Valor que se escribe en el registro   
   call   tx_byte
   call   stop      ;Fin
   return


En este ejemplo se envia la dirección del esclavo (68H), se envía la deirección del registro que se va a escribir(40H) y se escribe el byte en el registro anterior(00H)

Desconectado piriots

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 609
RE: ayuda con pics 16f84
« Respuesta #8 en: 05 de Junio de 2005, 06:22:00 »
Entendido, pues voy a seguir intentando la comunicacion I2C, que con las explicaciones que hiciste lo veo bastante mas claro.

Gracias de nuevo y salu2