Hola a todos. El motivo de esta publicación es porque estoy en la realización de un proyecto que consiste en la medición de corriente eléctrica AC en un pic18f4550 y dicha corriente la comparo con unos datos que consigo de un pic18f2550 a traves de I2C. El master es el pic18f4550 y el esclavo es el pic182550. Trabajo a una frecuencia de 48Mhz en cada micro con cristales de 4Mhz. La comunicación consiste en enviar del esclavo al maestro 4 bytes de datos cada ves q el maestro lo solicite. He simulado esta transacción en isis proteus y todo funciona de maravilla, pero el circuito fisico armado no funciona la comunicacion I2C. quisiera el apoyo de todos ustedes para resolver mi problema. El codigo es el siguiente:
Maestro:
#include <p18f4550.h> // Include Header for PIC18f455
#include <delays.h> // library containing delays - i.e. wait for time t
#include "compdirectives.h" // User defined header: Chip Config | Complier directivs
#include <stdlib.h>
#include <math.h>
#include <xlcd.h>
#include <adc.h>
#include <stdio.h>
#include <usart.h> // library containing serial communtication functions
// Definicion de bytes para el protocolo
#define BYTE_SINC 0xAA // Byte de sincronia
#define BYTE_INICIO 0x7E // Byte delimitador de inicio
#define BYTE_DIR_RX 0x11 // Dirección asignada al nodo receptor
#define TAM_TRAMA 4 // Cantidad de bytes en una trama
//#define DO_REQUEST LATCbits.LATC0
//#define DATA_READY LATCbits.LATC1
// I2C Bus Control Definition
#define I2C_DATA_ACK 0
#define I2C_DATA_NOACK 1
#define I2C_WRITE_CMD 0
#define I2C_READ_CMD 1
#define I2C_START_CMD 0
#define I2C_REP_START_CMD 1
#define I2C_REQ_ACK 0
#define I2C_REQ_NOACK 0
#define ADDRESS 0xA0
//Variables Globales
unsigned int adc_Res;
float inst_current, integral, rms_current, ref_voltaje, primary_current, ratio;
static unsigned long samples;
char buffer_data[8], bytes[4];
//Constantes
const int cero_Dig = 512; //2.5 Volts es el valor que entrega el sensor cuando la corriente vale 0
//Prototipos de funciones
char *ftoa (float x, char *str,char prec,unsigned char format);
unsigned int ADC_read2b(unsigned char ch);
void comandXLCD(unsigned char);
void gotoxyXLCD(unsigned char, unsigned char);
void i2c_float_read(void);
// I2C Functions
void i2c_init(void);
void i2c_idle(void);
void i2c_start(unsigned char);
void i2c_stop(void);
unsigned char i2c_slave_ack(void);
void i2c_write(unsigned char);
void i2c_master_ack(unsigned char);
unsigned char i2c_read(void);
void main()
{
Delay10KTCYx(200); //Retardo de 0.5 segundos
//Inicializamos el periferico i2c
TRISB = 0x00;
LATB = 0x00;
TRISB = 0xFF;
i2c_init();
RCONbits.IPEN=0; // Deshabilitamos Prioridades
INTCONbits.PEIE=0; // Deshabilitamos interrupcion de perifericos.-
//INTCONbits.GIE=1; // Habilitamos interrupcion Global.
//TRISB = 0b00000001; // RB0 se configura como entrada
//SetChanADC(ADC_CH0);
//***************
ADCON1 = 0b00001101;//VSS,VDD ref. AN0 y AN1 analog only
ADCON0 = 0x00;//clear ADCON0 to select channel 0 (AN0)
ADCON2 = 0b10001110;//ADCON2 setup: Right justified, Tacq=4Tad, Tad=2*Tosc (or Fosc/64)
ADCON0bits.ADON = 0x01;//Enable A/D module
//Configuracion del Timer0
T0CON = 0b00000010;
TMR0H = 0x00; // Reset Timer0
TMR0L = 0x00;
INTCONbits.TMR0IF = 0; // Clear Timer0 overflow flag
samples = 0;
integral = 0;
adc_Res = 0;
primary_current = 0;
OpenXLCD(FOUR_BIT & LINES_5X7); // Iniciamos LCD.-
while(BusyXLCD());
comandXLCD(0x06); // Mover cursor a la derecha...
comandXLCD(0x0C); // Desactivando el cursor.
comandXLCD(0x01); // Borra pantalla y vuelve al origen.-
putrsXLCD("CFE Medicion");
gotoxyXLCD(1, 2);
putrsXLCD("Irms = ");
gotoxyXLCD(1, 3);
putrsXLCD("Ip = ");
gotoxyXLCD(1, 4);
putrsXLCD("Rel = ");
adc_Res = ADC_read2b(1); // Obtenemos el voltaje de referencia
ref_voltaje = ((float)adc_Res*5)/1023;
while (1) // loop infinito el cual maneja la conversion analaga a digital de la corriente y su presentacion en display
{
TMR0H = 0x9E; // Reset Timer0
TMR0L = 0x57;
INTCONbits.TMR0IF = 0; // Clear Timer0 overflow flag
T0CONbits.TMR0ON = 1;
while (~INTCONbits.TMR0IF)
{
adc_Res = ADC_read2b(0); //iniciamos conversiones en el canal 0 hasta que se desborde el timer0
//inst_current = ( (( (float)adc_Res*5)/1023 ) - 2.5 )/0.1 ; // Calculamos la corriente instantanea
//***************
inst_current = ( ( ((float)adc_Res*5)/1023) - ref_voltaje )/0.28 ; // Calculamos la corriente instantanea resistencia de
// burden igual a 560 ohms
integral = integral + inst_current*inst_current;
samples++; // Incrementamos el contador de muestras
}
INTCONbits.TMR0IF = 0; // Clear Timer0 overflow flag
T0CONbits.TMR0ON = 0;
if(samples!=0)
rms_current = sqrt(integral/(float)samples);
//comandXLCD(0x01); // Borra pantalla y vuelve al origen.-
gotoxyXLCD(8, 2);
putsXLCD( ftoa(rms_current,buffer_data,3,'f') );
samples = 0;
integral = 0;
i2c_float_read(); // Obtenemos primary_current
gotoxyXLCD(7, 3);
putsXLCD( ftoa(primary_current,buffer_data,3,'f') );
if(rms_current!=0){
ratio = primary_current/rms_current;
gotoxyXLCD(7, 4);
putsXLCD( ftoa(ratio,buffer_data,3,'f') );
}
}//while
}//main
//*************************************************************************
void DelayFor18TCY(void){
Delay10TCYx(120);
}
void DelayPORXLCD(void){
Delay1KTCYx(180);
return;
}
void DelayXLCD(void){
Delay1KTCYx(60);
return;
}
unsigned int ADC_read2b(unsigned char ch){
unsigned int ad_res;
SetChanADC(ch); // elegir canal
ADCON0bits.GO=1; // Lanzar conversion sin retardo
while(ADCON0bits.GO); // while(BusyADC());
ad_res=ADRESH;
ad_res<<=8;
ad_res+=ADRESL; // ad_res= ReadADC();
return ad_res;
}
void i2c_float_read(){
//unsigned cont_bytes;
Delay10TCYx(240); // Demora de 200 us
// Start the I2C Transmission
i2c_start(I2C_START_CMD);
// Read Control Byte - Read
i2c_write(0xA1);
Delay10TCYx(240); // Demora de 200 us
// Get the byte
bytes[0] =i2c_read();
// Send Acknowledge to the Slave
i2c_master_ack(I2C_DATA_ACK);
// Get the byte
bytes[1] =i2c_read();
// Send Acknowledge to the Slave
i2c_master_ack(I2C_DATA_ACK);
// Get the byte
bytes[2] =i2c_read();
// Send Acknowledge to the Slave
i2c_master_ack(I2C_DATA_ACK);
// Get the byte
bytes[3] =i2c_read();
Delay1KTCYx(36); // Retardo de 3ms
// Send No Acknowledge to the Slave
i2c_master_ack(I2C_DATA_NOACK);
// Stop I2C Transmission
i2c_stop();
Delay10TCYx(240); // Demora de 200 us
memcpy(&primary_current, bytes, sizeof(float));
}
// Envia comando al LCD
void comandXLCD(unsigned char a){
while(BusyADC());
WriteCmdXLCD(a);
}
// Ubica cursor en (x = Posicion en linea, y = nº de linea)
void gotoxyXLCD(unsigned char x, unsigned char y){
unsigned char adr;
//if(y != 1)
// direccion = 0x40;
//else
// direccion=0;
//direccion += x-1;
//comandXLCD(0x80 | direccion);
switch(y){
case 1 : adr = 0x80; break;
case 2 : adr = 0xC0; break;
case 3 : adr = 0x90; break;
case 4 : adr = 0xD0; break;
}
adr+=x-1;
comandXLCD(adr);
}
//Convierte numero flotante a cadena de texto
char *ftoa (float x, char *str,char prec,unsigned char format)
{
/* converts a floating point number to an ascii string */
/* x is stored into str, which should be at least 30 chars long */
char *adpt;
int ie, i, k, ndig, fstyle;
double y;
adpt=str;
//if (nargs() != 7) IEHzap("ftoa ");
ndig = ( prec<=0) ? 7 : (prec > 22 ? 23 : prec+1);
if (format == 'f' || format == 'F')
fstyle = 1;
else
fstyle = 0;
/* print in e format unless last arg is 'f' */
ie = 0;
/* if x negative, write minus and reverse */
if ( x < 0)
{
*str++ = '-';
x = -x;
}
/* put x in range 1 <= x < 10 */
if (x > 0.0) while (x < 1.0)
{
x *= 10.0; // à la place de =*
ie--;
}
while (x >= 10.0)
{
x = x/10.0;
ie++;
}
/* in f format, number of digits is related to size */
if (fstyle) ndig += ie; // à la place de =+
/* round. x is between 1 and 10 and ndig will be printed to
right of decimal point so rounding is ... */
for (y = i = 1; i < ndig; i++)
y = y/10.;
x += y/2.; // à la place de =+
if (x >= 10.0) {x = 1.0; ie++;} /* repair rounding disasters */
/* now loop. put out a digit (obtain by multiplying by
10, truncating, subtracting) until enough digits out */
/* if fstyle, and leading zeros, they go out special */
if (fstyle && ie<0)
{
*str++ = '0'; *str++ = '.';
if (ndig < 0) ie = ie-ndig; /* limit zeros if underflow */
for (i = -1; i > ie; i--)
*str++ = '0';
}
for (i=0; i < ndig; i++)
{
k = x;
*str++ = k + '0';
if (i == (fstyle ? ie : 0)) /* where is decimal point */
*str++ = '.';
x -= (y=k); // à la place de =-
x *= 10.0; // à la place de =*
}
/* now, in estyle, put out exponent if not zero */
if (!fstyle && ie != 0)
{
*str++ = 'E';
if (ie < 0)
{
ie = -ie;
*str++ = '-';
}
for (k=100; k > ie; k /=10); // à la place de =/
for (; k > 0; k /=10) // à la place de =/
{
*str++ = ie/k + '0';
ie = ie%k;
}
}
*str = '\0';
return (adpt);
}
// Start PIC18F4550 I2C Function
void i2c_init(void) {
unsigned char temp;
// Initial PIC18F4550 I2C bus Ports: RB0 - SDA and RB1 - SCL, Set as Input
TRISBbits.TRISB0 = 1;
TRISBbits.TRISB1 = 1;
// Initial the PIC18F4550 MSSP Peripheral I2C Master Mode
// I2C Master Clock Speed: 48000000 / (4 * (SSPADD + 1)) = 48000000 / (4 * (39 + 1))
PIE1bits.SSPIE = 0; // Disable I2C Interrupts
SSPCON1bits.SSPEN = 0; // Disable I2C Mode
SSPCON1 = 0x08; // I2C Master Mode
SSPSTATbits.SMP = 0; // SlewRate Control enabled
SSPADD = 119; // 48 MHz: 119 =~100KHz Clock, 29 =~ 400 Khz, 14 =~ 800 Khz
PIR1bits.SSPIF = 0; // Clear Interrupt
SSPCON1bits.SSPEN = 1; // Enable I2C Mode
temp = SSPBUF; // Read buffer to clear buffer full
}
void i2c_idle(void)
{
// Wait I2C Bus and Status Idle (i.e. ACKEN, RCEN, PEN, RSEN, SEN)
while (( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_W));
}
void i2c_start(unsigned char stype)
{
i2c_idle(); // Ensure the I2C module is idle
SSPCON2bits.SEN = 1; // Start I2C Transmission
while(SSPCON2bits.SEN);
}
void i2c_stop(void)
{
// Stop I2C Transmission
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
}
unsigned char i2c_slave_ack(void)
{
// Return: 1 = Acknowledge was not received from slave
// 0 = Acknowledge was received from slave
return(SSPCON2bits.ACKSTAT);
}
void i2c_write(unsigned char data)
{
// Send the Data to I2C Bus
SSPBUF = data;
if (SSPCON1bits.WCOL) // Check for write collision
return;
while(SSPSTATbits.BF); // Wait until write cycle is complete
i2c_idle(); // Ensure the I2C module is idle
}
void i2c_master_ack(unsigned char ack_type)
{
SSPCON2bits.ACKDT = ack_type; // 1 = Not Acknowledge, 0 = Acknowledge
SSPCON2bits.ACKEN = 1; // Enable Acknowledge
while (SSPCON2bits.ACKEN == 1);
}
unsigned char i2c_read(void)
{
// Ensure the I2C module is idle
i2c_idle();
// Enable Receive Mode
SSPCON2bits.RCEN = 1; // Enable master for 1 byte reception
while(!SSPSTATbits.BF); // Wait until buffer is full
return(SSPBUF);
}