Autor Tema: Comunicación entre pic18f4550 y pic18f2550 por medio de I2C  (Leído 2188 veces)

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

Desconectado cidtepole

  • PIC10
  • *
  • Mensajes: 5
Comunicación entre pic18f4550 y pic18f2550 por medio de I2C
« en: 20 de Julio de 2014, 15:41:39 »
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); 
}

Desconectado pajaro

  • PIC24H
  • ******
  • Mensajes: 1121
Re: Comunicación entre pic18f4550 y pic18f2550 por medio de I2C
« Respuesta #1 en: 26 de Julio de 2014, 11:59:27 »
hola compañero

si en el simulador te funciona y en el real no puede ser un problema de retardos o de que algún cablecito no hace buen contacto,

que compilador usas?
teóricamente cuando lees desde el maestro un esclavo, le pones la dirección del esclavo a leer  y le activas el modo lectura.

mira este enlace:
http://www.todopic.com.ar/foros/index.php?;topic=38547.0

como lo tienes conectado en el proteus sube el fichero?

yo logre crear una red de varios esclavos comandados por el maestro todo en i2c.

un saludo y comenta tus progresos.