Hola a todos,
Estamos realizando un proyecto para el cual se necesita comunicar 2 Pic mediante el bus I2C.
La cuestion es que, despues de haber realizado un programa maestro y otro esclavo, no conseguimos, ni siquiera que el esclavo lea la direccion.
Os agradeceriamos, si alguno teneis ejemplos de maestros y esclavos que comuniquen que nos los pusierais ya que por mas que hemos buscado en este foro y en internet, aun no hemos encontrado nada que funicone.
Por otro lado, os agregamos los dos programas realizados por si teneis tiempo y os apetece echarles un vistazo.
Muchas gracias y esperamos vuestra ayuda.
P.D. Estamos utilizando MPLAB, espero que no os cause mucho trastorno.
MAESTRO:
#include <p18F452.h>
#include <tcepi2.h>
#include <i2c.h>
#include <delays.h>
#include "I2Cv1.h"
void sai(void);
void I2C_config(void);
//void I2C_Enviar(char);
void I2C_recibir(void);
void esperar_ACK(void);
//#define ESCLAVO_WRITE 0xA0
//#define ESCLAVO_READ 0xA1
char lin1[17]="Escrita ";
char lin2[17]="Direccion ";
char lin3[17]="colision direcc";
char lin4[17]="colision dato ";
char lin5[17]="no ACK ";
char lin6[17]="interrupcion ";
char lin7[17]="Enviado ";
char lin8[17]="Dato ";
char lin9[17]="3m ";
char lin10[17]="4m ";
char lin11[17]="5m ";
char lin12[17]="6m ";
char lin13[17]="SOY ";
char lin14[17]="MAESTRO ";
unsigned char i;
unsigned char p_enviada[5]="Hola";
unsigned char p_recibida[5]="Nada";
unsigned char carac_recibido;
/**************************************/
/* Simulando el bootloader */
/* (comentar antes de generar el hex) */
/**************************************/
//#pragma code AL_STARTUP = 0x0
//void _al_startup (void)
//{
// _asm
// goto 0x200
// _endasm
//}
//#pragma code AL_VECTOR_INTERRUPCIONES_ALTAS = 0x8
//void _al_vector_interrupciones_altas (void)
//{
// _asm
// goto 0x208
// _endasm
//}
/**************************************/
/* Aquí va el tema de la interrupción */
/**************************************/
#pragma code VECTOR_INTERRUPCIONES_ALTAS = 0x208
void salto_altas (void)
{
_asm
goto sai
_endasm
}
#pragma code
#pragma interrupt sai
void sai (void)
{
PutsLcd(lin1,lin6);
p0(WAIT_PUSH);
}
void main(void)
{
RCONbits.IPEN = 1; /* Habilitamos prioridades */
INTCONbits.GIEH = 1; /* Habilitamos interrupciones altas */
I2C_config();
p0(WAIT_PUSH);
PutsLcd(lin13,lin14);
/******************************************************************************
ESCRITURA
*******************************************************************************/
// Bucle para enviar la cadena
for (i=0;i<5;i++)
{
StartI2C();
//Esperamos a que detecte la condicion de Start.
while(PIR1bits.SSPIF==0){};
PIR1bits.SSPIF=0;
//I2C_Enviar(ESCLAVO_WRITE); // Envia la direccion del esclavo
IdleI2C(); // Espera que este libre
WriteI2C(0x00);
// Miramos si hay colision de escritura de la direccion
if(SSPCON1bits.WCOL)
{
p0(WAIT_PUSH);
PutsLcd(lin1,lin3);
}
esperar_ACK();
// Ponemos esto despues de que reciba el ACK. Si pone esto es
// que el esclavo ha leido la direccion.
p0(WAIT_PUSH);
PutsLcd(lin1,lin2);
PIR1bits.SSPIF=0;
p0(WAIT_PUSH);
PutsLcd(lin1,lin2);
//I2C_Enviar(p_enviada);
IdleI2C();
WriteI2C(p_enviada);
p0(WAIT_PUSH);
PutsLcd(lin1,lin2);
// Imprimimos mensaje si hay colision de escritura de dato
if(SSPCON1bits.WCOL)
{
PutsLcd(lin1,lin4);
}
esperar_ACK();
PIR1bits.SSPIF=0;
p0(WAIT_PUSH);
PutsLcd(lin7,lin8);
StopI2C();
}
// Realizamos una espera entre lectura y escritura
Delay10KTCYx(255);
/***********************************************************************************
LECTURA
************************************************************************************/
// Inicializamos el contador
i=0;
while(i<5)
{
StartI2C();
while(PIR1bits.SSPIF==0){};
PIR1bits.SSPIF=0;
//I2C_Enviar(ESCLAVO_READ); // Envia la direccion del esclavo, y le dice que quiere leer
IdleI2C(); // Espera que este libre
WriteI2C(0x01);
// Miramos si hay colision de escritura de la direccion
if(SSPCON1bits.WCOL)
{
PutsLcd(lin1,lin3);
}
esperar_ACK();
PIR1bits.SSPIF=0;
I2C_recibir();
//Si se ha recibido, se genera el ACK.
if(carac_recibido)
{
AckI2C();
p_recibida=carac_recibido;
}
else
{
NotAckI2C();
}
i++;
}
PutsLcd(lin1,p_recibida);
}
void I2C_config(void)
{
// Inicializa el módulo del MSSP en modo maestro
OpenI2C(MASTER, SLEW_OFF);
// Valor de recarga del baudrate generator.Frecuencia del reloj
SSPADD = 0x63;
// ACKSTAT y ACKDT a 1 Inicialización delos ACK"s
SSPCON2= 0x60;
TXSTAbits.TXEN=1;
INTCON=0xC0;
TRISCbits.TRISC3=0; // SCL del maestro, y por tanto del módulo.
TRISCbits.TRISC4=0; // Data del maestro. Salida de datos.
// Para ver si el ACK se produce en la direccion.
SSPCON2bits.ACKSTAT=1;
}
/*void I2C_Enviar(char dato)
{
IdleI2C(); // Espera que este libre
WriteI2C(dato);
}*/
void I2C_recibir(void)
{
// Le dices que el maestro v a ser receptor
SSPCON2bits.RCEN=1;
IdleI2C();
if (DataRdyI2C())
{
carac_recibido=getcI2C();
}
// return (carac_recibido);
}
void esperar_ACK(void)
{
// if (valor) AckI2C();
// else NotAckI2C();
// IdleI2C();
while(SSPCON2bits.ACKSTAT)
{
PutsLcd(lin1,lin5);
}
}
ESCLAVO:
#include <p18F452.h>
#include <tcepi2.h>
#include <i2c.h>
#include <delays.h>
#include <string.h>
#include "esclavo_v1.h"
unsigned char i,j;
unsigned char p_enviada[5]="aHol";
unsigned char p_recibida[17]="nadaaaaaaaaa";
unsigned char carac_recibido;
//Prototipos de las funciones
void I2C_config(void);
void I2C_enviar(char);
unsigned char I2C_recibir(void);
void esperar_ACK(void);
char lin1[17]="SOY ";
char lin2[17]="ESCLAVO ";
char lin3[17]="colision direcc";
char lin4[17]="colision dato ";
char lin5[17]="no ACK ";
char lin6[17]="interrupcion ";
char lin7[17]="paco1 ";
char lin8[17]="paco2 ";
char lin9[17]="paco3 ";
char lin10[17]="BUCLE ";
char lin11[17]="INFINITO ";
void main(void)
{
unsigned char Direccion=0x00;
// Configuracion del bus I2C
I2C_config();
p0(WAIT_PUSH);
PutsLcd(lin1,lin2);
/***********************************************************************************
LECTURA
************************************************************************************/
// Inicializamos los contadores
i=0;
j=0;
while(1)
{
while(PIR1bits.SSPIF==1)
{
p0(WAIT_PUSH);
PutsLcd(lin10,lin11);
};
p0(WAIT_PUSH);
PutsLcd(lin7,lin8);
// Pongo esto para saber si detecta la dirección
PIR1bits.SSPIF=1;
// Esto nos lo podemos quitar
IdleI2C();
//Limpiamos el buffer
Direccion=SSPBUF;
// Si lo que le ha llegado es un 0, es que va a recibir datos
if (SSPSTATbits.R_W == 0 )
{
p0(WAIT_PUSH);
PutsLcd(lin10,lin11);
carac_recibido=I2C_recibir();
/*PutsLcd(lin1,carac_recibido);
p0(WAIT_PUSH);*/
//Si se ha recibido, se genera el ACK.
if(carac_recibido)
{
AckI2C();
p_recibida=carac_recibido;
p0(WAIT_PUSH);
PutsLcd(lin1,lin2);
}
else
{
NotAckI2C();
}
i++;
/*PutsLcd(lin1,carac_recibido);
p0(WAIT_PUSH);*/
}
// Si va a escribir
else
{
/* Mirar si puede haber problema con el clock Streching*/
IdleI2C();
// I2C_enviar(p_enviada[j]); // Envia el primer caracter
SSPBUF=p_enviada[j];
// Liberamos el reloj
SSPCON1bits.CKP=1;
// Miramos si hay colision de escritura del dato
if(SSPCON1bits.WCOL)
{
PutsLcd(lin1,lin3);
}
j++;
//esperar_ACK();
}
}
}
void I2C_config(void)
{
// Inicializa el módulo del MSSP en modo esclavo
//OpenI2C(SLAVE_7, SLEW_OFF);
SSPCON1=0B00000110; // seteo como SLAVE
//
SSPADD = 0x00;
// ACKSTAT y ACKDT a 1 Inicialización delos ACK"s
SSPCON2= 0x60;
TXSTAbits.TXEN=1;
INTCON=0xC0;
// Configuramos los pines como entrada
TRISCbits.TRISC3=1;
TRISCbits.TRISC4=1;
SSPCON1bits.CKP = 1; // Libera el clock
SSPCON2bits.SEN = 0;
PIE1bits.SSPIE = 1; // Para habilitar interrupciones, esta en 0 por defecto.
}
void I2C_enviar(char dato)
{
IdleI2C(); // Espera que este libre
WriteI2C(dato);
}
unsigned char I2C_recibir(void)
{
unsigned char carac;
IdleI2C();
// Mientras no este el dato disponible, no hace nada
if (DataRdyI2C())
{
carac=getcI2C();
PutsLcd(lin1,lin2);
p0(WAIT_PUSH);
}
return (carac);
}
void esperar_ACK(void)
{
// if (valor) AckI2C();
// else NotAckI2C();
IdleI2C();
if(SSPCON2bits.ACKSTAT)
{
PutsLcd(lin1,lin5);
}
}