Comunicación I2C entre PICs y USB

Hola:
Verán, estoy utilizando 2 pic: el que llamo B, el esclavo, lee una variable analogica y la almacena en un registro. El otro PIC, el A, es el maestro. El maestro lee otra variable analogica y a la vez, se comunica por I2C con el B para leer la variable analogica que leyó. cuando tiene las 2 variables, las envia por USB al PC. El caso es que la variable que lee el propio A, sí que me la envía por USB, pero la del B no la lee, es como si no llegase a solicitar la lectura el Master al Slave. Sin embargo, todo este mismo codigo pero sin comunicacion USB si que la lee el Master del Slave.
Pego los códigos de ambos pic por si alguien me puede ayudar:

MASTER (A)

Código:
#include <18F2455.h>
#device ADC=8
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)

#DEFINE USB_HID_DEVICE TRUE

#define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT 
#define USB_EP1_TX_SIZE 8

#include <pic18_usb.h>
#include <.\include\midi_hid2.h> 
#include <usb.c> 
#include <ctype.h>

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(MASTER,SCL=PIN_B1,SDA=PIN_B0,SLOW,FORCE_HW)

	int8 pichA,pichB;
	int8 out_data[2];

void main(void) {

	delay_ms(1000);
	set_tris_A(0b0000001);
	setup_adc_ports(AN0);
	setup_adc(ADC_CLOCK_INTERNAL);
	set_adc_channel(0);
        usb_init_cs();

   while (TRUE) {
      usb_task();
      if (usb_enumerated())
		
      {
		output_high(PIN_A2);
		set_adc_channel(0);
		delay_us(20);
		pichA=read_adc();
	
		i2c_start();
		i2c_write(0xA0+1);
		pichB=i2c_read(0);
		i2c_stop();
		
		out_data[0]=pichB; 
		out_data[1]=pichA;
		  
		usb_put_packet(1,out_data,2,USB_DTS_TOGGLE);
         
      }  
   }
}

ESCLAVO (B)

Código:
#include <16F873A.h>
#device ADC=8
#fuses HS,NOWDT,PUT
#use delay(clock=20000000)
#use i2c(SLAVE,SCL=PIN_C3,SDA=PIN_C4,SLOW,FORCE_HW,ADDRESS=0x0A)


int pichB,state,buffer[0x01],adress;

#INT_SSP
void ssp_interrupt()
{
	state=i2c_isr_state();
	if(state==0x80){
	i2c_write(buffer[0x00]);
	output_high(PIN_A1);      //este no se llega a encender, asi que no realiza la lectura el MASTER
	}
}

void main(){
	set_tris_A(0b00000001);
	setup_adc_ports(AN0);
	setup_adc(ADC_CLOCK_INTERNAL);
	set_adc_channel(0);
	delay_us(20);
	pichB=read_adc();

	enable_interrupts(GLOBAL);
   	enable_interrupts(INT_SSP);
	
	adress=0x00;
	
	while(TRUE){
	
	set_adc_channel(0);
	delay_us(20);
	pichB=read_adc();
	buffer[0x00]=pichB;
	delay_ms(1);

	}
}

Gracias a todos. un saludo
 
Hola amigos soy nuevo en esto y estoy con un problema mas que nada en la comunicación i2c.
Mi proyecto es el siguiente:
PIC MASTRO(18f4550) el cual se comunica con una PC vía USB .balanza vía RS232 ,
y con otro pic slave(16f877a) vía i2c(aquí esta el problema)


El pic maestro envía 6 datos a la pc y recibe un dato...hablo de dato como un BYTE.
Aquí les paso el programa del MASTER :

---------------------------------------------------------------------------------------------------------------------
Código:
#include <18F4550.h>
#DEVICE ADC=8
#fuses HSPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#use rs232(baud=1200 ,xmit=PIN_C6,rcv=PIN_C7,stop=1,bits=8,parity=O)    //#use standard_io(c)
#use I2C(MASTER,SDA=PIN_b0,SCL=PIN_b1, FAST=400000)

#define USB_HID_DEVICE     FALSE             //deshabilitamos el uso de las directivas HID
#define USB_EP1_TX_ENABLE  USB_ENABLE_BULK   //turn on EP1(EndPoint1) for IN bulk/interrupt transfers
#define USB_EP1_RX_ENABLE  USB_ENABLE_BULK   //turn on EP1(EndPoint1) for OUT bulk/interrupt transfers
#define USB_EP1_TX_SIZE    6             //size to allocate for the tx endpoint 1 buffer
#define USB_EP1_RX_SIZE    2                 //size to allocate for the rx endpoint 1 buffer


#include <pic18_usb.h>     //Microchip PIC18Fxx5x Hardware layer for CCS\'s PIC USB driver
#include <PicUSB.h>         //Configuración del USB y los descriptores para este dispositivo
#include <usb.c>           //handles usb setup tokens and get descriptor reports


