Autor Tema: Comunicación con I2C de Master a distintos Slaves  (Leído 3400 veces)

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

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Comunicación con I2C de Master a distintos Slaves
« en: 02 de Agosto de 2006, 07:06:29 »
Hola a todos, es la primera vez que escribo en el foro pero ya hace tiempo que merodeo por aquí. Primero que todo quiero felicitar a todos los del foro, es genial que haya gente como vosotros dispuestos a compartir todo, ojala yo también pueda ayudar con lo que pueda!

Estoy haciendo un proyecto para la universidad, es un control de riego monitorizado vía GSM. El problema en que me encuentro ahora es con el bus I2C, os explico: Tengo una pic central que me hace de master i otras 6 Pics que son los sensores, estas las tengo con slave. Mi problema es que con una sola pic slave todo me funciona perfectamente, cuando conecto las otras pics slaves todo sigue funcionando perfectamente hasta que intento leer los datos de otra pic slave que no sea la inicial. Me explico, inicio el programa (lo estoy simulando con proteus) i todo funciona a la perfección (me llegan los datos de la pic slave a la master perfectamente) la master pide a la slave que le mande el dato y llega sin problemas, el problema me lo encuentro cuando quiero leer de otra pic slave, cambio al address de la nueva slave i el sistema se que queda tirado, a la master no le llega nada... A alguien se le ocurre que puede pasar?¿

He estado haciendo pruebas y creo que el problema esta en el 0 del i2c_read(0); en el código del master. Tengo entendido que un 0 significa que el sistema funciona sin ACK i que con un 1 con ACK (sin nada es por defecto un 1). No se muy bien por que pero cuando pongo un 0 funciona solo con un slave y si pongo cualquier orto valor no me funciona. Es como si la master se quedara esperando que la slave le diera un ACK i no hace nada mas. Alguien sabe como hacer el ACK desde el salve?¿

Espero que alguien me pueda dar una mano... os pongo el código a bajo:


MASTER

#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,LVP
#use delay(clock=4000000)
#use i2c(MASTER, sda=PIN_C4, scl=PIN_C3,FAST,FORCE_HW)


void init_slave(){
   output_float(PIN_C3);
   output_float(PIN_C4);
}

//Esta rutina lee un byte desde el esclavo.
//chadd es la direccion del esclavo 0-7 (0xA0 hasta 0xA7).
//address es la posicion de memoria.
//La función devuelve el byte leido.
byte read_slave(byte chadd) {
  byte data;
   //chadd = (chadd<<1) + 0xa0;
   
   i2c_start();
   //chadd = chadd | 1;
   i2c_write(chadd);
   data=i2c_read(0);
   i2c_stop();
   delay_us(50);



   return(data);
}

void MostraDada(int dada){
   set_tris_b(0b00000000); // todo el puerto B como salidas.
   delay_ms(25);
   output_b(dada);
   delay_ms(500);
}


byte QuinSensor(){
   byte adressasensor=0;
   
   switch(input_d()){
      case 1: adressasensor=0xa1;
            output_high(PIN_A0);
            break;
      case 2: adressasensor=0xb1;
            output_high(PIN_A1);
            break;
      case 4: adressasensor=0xc1;
            output_high(PIN_A2);
            break;
      case 8: adressasensor=0xd1;
            output_high(PIN_A3);
            break;
      case 9: adressasensor=0xe1;
            output_high(PIN_A4);
            break;
      case 10: adressasensor=0xf1;
            output_high(PIN_A5);
            break;
      default:
            break;
   }
   return adressasensor;
}

void main(){

   int dada_llegida=4;
   byte num_sensor=1;

   set_tris_b(0b00000000); // todo el puerto B como salidas.
   set_tris_c(0b10000000); // RX como entrada, el resto salidas.
   set_tris_d(0b11111111);   // com entrades '1'
   set_tris_a(0b00000000);   //com a sortides

   init_slave();

   while(TRUE){
   num_sensor=QuinSensor();
   dada_llegida=read_slave(num_sensor);       //Leer el byte en la posicion 0 del esclavo.
   MostraDada(dada_llegida);
   }

}


SALVE

#include <16F876.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use delay(clock=4000000)
#use fast_io(b)

#use I2C(slave,sda=PIN_C4,scl=PIN_C3, ADDRESS=0xa0,FAST,FORCE_HW)   //defineixo el bus I2C en mode slave i adressa 0xa0

int llegit;

