Autor Tema: En una comunicacion I2C como obtengo el resultado en el esclavo?  (Leído 4513 veces)

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

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Hola tengo un programa en base a la comunicacion I2C Maestro-esclavo en el maestro tengo

Código: [Seleccionar]
void envio(direccion, posicion, dato){
   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C
   i2c_write(posicion);    // Posición donde se guardara el dato transmitido
   i2c_write(dato);        // Dato a transmitir
   i2c_stop();             // Fin comunicación
   delay_ms(1000);
 }

en el main tengo

Código: [Seleccionar]
while(true)
   {
     
      if (valor_B == '0')
      {
      envio(0XA0, 0X05, 0); 
      }
           
      if (valor_B == '1')
      {
      envio(0XA0, 0X05, 1);
      }

y creo que lo hace todo bien segun yo... lo que no entiendo es como hacer para que el esclavo aga "algo" segun el valor que le envio el maestro, por ejemplo envie 0 y despues 1 y en el esclavo tengo

Código: [Seleccionar]
byte posicion, buffer[0x10];


#INT_EXT
void ssp_interupt (){
   byte incoming;                //es donde se recibe el byte que manda el maestro
   fstate = i2c_isr_state();     //estado del bus tras la interrupción
   if (fstate == 0x80) {    // Si no hay dato recibido=>lectura del esclavo por el master
     
      //Muestra por LCD valor en posición de memoria solicitada por el master
      //printf (lcd_putc, "\fDireccion I2C=A0\n");
      //printf (lcd_putc, "Pos.%d   Dato= %x"  posicion, buffer[posicion]);
      //Manda al maestro la información contenida en la posición de memoria que le ha solicitado
      i2c_write (buffer[posicion]);
   }
   else {                                 //Sino es que hay dato en el bus I2C...
      incoming = i2c_read();              //... lo lee
      if (fState == NOTHING){             //Información recibida es aviso de que va mandar algo master
         fState = CONTROL_READ;           //Siguiente información será la posición donde guardar dato
      }
      else if (fState == CONTROL_READ) {  //Información recibida corresponde a la posicion
         posicion = incoming;             //Se guarda posición
         fState = ADDRESS_READ;           //Siguiente información recibida será el dato
      }
      else if (fState == ADDRESS_READ) {  //Información recibida corresponde al dato
         buffer[posicion] = incoming;     //Se guarda dato
         fState = NOTHING;                //Siguiente información será aviso de nuevo envío del master
         envio=1;
      }
   }
}

supongo que buffer[posicion] es el encargado de manejar el valor enviado por el master, pero lo recive en byte y como convierto o como comparo un valor en byte? osea 0,1,2,3,4,5,6,7,8,9 con esos numeros para compararlos con los mismos pero en formato byte me conformo pero es ahi donde no tengo idea si compararlos de esta forma:

0==00000000
1==00000001
2==00000010
3==00000011
etc.

si esta es la forma entonces hay algo que no funciona en el codigo...

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #1 en: 07 de Junio de 2015, 02:38:20 »
Por ejemplo hay algunos RTC en los que se define como leer o escribir.

Como la direccion es de 7 bits, utilizan el otro bit para designar si es escritura o lectura.

Entonces haces esto para escribir:

   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C
   i2c_write(posicion);    // Posición donde se guardara el dato transmitido
   i2c_write(dato);        // Dato a transmitir
   i2c_stop();             // Fin comunicación
   delay_ms(1000);


Y para leer:

char recepcion(direccion, posicion){
   char dato_leido;
   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C + bit de Lectura
   dato_leido = i2c_read();        // Dato a leer
   i2c_stop();             // Fin comunicación
   delay_ms(1000);
   return(dato_leido)
 }


es decir se escribe la direccion y la posicion, y se recibe lo que se quiere. Lo que si ademas de eso vas a tener que implementarlo en tu maquina de estados del receptor, es decir cuando entre la direccion y coincida , fijarse el bit de R/W cual es, y ahi crear un nuevo estado de lectura, asi le envia los datos al master.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #2 en: 07 de Junio de 2015, 03:33:15 »

Y para leer:

char recepcion(direccion, posicion){
   char dato_leido;
   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C + bit de Lectura
   dato_leido = i2c_read();        // Dato a leer
   i2c_stop();             // Fin comunicación
   delay_ms(1000);
   return(dato_leido)
 }


porque necesita nuevamente la direcion del esclavo si ya esta implementado en

Código: [Seleccionar]
#use i2c(SLAVE,fast, SDA=PIN_A5, SCL=PIN_A4, address=0xA0, force_hw, stream=I2CS )

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #3 en: 07 de Junio de 2015, 03:50:45 »
Disculpa, pense que seria posible hacerlo de esa forma, en fin vos sos el responsable de armar el protocolo que quieras.

Ejemplo

Start - Direccion - Comando - Registro - Dato

Luego en tu esclavo tendras que hacer la maquina de estado para eso.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #4 en: 07 de Junio de 2015, 09:42:40 »
Disculpame ami por mi ignorancia! entonces es posible hacerlo de esa forma tambien?! yo pensé que el protocolo I2C era más "rigido"

gracias!

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #5 en: 07 de Junio de 2015, 10:32:47 »
Un error del programa es que veo que en muchos codigos usan la interrupcion #INT_SSP pero yo estoy practicando con el pic 12f675 y no se si soy yo que soy muy bruto para esto o si es que no acepta esta interrupcion este pic, lo estoy usando porque creo que acá en Argentina lo puedo conseguir, es muy barato y no necesito ni mucha ram ni mucha rom... ahora puedo obviar esa interrupcion??

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #6 en: 07 de Junio de 2015, 13:05:53 »
Despues de releer el datasheet

El LSB del Address del esclavo corresponde al bit R/W , asi que primero escribis y luego lees.
No se como actuaria ante una segunda condicion de start, pero deberias probar como para elegir el registro y leerlo al mismo tiempo


Citar
char recepcion(direccion, posicion){
   char dato_leido;
   i2c_start();            // Comienzo comunicación
   i2c_write(direccion);   // Dirección del esclavo en el bus I2C + bit de Escritura
   i2c_write(registro);   // Registro a conseguir
   i2c_start();            // Comienzo comunicación
   dato_leido = i2c_read();        // Dato a leer
   i2c_stop();             // Fin comunicación
   delay_ms(1000);
   return(dato_leido)
 }

Recomiendo el uso de las interrupciones, no cuesta nada hacerlo, y el mismo codigo que usarias en tu programa principal pasaria a estar en tu interrupcion, ademas te evitas posibles perdidas de datos.
el INT_SSP es por el MASTER SYNCHRONOUS SERIAL PORT (MSSP) MODULE

Si no lo tiene debe estar bajo otro nombre. O no tiene I2C y tendrias que implementarlo por soft que seria un dolor de cabeza o requiere que sepas bien el protocolo.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #7 en: 07 de Junio de 2015, 13:26:17 »
Encima que estoy engripado  :5] me estoy rompiendo la cabeza con esto! es como tú dices, este pic para el protocolo I2C es un dolor de cabeza! me recomiendas uno que sea facil de conseguir y que pueda usar #INT_SSP y que no sea muy caro? el ultimo punto es muy importante  :mrgreen:
« Última modificación: 07 de Junio de 2015, 13:58:08 por MINDFIELD »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #8 en: 07 de Junio de 2015, 15:25:33 »
El PIC que decis, vi el datasheet y no posee modulo I2C, lo cual o usas un I2C por software o te conseguis otro con I2C.

