No obtener valores correctos en la interfaz I2C en Atmega

Soy muy nuevo en el concepto de I2C y he tenido algunos problemas para conectar I2C entre 2 Atmega32(s).

  • Tengo un Atmega32 como Master al que se le conecta una pantalla LCD y otro I2C como esclavo al que se le ha conectado un LM35 y ambos Atmega se han conectado con las lineas SDA y SCL.

  • Entonces, aunque obtengo datos en la pantalla LCD adjunta al
    maestro, no obtengo los valores correctos. Por ejemplo, la temperatura es de 28 grados centígrados aquí, pero la pantalla LCD que está conectada al maestro sigue
    repitiendo 65280 por alguna razón. ¿Alguien puede decirme dónde me estoy equivocando? El código para los dispositivos maestro y esclavo se ha publicado
    a continuación.


El código maestro:

int main(void)
{
    unsigned int xx=0x00;
    unsigned char yy;
    DDRA=0xff;
    I2C_init(); //I2C initialization
    lcd_init(); //LCD initialization
    while(1)
    {
        for (int i=0;i<4;i++) //Getting unsigned int data from slave, so
        {                     //broke data into 4 parts and receiving 
            if (i==0)         //one byte at a time. 
            {
                I2C_start(0x01);  //I2C start along with the address of the slave
                yy=I2C_read_ack(); //Read slave data along with an acknowledgment 
                xx |= (yy << 8);    
                I2C_stop(); //I2C stop function.
            }
            else if (i>0)
            {
                I2C_start(0x01+1); //don't know any particular reason
                yy=I2C_read_ack(); //behind this, but if i don't do 0x01+1
                xx |= (yy << 8);   //then the master ends up reading the
                I2C_stop();        //address as a data packet.
            }
        }
     lcd_num(xx);   //lcd function to display unsigned int data.
    }
}

El código esclavo:

El código esclavo solo repite una función una y otra vez, así que no estoy publicando el código completo, solo los fragmentos intermedios.

int main(void)
{
    xx=adc_read(0); //reading from ADC0 of the Atmega.
    toTransfer = (5.0 * xx * 100.0) / 1024; //calibrating the temperature

    if (byte == 1) //send packet 1
    {
        toSend = toTransfer & mask; //sending the first 8 bits of data.
        toTransfer = toTransfer >> 8;//right shift so that the next function will take the 8-16 bits of data.
        TWI_match_write_slave(); //I2C function to verify address
        TWI_write_slave(toSend); //I2C function to write data on to master
        byte = 2;
    }

    /*Repeating this till byte 4*/

    else if (byte == 4) //send packet 4
    {
        toSend = toTransfer & mask;
        toTransfer = toTransfer >> 8;
        TWI_match_write_slave();
        TWI_write_slave(toSend);
        byte = 1;
        //initialization for next turn
        mask = 0xFF;
        toSend = 0;
    }
}

actualización: he intentado esto sin suerte:

unsigned int xx;   //I just wrote it here so that you don't have to refer the code again-
unsigned char yy;  //-not present in the main loop.
I2C_start(0x01);   //yy is receiving data one byte at a time from the slave
yy = I2C_read_ack();
xx = (xx|yy);
xx<<8;
I2C_stop();

De manera similar para la declaración else en el código publicado por mí originalmente.

Sea cual sea el valor que envíe, la pantalla LCD en el extremo receptor está imprimiendo 255.

Tienes "xx |= (yy << 8);" dos veces en su código maestro de recepción, por lo que nunca cambia los 8 bits inferiores de xx. También debe solucionar su problema de direccionamiento (0x01 frente a 0x01 + 1) antes de pensar que obtendrá comunicaciones confiables entre su maestro y esclavo.
Además, dependiendo de cómo se comporte su compilador, es posible que yy << 8 nunca produzca nada, ya que ha declarado yy como un carácter sin firmar de 8 bits.
Estoy confundido sobre cómo solucionar esto. Podrías explicarlo un poco más.
Si desplazas a la izquierda una variable de 8 bits en 8, entonces todos los bits simplemente caen al final y te quedas sin nada. Declare yy como un tipo de 16 bits, o cámbielo antes de realizar el cambio. Y uno de tus 2 "xx |= (yy << 8);" las líneas deberían ser algo así como "xx = yy", probablemente la primera.
¿Está utilizando dos bibliotecas diferentes? ¿Uno para Maestro y otro para Esclavo? Parece que usaste I2Cmaster como maestro y Wire como esclavo.
sí, haz esto: xx |= (((int sin firmar)yy) << 8);
@PedroQuadros, sí, son 2 bibliotecas diferentes para el esclavo y el maestro.
@brhans ahora entendí de lo que estabas hablando. Haré los cambios necesarios y lo probaré.
@brhans eche un vistazo al fragmento de código que publiqué a continuación.
@Alex echa un vistazo al fragmento de código que publiqué a continuación.
¿Ha configurado la dirección de su esclavo escribiendo 0x01 en el registro TWAR?

Respuestas (1)

¡¡FUNCIONA!! Entonces, después de notar que la pantalla LCD está imprimiendo solo 255 y nada más, me senté y lo pensé. Luego me di cuenta de que 255 es 0xff en hexadecimal, lo que significa que la línea SCL no se retuvo el tiempo suficiente para que el esclavo transmitiera datos. Así que simplemente puse un pequeño retraso de 100 ms después de la función de lectura y comenzó a funcionar. :D

 I2C_start(0x01);
 yy = I2C_read_ack();    
 _delay_ms(100);
 getdata=yy; //getdata is just another unsigned char variable. I thought that maybe yy 
 yy=0;       //isn't getting refreshed or something, so i made a small reset sort of thing here.
 xx = getdata&zz;
 xx<<8;
 I2C_stop();
La declaración xx<<8;no logra nada en absoluto. Si lo usara xx <<= 8;, desplazaría xx 8 bits a la izquierda.