#INT_SSP
void ssp_interupt(){

   BYTE state,incoming,address;

   state = i2c_isr_state();

   if(state < 0x80)                     //Master is sending data
   {
   }

   if(state == 0x80)                     //Master is requesting data
   {
      i2c_write(llegit);
   }

}


void LlegeixADC(){
      setup_adc (adc_clock_div_32);      //activem el ADC amb
      setup_adc_ports (RA0_RA1_RA3_ANALOG);   //Configurem els ports analogics; RA0 RA1 i el voltatge de referència 5V
      set_adc_channel (0);      //escollim el canal a mesurar
   
      delay_us(20);            //esperem 20us
      llegit=read_adc();         //fem la conversió

      output_b(llegit);

      setup_adc(adc_off);         //apaguem ADC   

}

void main(void){


   set_tris_b(0b00000000);         // todo el puerto B como salidas.
   //set_tris_c(0b10011000);         // RX, SDA y SCL como entradas, el resto salidas.

   output_float(PIN_C3);         //I2C pin float
    output_float(PIN_C4);         //I2C pin float

   //Habilito interrupcions del port I2C.
   enable_interrupts(INT_SSP);
   // Habilito interrupcions Generals
   enable_interrupts(GLOBAL);


   output_b(0xff);


   while(TRUE){

      LlegeixADC();      

   }

   
}

Desconectado JavisusII

  • PIC12
  • **
  • Mensajes: 79
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #1 en: 02 de Agosto de 2006, 07:33:50 »
uhmmm.. que manía con el i2c

con lo fácil de utilizar y lo bien que va el spi  :mrgreen:

Es broma Andreuf, felicidades por el proyecto y adelante.. :D

Xavi (Barcelona)

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #2 en: 02 de Agosto de 2006, 08:47:05 »
Ups el spi?¿ a ver JavisusII... no tengo ni idea de cual es... infórmame un poco. Funciona bien con la PIC16f877?¿

La verdad és que me da igual cual utilizar... asi que :-)

Por cierto, ya puestos la comunicación final que yo necesito hacer és por RF, así que si sabes de algún bus (protocolo) que ya me sirviera para esta comunicación pues mejor!! Creo que utilizare para la RF los módulos de CEVEK (si no hay una propuesta mejor...)que ya he usado alguna otra vez.

Gracias por contestas!! :-/

Desconectado JavisusII

  • PIC12
  • **
  • Mensajes: 79
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #3 en: 02 de Agosto de 2006, 13:54:54 »
Buenas Andreuf ,

Nada pues, mientras los expertos en ccs y tu pic vienen para ayudarte.....

Un par de preguntas:

- El master y los esclavos están separados físicamente ?
- Cuando hablas de comunicación final, te refieres a la de los actuadores?
- Realmente necesitas una comunicación I2C ,spi?, o puede ser otra, piensalo.
- Hablas de GSM, expones un poco de código, cabe pensar que a lo mejor
  te estás precipitando?


Tampoco me hagas mucho caso, es sólo para hacer un poco de tiempo.

De todas formas, felicidades por tu proyecto y por compartirlo con el foro.

Saludos
 


Xavi (Barcelona)

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #4 en: 02 de Agosto de 2006, 15:52:06 »
A ver JavisusII creo que no me he explicado bien.

A la pregunta:
- El master y los esclavos están separados físicamente ?
Están separados físicamente dentro de una placa de circuito impreso. Si lo preguntas por las distancias no hay problema!

- Cuando hablas de comunicación final, te refieres a la de los actuadores?
Digo comunicación final queriendo decir que mi aplicación real no será vía bus I2C, sino vía RF. Pero primero empezaba haciendo pruebas para poder diseñar el control PID (control de riego) sin tener que estar pendiente de la comunicación RF que lo dejare para el final.
La aplicación real seria con los sensores distribuidos por el campo... de manera que no hay contacto físico entre el nodo central (PIC16F877) i el los sensores (PIC16F876). Entonces la comunicación entre ellos será RF. Pero de eso me encargare luego.

- Realmente necesitas una comunicación I2C ,spi?, o puede ser otra, piensalo.
Realmente la comunicación no tiene que ser I2C ni spi, tiene que ser RF. Que lo haga ahora con I2C es solo para hacer pruebas. Por eso realmente me da igual que protocolo utilizar solo con que pueda comunicar 1a PIC15F877 i 6 PIC16F876 de manera fácil y eficaz!