Que PIC seleccionar ? el que te sirva para las cosas que pensas hacer. Tu idea es hacerlo para aprender ? entonces yo buscaria un PIC con muchos pines y varios modulos asi de esa forma lo podes usar para multiple proyectos y no te quedas sin pines como un 16f887 que tiene 40 pines, O si queres USB un PIC18F4550  tambien 40 pines (Ambos modelos viejos y seguro que hay algun reemplazo con las mismas caracteristicas y menor precio). Y con un solo PIC podes usarlo para varios proyectos, lo cual no tendrias que comprar un PIC para cada cosa

Ahora si tu problema es del tema economico por que pensas hacerlo para venderlo o no pensas reutilizar ese PIC, entonces lo primero que hago es irme a la pagina de Microchip y buscar un PIC que cumple con esas caracteristicas, Con un I2C, si utilizo SPI voy a tener que buscar alguno en que pueda usar ambos, o que tenga 2 modulos SSP, Si necesito USB entonces buscas algo tambien con USB, ahi te van a salir todos y el precio por 1000, lo cual es una relacion casi directa al precio unitario.
Pero ahi no termina, luego tenes que buscar en las casas de electronica de donde vivis por si es posible conseguir ese modelo o lo mas barato que tiene. Y si cumplen con lo que necesitas.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #9 en: 07 de Junio de 2015, 16:50:32 »
Gracias KILLERJC! sin animo de ofender pero pareces cartel de la coca... estas en todos lados  :mrgreen: gracias  de nuevo!

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #10 en: 07 de Junio de 2015, 21:18:25 »
Bueno pude hacer la comunicacion i2c y en la primer prueba con un micro 16f887 (maestro) y 16f887(esclavo) me fue bien, el unico problemita es que envio desde el maestro supongamos el numero 5 y el esclavo lo reconoce, si vuelvo a enviar el mismo numero no lo reconoce pero si lo envio de nuevo si lo reconoce, osea me reconoce el numero 5 intercaladamente la primera si la segunda no la tercera si la cuarta no etc. pongo el codigo del maestro y del esclavo aver con que me tiran de la oreja  :D