//Asignacion de variables 
#define LEDV    PIN_B3
#define LEDR    PIN_B4
#define LED_ON  output_high
#define LED_OFF output_low

#define modo      recibe[0]
#define param     recibe[1]
#define Temperatura   envia[0]
#define Temperatur   envia[1]
#define Temperatu   envia[2]
#define Temperat   envia[3]
#define Temper   envia[4]
#define Tem   envia[5]

//declaramos variables globales
void temp (void);
int8 recibe[1];                 
int8 envia[6];
int8 dato,t;

#int_rda //recibo datos de balanza
void rda_isr()
{
  temperatu=getc();
  output_d(0xf7);  
   delay_us(10);
    return;
   }
  
   


void main(void) 
{
   set_tris_d(0x00);                //Configuracion para el puerto D como salida
   output_d(0xff);                  //Limpiamos el puerto D
   setup_timer_0(RTCC_INTERNAL);   
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   disable_interrupts(GLOBAL);     //deshabilitamos todas las interrupciones
          
   LED_OFF(LEDV);                   //Apagamos led Verde
   LED_ON(LEDR);                    //Encendemos led Rojo   

   usb_init();                      //inicializamos el USB
   usb_task();                      //habilita periferico usb e interrupciones
   usb_wait_for_enumeration();      //esperamos hasta que el PicUSB sea configurado por el host
     
   setup_port_a( ALL_ANALOG );      //habilitamos el puerto a para entrada analogica
   setup_adc(ADC_CLOCK_INTERNAL);   //Utilizamos el reloj interno 

   LED_OFF(LEDR);                   //Apagamos el led Rojo
   LED_ON(LEDV);                    //encendemos led verde
    enable_interrupts(GLOBAL);
    enable_interrupts(int_rda);
   
  
   while (TRUE)
   {
      if(usb_enumerated())          //Si el PicUSB está configurado
      {
         if (usb_kbhit(1))          //Si el endpoint de salida contiene datos del host
         {  
            usb_get_packet(1, recibe, 2); //Cachamos el paquete de tamaño 2bytes del EP1 y almacenamos en recibe
            
           
            
           if (modo==1)//modo salida digital d1,d2,d3,d4,d5,d6,d7,d8
            {      
            disable_interrupts(int_rda); 
             output_d(param); //El dato param recibido lo mandamos al puerto o registro d
                 i2c_start();            // Comienzo de la comunicación                                              //PORBLEMA
                 i2c_write(0xa0);   // Dirección del esclavo en el bus I2C                                     
                 i2c_start();
                 i2c_write(0xa1);
                 t= i2c_read();  //Read Next
                 i2c_stop();             // Fin comunicación           
            }

                         
            }
            else if(modo==2)//modo analogico temperatura
            {
              temp(); //Adquirimos la señal analogica
             usb_put_packet(1,envia,6,USB_DTS_TOGGLE); //enviamos el paquete de tamaño 1byte del EP1 al PC
            }
            else if(modo==4)//Todo al mismo tiempo
            {
              output_d(param);
            
           temp();
            usb_put_packet(1,envia,6,USB_DTS_TOGGLE);  //despues modificar a 3
            }
                 else 
                 output_d(0xff);// Limpiamos el puerto D
         }  
      }
   }


void temp (void)
{

              set_adc_channel(0); // Tomamos datos del canal 5 (Pin4 RA2/AN2)
              delay_us(4);        // Hacemos un retardo de 4 ms
              dato=read_adc();    // Leemos el dato
              delay_us(10);       // Hacemos un retardo de 10 ms   
              Temperatura=dato;   // El dato leido lo almacenamos en Temperatura
            
              set_adc_channel(1); // Tomamos datos del canal 5 (Pin4 RA2/AN2)
              delay_us(4);        // Hacemos un retardo de 4 ms
              dato=read_adc();    // Leemos el dato
              delay_us(10);       // Hacemos un retardo de 10 ms   
              Temperatur=dato;   // El dato leido lo almacenamos en Temperatura
            
                      output_d(0xfb); 
                     temperat=t;
                     tem=temperat;
                    temper=temperat; 
            
}
--------------------------------------------------------------------------------------------------------------------------------------
el pic SLAVE me en teoria le manda el dato mediant una interrupcion .... les paso el codigo:

----------------------------------------------------------------------------------------------------------------------------------------
Código:
#include <16F877A.h>

#FUSES XT,NOWDT
#use delay(clock=4000000)
#use rs232(baud=1200 ,xmit=PIN_C6,rcv=PIN_C7,stop=1,bits=8,parity=O)
#use I2C(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0xa0, FAST=400000)

#use standard_io(A)
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)                     ///   con esta instruccion evitamos que
#use fast_io(D)                     ///   se este configurando cada vez que usamos
#use fast_io(E)                     ///   alguna instruccion de entrada o salida

