Comunicacion entre 2 PIC's con I2C

Hola, vereis tengo un problema, estoy trabajando en lo que yo denomino mi torreta ^^ se trata de una plataforma que realizara un tracking de movimiento mediante ultrasonidos. Para ello estoy utilizando 2 PIC'S 18f2550 conectados mediante I2C (aqui es donde tengo el problema), un pic controlara los servos y la comunicacion al pc mediante usb, mientras que el otro se encargara de los ultrasonidos y la triangulacion.

Pues empezando por el principio, comunicar los 2 pics, creo que entiendo bien la mecanica del I2C pero utilizando el proteus ISIS, consigo enviar datos con el master (que es el de los servos, y usb) pero el slave no hace ni caso, nose si es que tendre mal la rutina, pero es que nisiquiera me salta la interrupcion SSP (e probado a en la interrupcion encender un led y pa tu tia). es como si no recibiera la señal del I2C.

Me preguntaba si pudierais hecharme una mano, por que es aqui donde estoy atasco.
No estoy en casa, pero cuando llege subire el codigo.

Mientras tanto si alguien podria, nose, decirme algo.
Gracias
 
Hola perdon por tardar en responder, pero estado algo liado en el trabajo.

Gracias por contestar la informacion esta de lujo.
Mirar os pongo el mi codigo por si podriais indicarme en donde me equivoco, a mi me parece que esta todo correcto.

Master.c
Código:
#include <18F2550.h>
#fuses HS,USBDIV,PLL5
#use delay(clock=20000000)
#use I2C(MASTER, sda=PIN_B0, scl=PIN_B1, FAST,  FORCE_HW)

//////////////////////////////////////////////////////////////////////
////////////////////////////DEFINES///////////////////////////////////
//////////////////////////////////////////////////////////////////////

/*
DESCRIPTORES PARA EL USO USB

#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 1 //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 <main.h> //Configuración del USB y los descriptores para este dispositivo
#include <usb.c> //handles usb setup tokens and get descriptor reports
*/
#define ENCENDER output_high
#define APAGAR output_low
#define LED_PIC PIN_C6

//////////////////////////////////////////////////////////////////////
///////////////////////////VARIABLES//////////////////////////////////
//////////////////////////////////////////////////////////////////////

boolean sistema_usound = TRUE;

int posicion_servo1 = 0;
int posicion_servo2 = 0;
//int contador = 0;
//int8 recibe[3];

/////////////////////////////////////////////////////////////////////
///////////////////////////INTERRUPCIONES////////////////////////////
/////////////////////////////////////////////////////////////////////
#INT_TIMER2
void PWM_movimiento_servos(void)
{
	//mirar de mejorar el movimiento de los servos 
}

#INT_SSP
void interrupcion_I2C(void)
{
	//de momento como es master esta interrupcion no hace nada, pero dejamos esta opcion disponible para futuras actualizaciones de funcionamiento
}

/////////////////////////////////////////////////////////////////////
/////////////////////////////FUNCIONES///////////////////////////////
/////////////////////////////////////////////////////////////////////
void escribir_i2c(BYTE direccion, int dato)
{
	i2c_start();
	i2c_write(direccion);
	i2c_write(dato);
	i2c_stop();
	delay_us(50);
}

int leer_i2c(BYTE direccion, int opcion)
{
	int dato = 0;
	i2c_start();
	i2c_write(direccion);
	i2c_write(opcion);
	
	i2c_start();
	i2c_write(direccion+1);
	dato = i2c_read();
	i2c_stop();
	
	return(dato);
}