maestro:
Código: [Seleccionar]
#include <16F887.h>
#fuses PUT,NOWDT,NOPROTECT,INTRC_IO,NOLVP
#use delay (clock=4000000)                     
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,STREAM=PORT1,ERRORS)
#use i2c(MASTER,fast, SDA=PIN_C4, SLOW, SCL=PIN_C3)//MAESTRO
#bit control=0x05.0
#use standard_io(a)
#use standard_io(c)

int8 grados=90,grados2=90; //grados solo de 0-254
byte dato;
byte esclavo; //0xa0 esclavo de motor a pasos 0xb0 esclavo de motor DC
char valor_B;

   
void envio_I2C (void) //Funcion de I2C
{
  i2c_start();         //Comienzo de la comunicación I2C ...
  i2c_write(esclavo);     //...con la dirección del PIC esclavo...
  i2c_write(dato);      // Envia dato
  i2c_stop();          //Finalización de la transmisión
  delay_ms(100);
}


/******************************************************************************/
/*************************** FUNCIÓN PRINCIPAL ********************************/

void main(void)
{
  setup_oscillator(OSC_4MHZ);
  set_tris_a(0xFF);   
      while (true)
        {

 valor_B=getc();
   
      if (valor_B == '0')
      {
      dato=0;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
           
      if (valor_B == '1')
      {
      dato=1;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '2')
      {
      dato=2;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '3')
      {
      dato=3;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '4')
      {
      dato=4;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '5')
      {
      dato=5;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '6')
      {
      dato=6;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '7')
      {
      dato=7;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '8')
      {
      dato=8;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
     
      if (Valor_B == '9')
      {
      dato=9;
      esclavo=0xa0; //primer esclavo
      envio_I2C();
      }
   }
}



esclavo:
Código: [Seleccionar]
#include <16F887.h>
#fuses PUT,NOWDT,NOPROTECT,INTRC_IO
#use delay (clock=4000000)
#use standard_io(b)
#use fast_io(C)
#use fast_io(D)
#use I2C(SLAVE, fast,SDA=PIN_C4 , SCL=PIN_C3, ADDRESS=0xa0, force_hw, stream=I2CS)
//#include <lcd.c>
//#bit ba=0x07.5 // color amarillo 1a
//#bit bb=0x07.4 // color rojo 1b
//#bit la=0x07.3 // color cafe 2a
//#bit lb=0x07.6 //color naranja
#byte control=0x06
   int8 grado;
   int pasos;
   int cont=0,i;
byte const sentido [4]={0x28,0x60,0x50,0x18};//00101000,01100000,01010000,00011000   



#int_ssp
ssp_isr(void){
     while(true){
     BYTE state, incoming;
      state = i2c_isr_state();

if(i2c_read(0x05)==5)
         {
         
         output_high(pin_b2);
         delay_ms(200);
         output_low(pin_b2);
         delay_ms(200);
         }
         else
         output_low(pin_b2);

   }
}
void main(void) {
setup_oscillator(OSC_4MHZ); 
set_tris_b(0x00);
control=0;
//lcd_init(); 
enable_interrupts(global);
enable_interrupts(int_ssp);
//printf(lcd_putc, "Esperando dato...\n"); 
 
   while (TRUE)
   {
   
     
   }
   }

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #11 en: 07 de Junio de 2015, 23:08:51 »
No vi mucho el codigo.

Solo pare al mirar que tenias un while(true) dentro de tu rutina de interrupcion.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #12 en: 08 de Junio de 2015, 20:07:46 »
asi funciona y si lo saco tambien, pero solo funciona un esclavo, ademas el compilador me tira un warning que dice funcion not void and does not return a value ssp_isr porque?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #13 en: 08 de Junio de 2015, 21:54:17 »
No podes poner un while(true) dentro de una interrupcion. El por que ? por que es lo mas basico que puede haber de una interrupcion, vos queres que se atienda rapidamente, y luego continue con el programa, si pones eso dentro de la interrupcion queda atrapado dentro de la misma para siempre.

Lo del void es por esto:


ssp_isr(void){

Cambialo a

void ssp_isr(void){

Imagino que al no definirlo espera que se devualve algun valor, por eso mismo te pide que uses el return.

Desconectado MINDFIELD

  • PIC16
  • ***
  • Mensajes: 139
Re: En una comunicacion I2C como obtengo el resultado en el esclavo?
« Respuesta #14 en: 08 de Junio de 2015, 22:43:19 »
hice lo que digiste, no me di cuenta del void y saque el while, pero con 2 esclavos solo funciona la primera ves pero hace lo mismo en los dos esclavos aunque tengan distintas direcciones y despues no hace nada como si los dos esclavos se quedara en algun while, si solo trengo un solo esclavo anda bien, revise todo pero algo se me escapa, que consejo me puedesdar? seran los fuses??

pic: 16f887

maestro: #fuses PUT,WDT,NOPROTECT,INTRC_IO,NOLVP
#use delay (clock=4000000)                    
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,STREAM=PORT1,ERRORS)
#use i2c(MASTER,fast, SDA=PIN_C4, SLOW, SCL=PIN_C3, force_sw, stream=i2cM)//MAESTRO
#bit control=0x05.0
#use standard_io(a)
#use standard_io(c)

esclavos1: #fuses PUT,WDT,NOPROTECT,INTRC_IO
#use delay (clock=4000000)
#use standard_io(b)
#use fast_io(C)
#use fast_io(D)
#use I2C(SLAVE, fast,SDA=PIN_C4 , SCL=PIN_C3, ADDRESS=0xb0, noforce_sw)


esclavo2: #fuses PUT,WDT,NOPROTECT,INTRC_IO
#use delay (clock=4000000)
#use standard_io(b)
#use fast_io(C)
#use fast_io(D)
#use I2C(SLAVE, fast,SDA=PIN_C4 , SCL=PIN_C3, ADDRESS=0xa0, noforce_sw)

no entiendo porque con uno solo anda bien y con dos no o serán las resistencias, tengo 2 de 10k conecectadas al i2c
« Última modificación: 08 de Junio de 2015, 22:45:45 por MINDFIELD »


 

anything