- Hablas de GSM, expones un poco de código, cabe pensar que a lo mejor te estás precipitando?
No se muy bien a que te refieres con esto. Solo he puesto este trozo de código (que és el de la comunicación entre las PICs) por que voy haciendo las cosas por partes... cuando tenga el PID ya me pondré con el GSM (aun que ya lo tengo todo mas o menos preparado...)

En definitiva si sabes decirme como puedo comunicar 1a PIC master con 6 Slaves te estare muy agradecido!

Gracias por tu rapidez! espero que todo haya quedado un poco mas claro!

Desconectado Manofwar

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 156
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #5 en: 02 de Agosto de 2006, 16:23:34 »
Hola Andreu

Yo estoy mirando un poquito el C y además no se mucho del I2C, así que probablemente diga una estupidez pero bueno, ¿Cada Slave tiene dirección propia verdad? Lo digo por si se te olvidó cambiar la dirección a la hora de grabar cada PIC Slave y los grabaste todos con la misma.

He visto tu proyecto en tu blog y si me admites una sugerencia, yo haría la presentación en el display por software ya que te sobran pines en los Pics y te ahorrarias el decodificador a 7 segmentos.

Saludos y suerte.
Saludos desde Almería, España

Desconectado JavisusII

  • PIC12
  • **
  • Mensajes: 79
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #6 en: 02 de Agosto de 2006, 16:38:11 »
Gracias andreu , ahora me queda más claro.

El proyecto es más bien sencillo.

Ciertamente no te puedo ayudar, pues no conozco ni el pic que utilizas ni este tipo de comunicación.(I2C).

pero pronto aparecerán  expertos que te echarán una mano.

Saludos. :-)
Xavi (Barcelona)

Desconectado jfh900

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3595
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #7 en: 02 de Agosto de 2006, 17:05:26 »
Podemos aclarar algunos conceptos que parece que no estan claros. El ACK se envia despues de una lectura para aceptar los datos, de tal forma que leemos y pasamos como parámetro "0" si no queremos enviar el ACK y "1" si enviamos el ACK. En la función de escritura recibimos el ACK si le hemos enviado en la lectura como una devolución de la función.

Un ejemplo:

En el envio =>

#define ACK 0

if (i2c_write(dato)==ACK)
   .... Código correcto
else
   .... Código erroneo

En la lectura =>

valor = i2c_read(ACK);

Esto se puede utilizar para realizar funciones de sincronización, podemos enviar y leer varios datos y cuando recivamos el ACK terminamos.

Un saludo
* Cuando hables, procura que tus palabras sean mejores que el silencio.
* 'Todos somos ignorantes, lo que ocurre es que no todos ignoramos las mismas cosas.' Albert Einstein.
* No hay nada peor que un experto para evitar el progreso en un campo
* "La vida es como una novela. No importa que sea larga, sino que esté bien narrada" Seneca
* La vida no se vive por las veces que respiras, sino por los momentos que dejan sin aliento.
* Dios dijo: ∇·E=ρ/ε0 ; ∇·B=0 ; ∇xE=-dB/dt ; ∇xB= μ0ε0dE/dt..y la luz se hizo..!!..

Desde España Jesús

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #8 en: 03 de Agosto de 2006, 07:44:49 »
A ver voy a responder por partes, aun que primero que todo os agradezco vuestra ayuda!!

Manofwar
Respondiendo a tu primera pregunta, si que he puesto una dirección distinta a cada slave, aquí solo he colgado el código de uno por que todos son iguales, gracias por la observación pero esto lo tengo controlado. Las direcciones que les he puesto son: 0xa1, 0xb1, 0xc1... y asi sucesivamente.

A tu segunda sugerencia; ya se que lo del 7segment es un poquito cutre... pero solo lo hecho para poder ver si se enviaban bien los datos, no por otra cosa, luego eso al final no creo que lo ponga. Lo del LCD si que tengo previsto ponerlo (de hecho en eso estoy trabajando ahora mismo) pero solo en el master (el nodo central) en el cual también irá un teclado matricial, en los sensores no tiene sentido por que lo único que hacen es leer el sensor y mandar lo leyendo al master no tienen que interactuar con las personas.

JavisusII
Gracias JaviusII por tu interés! a lo mejor si que me puedes ayuda mas adelante!

jfh900
A ver jfh900, lo que me dices creo que ya lo tenia claro, el problema es como lo aplico yo a mi código. Tu ejemplo donde iría, al slave?¿ dentro de la interrupción?¿ Entonces la secuencia de eventos seria:

-el master hace i2c_start();
-escribe la dirección del slave con el último bit a 1 para que el slave sepa que queremos leer de el.
-el slave le llega un interrupción por SSP, mira si es de lectura para el y hace un if(i2c_write(dato)==ACK) si llega el ACK del master "Código correcto" salimos de la interrupción y todo bien. Pero si es "Código incorrecto" que se supone que tengo que hacer?¿ salir de la interrupción igualmente sabiendo que no le ha llegado el dato al master?¿ volver a mandar el dato?¿
-al master hace un i2c_read(ACK); y espera a que le llegue bien el dato. Si no le llega bien?¿
-el master hace i2c_strop(); y sigue ejecutando el programa...

El problema que yo tengo, no es exactamente este, como he dicho mi código funciona perfectamente mientras este leyendo datos de un solo slave (por ejemplo el de la dirección 0xa1) eso siempre funciona bien, el problema es cuando quiero leer de otro slave (por ejemplo el de la dirección 0xb1) lo único que hago es que cuando empiezo la conexión hago el i2c_start(); y en vez de mandar la dirección 0xa1 mando con el i2c_write(); siguiente la dirección 0xb1. Luego el master pasa a esperar el dato que le tiene que llegar del slave 0xb1 pero esto nunca sucede... el master se queda allí tirado...
Quiero comentar tb que si pongo en el master i2c_read(1); no funciona de ninguna forma... el master se queda allí esperando algo... o no se...

A ver si lo solucionamos entre todos, y gracias!!

Desconectado jfh900

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3595
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #9 en: 03 de Agosto de 2006, 11:08:53 »
Llegado a este punto seria interesante que postearas el código para poder estudiarlo.

Un saludo
* Cuando hables, procura que tus palabras sean mejores que el silencio.
* 'Todos somos ignorantes, lo que ocurre es que no todos ignoramos las mismas cosas.' Albert Einstein.
* No hay nada peor que un experto para evitar el progreso en un campo
* "La vida es como una novela. No importa que sea larga, sino que esté bien narrada" Seneca
* La vida no se vive por las veces que respiras, sino por los momentos que dejan sin aliento.
* Dios dijo: ∇·E=ρ/ε0 ; ∇·B=0 ; ∇xE=-dB/dt ; ∇xB= μ0ε0dE/dt..y la luz se hizo..!!..

Desde España Jesús

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #10 en: 03 de Agosto de 2006, 11:49:13 »
ok jfh900 aki va el código con las modificaciones y sigue sin funcionar, es poner el uno en i2c_read(1); y el master se queda colgado... de todos modos voy a poner el codigo otra vez para verlo mejor:

MASTER

#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,LVP
#use delay(clock=4000000)
#use i2c(MASTER, sda=PIN_C4, scl=PIN_C3,FAST,FORCE_HW)


void init_slave(){
   output_float(PIN_C3);
   output_float(PIN_C4);
}

//Esta rutina lee un byte desde el esclavo.
//chadd es la direccion del esclavo 0-7 (0xA0 hasta 0xA7).
//address es la posicion de memoria.
//La función devuelve el byte leido.
byte read_slave(byte chadd) {
  byte data;
   //chadd = (chadd<<1) + 0xa0;
   
   i2c_start();
   //chadd = chadd | 1;
   i2c_write(chadd);
   data=i2c_read(1);
   i2c_stop();
   delay_us(50);



   return(data);
}

void MostraDada(int dada){
   set_tris_b(0b00000000); // todo el puerto B como salidas.
   delay_ms(25);
   output_b(dada);
   delay_ms(500);
}


byte QuinSensor(){
   byte adressasensor=0;
   
   switch(input_d()){
      case 1: adressasensor=0xa1;
            output_high(PIN_A0);
            break;
      case 2: adressasensor=0xb1;
            output_high(PIN_A1);
            break;
      case 4: adressasensor=0xc1;
            output_high(PIN_A2);
            break;
      case 8: adressasensor=0xd1;
            output_high(PIN_A3);
            break;
      case 9: adressasensor=0xe1;
            output_high(PIN_A4);
            break;
      case 10: adressasensor=0xf1;
            output_high(PIN_A5);
            break;
      default:
            break;
   }
   return adressasensor;
}

void main(){

   int dada_llegida=4;
   byte num_sensor=1;

   set_tris_b(0b00000000); // todo el puerto B como salidas.
   set_tris_c(0b10000000); // RX como entrada, el resto salidas.
   set_tris_d(0b11111111);   // com entrades '1'
   set_tris_a(0b00000000);   //com a sortides

   init_slave();

   while(TRUE){
   num_sensor=QuinSensor();
   dada_llegida=read_slave(num_sensor);       //Leer el byte en la posicion 0 del esclavo.
   MostraDada(dada_llegida);
   }

}