void parpadeo()
{
		ENCENDER(LED_PIC);
		delay_ms(500);
		APAGAR(LED_PIC);
		delay_ms(500);
}
/////////////////////////////////////////////////////////////////////
///////////////////////////////MAIN//////////////////////////////////
/////////////////////////////////////////////////////////////////////
void main(void) 
{
   //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_timer_2(T2_DIV_BY_1,249,2); //inicializacion de las interrupciones del timer 2 a 0.1 ms cada una
	set_timer2(0); //inicializar a 0 el timer2

	delay_ms(1000); //esperamos 1 segundo que para asegurarnos que se inicialice toda la placa antes de empezar la fiesta
	
//	enable_interrupts(INT_TIMER2); //interrupcion del timer 2
//	enable_interrupts(INT_SSP);	//interrupcion del I2C (desabilitada puesto que el master no recibe interrupciones, sino que als crea)
//	enable_interrupts(GLOBAL); //habilitamos las interrupciones
	
	while(1)
	{
		/* FUNCION DE USB DESACTIVADA DE MOMENTO

		if(usb_enumerated()) //si la torreta esta correctamente instalada en el pc (opcion desactivada de momento
		{
				if (usb_kbhit(1))          //si el endpoint de salida contiene datos del host
       			{
           			usb_get_packet(1, recibe, 3); //cojemos el paquete de tamaño 3bytes del EP1 y almacenamos en recibe

					posicion_servo1 = recibe[1];
					posicion_servo2 = recibe[2];            
        		}*/
			if(sistema_usound) //si esta activo el utilizar los ultrasonidos
			{
				posicion_servo1 = leer_i2c(0xa0, 1); //leer posicion en la que debe situarse el servo 1
				posicion_servo2 = leer_i2c(0xa0, 2); //leer posicion en la que debe situarse el servo 1
			}

		//} //fin del if(usb_enumerated)
	};
}

Slave.c
Código:
#include <18F2550.h>
#fuses HS,USBDIV,PLL5
#use delay(clock=20000000)
#use I2C(SLAVE, sda=PIN_B0, scl=PIN_B1, ADDRESS= 0xa0, FAST, FORCE_HW)

//////////////////////////////////////////////////////////////////////
////////////////////////////DEFINES///////////////////////////////////
//////////////////////////////////////////////////////////////////////

#define ENCENDER output_high
#define APAGAR output_low
#define LED_PIC PIN_C6

//////////////////////////////////////////////////////////////////////
///////////////////////////VARIABLES//////////////////////////////////
//////////////////////////////////////////////////////////////////////

byte i2c_estado= 0;
byte i2c_dato_entrada;
byte i2c_dato_funcion;
int i=0;
BYTE direccion = 0x00;
int posicion_servo1 = 0;
int posicion_servo2 = 0;

/////////////////////////////////////////////////////////////////////
///////////////////////////INTERRUPCIONES////////////////////////////
/////////////////////////////////////////////////////////////////////
#INT_SSP
void ssp_interupt ()  //salta una interrupcion y nos disponemos a tratarla
{
	i2c_estado = i2c_isr_state();  //leemos el valor del isr (el que nos indica que accion debemos tratar, o bien leer o bien escribir)
	if(i2c_estado <0x80)  //el master te esta enviando informacion por lo que debemos leer lo que nos dice
	{
		i2c_dato_entrada = i2c_read(); //leemos "dato" del master, si hubieran mas datos habria que hacer mas reads, en nuestro caso solo leemos un byte por cada funcion de lectura en el esclavo (el master es el que escribe)
	}
	if(i2c_estado >= 0x80) //el master esta pidiendonos un dato con lo que debemos responderle con un write
	{
		i2c_dato_funcion = i2c_dato_entrada;
		if(i2c_dato_funcion == 1) //el master nos pide la posicion del servo1
		{
			i2c_write(posicion_servo1);
		}
		if(i2c_dato_funcion == 2) //el master nos pide la posicion del servo2
		{
			i2c_write(posicion_servo2);
		}
	}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////FUNCIONES///////////////////////////////
/////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////
///////////////////////////////MAIN//////////////////////////////////
/////////////////////////////////////////////////////////////////////
void main(void) 
{
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
		
   };
}

