2
\$\begingroup\$

I'm very new to the concept of I2C and I've been having some problems interfacing I2C between 2 Atmega32(s).

  • I have one Atmega32 as a Master to which an LCD screen is connected and another I2C as a slave to which a LM35 has been connected and both of these Atmega have been connected with the SDA and SCL lines.

  • So, although I am getting data on the LCD screen attached to the
    master, I'm not getting the right values. Like the temperature is 28 Centigrade here but the LCD that is connected to the master keeps
    repeating 65280 for some reason. Can someone tell me where I'm going wrong? Code for both the master and slave devices have been posted
    below.


The Master code:

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.
    }
}

The Slave code:

The slave code is just repeating one function again and again so I'm not posting the whole code, just the snippets in between.

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;
    }
}

update: I've tried this with no luck:

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();

Similarly for the else statement in the code posted by me originally.

Whatever value I send, the LCD on the receiving end is printing 255.

\$\endgroup\$
11
  • \$\begingroup\$ You have "xx |= (yy << 8);" twice in your master receive code, so you are never changing the lower 8-bits of xx. You also need to fix your addressing issue (0x01 vs 0x01+1) before thinking you're going to get reliable comms between your master & slave. \$\endgroup\$
    – brhans
    Commented Jul 24, 2015 at 14:15
  • \$\begingroup\$ Also, depending on how your compiler behaves, yy << 8 may never produce anything since you've declared yy as an 8-bit unsigned char. \$\endgroup\$
    – brhans
    Commented Jul 24, 2015 at 14:17
  • \$\begingroup\$ I'm confused on how to fix this. Could you explain it a little more. \$\endgroup\$ Commented Jul 24, 2015 at 14:30
  • \$\begingroup\$ If you left-shift an 8-bit variable by 8, then all the bits just fall out the end and you're left with nothing. Either declare yy as a 16-bit type, or typecast it before you perform the shift. And one of your 2 "xx |= (yy << 8);" lines should just be something like "xx = yy" - probably the 1st one. \$\endgroup\$
    – brhans
    Commented Jul 24, 2015 at 14:42
  • \$\begingroup\$ Are you using two different libraries? One for Master and another for Slave? It seems you used I2Cmaster for master and Wire for slave. \$\endgroup\$ Commented Jul 24, 2015 at 16:47

1 Answer 1

1
\$\begingroup\$

IT WORKS!! So, after I noticed that the LCD is printing only 255 and nothing else, I sat and thought about it. Then I realized that 255 is 0xff in hexadecimal so that meant the SCL line wasn't being held long enough for the slave to transmit data. So I simply put a small delay of 100 ms after the read function and it started working. :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();
\$\endgroup\$
1
  • \$\begingroup\$ The statement xx<<8; does not achieve anything at all. If you used xx <<= 8; it would shift xx left 8 bits. \$\endgroup\$ Commented Sep 25, 2015 at 0:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.