#byte porta = 5
#byte portb = 6
#byte portc = 7                     /// se definen direcciones de memoria
#byte portd = 8
#byte porte = 9
BYTE dato_i2c,dato_serie,dato1,dato2;

 #INT_SSP
void ssp_interupt (){
   byte incoming,fstate;                //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
        i2c_write (dato_serie);
            
         }
   else {                                 //Sino es que hay dato en el bus I2C...
      incoming = i2c_read();              //... lo lee
      if (fState == 0){             //Información recibida es aviso de que va mandar algo master
         fState = 1;           //Siguiente información será la posición donde guardar dato
      }
      else if (fState == 1) {  //Información recibida corresponde a la posicion
         dato1 = incoming;             //Se guarda posición
         fState = 2;           //Siguiente información recibida será el dato
       }
      else if (fState == 2) {  //Información recibida corresponde al dato
         dato2= incoming;     //Se guarda dato
         fState = 0;                //Siguiente información será aviso de nuevo envío del master
       }
   }
   
} 
 
void main(){

setup_port_a( ALL_ANALOG );      //habilitamos el puerto a para entrada analogica
   setup_adc(ADC_CLOCK_INTERNAL);   //Utilizamos el reloj interno
    enable_interrupts(INT_SSP);
  enable_interrupts(GLOBAL);
while(1){
//------CAD---------
              set_adc_channel(1); // Tomamos datos del canal 5 (Pin4 RA2/AN2)
              delay_us(4);        // Hacemos un retardo de 4 ms
              dato_serie=read_adc();    // Leemos el dato
              putc(dato_serie);
              dato_i2c=dato_serie;
}
}
-------------------------------------------------------------------------------------------------------------------------------------------
Estoy como loco no puedo resolver la comunicación I2C, el resto lo tengo cocinado.
En la pc estoy usando labview
Desde ya muchas gracias.
 
Última edición por un moderador:
El código del maestro me parece a primera vista correcto.
En el código del esclavo lo 1ro que me llama la atención es dentro de la rutina de interrupción se está escribiendo a las variables dato1, dato2 y datoserie cuando no están declaradas como volatile.
Reemplazá la línea:
BYTE dato_i2c,dato_serie,dato1,dato2;
por
volatile BYTE dato_i2c,dato_serie,dato1,dato2;

Por lo que veo del código por ahora no te interesa mandar información del maestro al esclavo, sino sólo del esclavo al maestro
No estoy familiarizado con cómo el CCS maneja el I2C, pero en el código del maestro ésto:

Código:
i2c_start();            // Comienzo de la comunicación                                              //PORBLEMA
i2c_write(0xa0);   // Dirección del esclavo en el bus I2C                                     
i2c_start();
i2c_write(0xa1);
t= i2c_read();  //Read Next
i2c_stop();             // Fin comunicación
Pretende hacer una lectura del esclavo, con lo que se podría reemplazar por:

Código:
i2c_start();            // Comienzo de la comunicación
i2c_write(0xa1);
t= i2c_read();  //Read Next
i2c_stop();             // Fin comunicación
Podrías comenzar con ver si funciona de esa forma (comunicación unidireccional donde el esclavo envía solo el dato del adc al maestro) y luego ir viendo como agregar más datos, como hacer la comunicación bidireccional, etc.
Es decir, no escribir el código bidireccional y multi-dato de una vez, sino probar lo mínimo, programar los pics, ver como funciona, y si funciona entonces sí ir escalando en complejidad. Un mini-plan de desarrollo podría ser:

  1. Transmisión esclavo a maestro siempre el mismo dato, y 1 solo dato
  2. Transmisión esclavo a maestro, múltiples datos
  3. Transmisión maestro a esclavo (si hace falta)
  4. etc
 
¿Esta parte te funciona?

Código:
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
        i2c_write (dato_serie);
            
         }
   else {                                 //Sino es que hay dato en el bus I2C...
      incoming = i2c_read();              //... lo lee
      if (fState == 0){             //Información recibida es aviso de que va mandar algo master
         fState = 1;           //Siguiente información será la posición donde guardar dato
      }
      else if (fState == 1) {  //Información recibida corresponde a la posicion
         dato1 = incoming;             //Se guarda posición
         fState = 2;           //Siguiente información recibida será el dato
       }
      else if (fState == 2) {  //Información recibida corresponde al dato
         dato2= incoming;     //Se guarda dato
         fState = 0;

En vez de poner tantos "else", lo haría con un "switch y case". Nunca puse tantos else, y no se como lo gestiona, pero date cuenta que en el primero, si fState==0, luego lo pones a 1, por lo que ya se cumple el siguiente "else", y luego pones fState a 2, por lo que también se te cumple el último else.
 
Atrás
Arriba