Realmente el fallo se debe de producir en la interrupcion #INT_SSP del esclavo o en la funcion escribier_i2c en el maestro, pero sigo pensando que esta todo correcto ya nose si es problema de los pics o es que yo soy un cenutrio que no vale pa esto, dios estoy desesperado.
 
Hola, perdon por la tardanza, pero aqui en España estabamos como locos mirando la final y no podia estar pendiente del foro jejeje

El master solicita informacion en el bucle del main mediante las funciones

posicion_servo1 = leer_i2c(0xa0, 1); //leer posicion en la que debe situarse el servo 1
posicion_servo2 = leer_i2c(0xa0, 2); //leer posicion en la que debe situarse el servo 1

codigo de la funcion:
Código:
int leer_i2c(BYTE direccion, int opcion)
{
	int dato = 0;
	i2c_start();
	i2c_write(direccion);
	i2c_write(opcion);
	
	i2c_start();
	i2c_write(direccion+1);
	dato = i2c_read();
	i2c_stop();
	
	return(dato);
}
 
bueno, lo que veo en tu código desta bien, pero te recomendaria que en el caso del esclavo en la parte que determinas si el maestro pide o manda un dato que es con el

i2c_estado = i2c_isr_state();

lo modifiques de esta manera


Código:
i2c_estado = i2c_isr_state();
if(i2c_estado <0x80)  //el master te esta enviando informacion por lo que debemos leer lo que nos dice
    {
        i2c_dato_entrada = i2c_read(); 
    }
    if(i2c_estado == 0x80) 
    {
        i2c_dato_funcion = i2c_dato_entrada;
        if(i2c_dato_funcion == 1) //el master nos pide la posicion del servo1
        {
            i2c_write(posicion_servo1);
        }
        else if(i2c_dato_funcion == 2) //el master nos pide la posicion del servo2
        {
            i2c_write(posicion_servo2);
        }
        else
        {i2c_write(0);}  //Nunca dejes al pic sin una respuesta de reserva aunque creas que nunca se dará
    }

y en el maestro cuando haces la lectura, modifícalo con esto:

Código:
int8 leer_i2c(int8 direccion, int8 opcion)
{
    int dato = 0;
    i2c_start();
    i2c_write(direccion);
    i2c_write(opcion);
    
    i2c_start();
    i2c_write(direccion+1);
    dato = i2c_read(0); //Coloca este cero, eso te evitará que tu pic se "cuelgue" intentando leer un dato erróneo.
    i2c_stop();
    
    return(dato);
}

verás que coloque en ves de solo "int" puse "int8" es bueno siempre definir la longitud de tus variables aunque por teoria un int=int8, pero por las dudas asegúrate colocándole un int8.

Ahora, no se que tan necesario te sea para ti usar el i2c ya que si solo comunicarás esos 2 pics y sólo esos 2 pics, te recomendaría que uses el puerto 232, es muchísimo mas eficiente, de verdad. Si gustas tener ayuda con códigos en eso, hice infinidad de proyectos con el puerto 232 y nunca me falló.

Saludos!
 
Pero... haciendo eso no se le altera la direccion del destino?

por ejemplo: si tengo dos dispositivos, uno con dirección 0xa0 y el otro con dirección 0xa1: cuando el maestro le escriba i2c_write(0xa0+1), supongo que seria lo mismo que escribir i2c_write(0xa1) Si??? entonces... ¿Cual dispositivo respondería? Por favor explicarme bien esta parte. Saludos (Y)
 
las direcciones i2c las colocas normalmente como pares, de esa manera siempre tendras el número par para la dirección de escritura y el número impar siguiente para la dirección de lectura del dispositivo.

si tienes dos dispositivos tendras las siguientes direcciones por ejemplo:
Device 1: 0xa0
Device 2: 0xb0

Si usarás pics como esclavos i2c puedes ponerle la dirección que creas conveniente para evitar posibles conflictos. Si en tu circuito tienes chips i2c como relojs o memorias pues debes fijarte en el datasheet de esos chips para saber cual es su direccion.

Saludos
 
Atrás
Arriba