SLAVE
#include <16F876.h>
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use delay(clock=4000000)
#use fast_io(b)

#use I2C(slave,sda=PIN_C4,scl=PIN_C3, ADDRESS=0xa0,FAST,FORCE_HW)   //defineixo el bus I2C en mode slave i adressa 0xa0

int llegit;

#INT_SSP
void ssp_interupt(){

   BYTE state;

   state = i2c_isr_state();

   if(state < 0x80)                     //Master is sending data
   {
   }

   if(state == 0x80)                     //Master is requesting data
   {
      if(i2c_write(llegit)== 0){
         //transmissió OK
      }else{
         //transmissió fallada!!
      }
   }

}


void LlegeixADC(){
      setup_adc (adc_clock_div_32);      //activem el ADC amb
      setup_adc_ports (RA0_RA1_RA3_ANALOG);   //Configurem els ports analogics; RA0 RA1 i el voltatge de referència 5V
      set_adc_channel (0);      //escollim el canal a mesurar
   
      delay_us(20);            //esperem 20us
      llegit=read_adc();         //fem la conversió

      output_b(llegit);

      setup_adc(adc_off);         //apaguem ADC   

}

void main(void){


   set_tris_b(0b00000000);         // todo el puerto B como salidas.
   //set_tris_c(0b10011000);         // RX, SDA y SCL como entradas, el resto salidas.

   output_float(PIN_C3);         //I2C pin float
    output_float(PIN_C4);         //I2C pin float

   //Habilito interrupcions del port I2C.
   enable_interrupts(INT_SSP);
   // Habilito interrupcions Generals
   enable_interrupts(GLOBAL);


   output_b(0xff);


   while(TRUE){

      LlegeixADC();      

   }

   
}

Desconectado jfh900

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3595
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #11 en: 03 de Agosto de 2006, 13:14:01 »
Mirando el código por encima hay que hacer alguna aclaración. Los esclavos solo pueden tener direcciones pares, ya que las impares corresponden al mismo esclavo que la par pero para lectura. Por ejemplo el esclavo "A0" es su dirección para escritura y "A1" su dirección para lectura. Como leería un master la información del esclavo:

i2c_start();
i2c_write(0xa0); // Le comunicamos al esclavo que nos dirigimos a el en modo escritura
i2c_write(0x00); // Seleccionamos el registro 0 implementado en el esclavo.
i2c_start();
i2c_write(0xa0+1); // Le comunicamos al esclavo que nos dirigimos al el en modo lectura
value=i2c_read(1); // Leemos y le devolvemos un ACK
i2c_stop();

Mediante este sistema leemos un registro virtual (registro 0) implementado en el esclavo. Si solo quieres leer quita las 3 primeras instrucciones.

Un saludo.
« Última modificación: 03 de Agosto de 2006, 13:16:11 por jfh900 »
* Cuando hables, procura que tus palabras sean mejores que el silencio.
* 'Todos somos ignorantes, lo que ocurre es que no todos ignoramos las mismas cosas.' Albert Einstein.
* No hay nada peor que un experto para evitar el progreso en un campo
* "La vida es como una novela. No importa que sea larga, sino que esté bien narrada" Seneca
* La vida no se vive por las veces que respiras, sino por los momentos que dejan sin aliento.
* Dios dijo: ∇·E=ρ/ε0 ; ∇·B=0 ; ∇xE=-dB/dt ; ∇xB= μ0ε0dE/dt..y la luz se hizo..!!..

Desde España Jesús

Desconectado Andreufr

  • PIC10
  • *
  • Mensajes: 19
    • Automatic water with Remote monitoring & Control
Re: Comunicación con I2C de Master a distintos Slaves
« Respuesta #12 en: 03 de Agosto de 2006, 15:32:41 »
ok jfh900 esto es exatamente lo que hago... pero no funciona. Cuando pongo el 1 al i2c_read(1); se me cuelga el master.

Lo de las direcciones de los slaves lo tengo claro, como yo solo leo del slave mis direccones siempre sera impares!

Yo creo que el problema mas bien esta en el slave. He estado buscando ejemplos por aqui pero casi todo es de masters ya que los slaves (como las EEPROMS o los ADC) ya vienen con el código de fabrica.

La verdad es que ya estoy un poco desesperado con esto... no se ya que hacer...


 

anything