Atmega168 I2C作为主设备

时间:2014-10-30 18:44:51

标签: c i2c atmega atmel

我在使用Atmega168作为I2C设备时遇到了一些问题。基本设置是物理I2C总线连接到其他从设备,但Atmel本身未启用I2C。

总线上还有一个基于linux的TI DM365 SoC。 DM365可以毫无问题地与从设备通信。从本质上讲,它将是一个多主设置。

下面粘贴了重要的atmel代码。在这种情况下,USART_Transmit与printf相同。在main()中调用TWIinit(),并在命令(从串行)上读取总线。

我一直收到“错误:0x18”,这是指未发送设备地址表示总线忙。但是当我使用电压表(抱歉,没有示波器)时,它保持在3.3V的高电平,这意味着总线可以自由使用。我也通过实际切断DM365来尝试这一点,但即使这样也行不通。

感谢任何帮助或想法。

编辑:为可怕的调试方法道歉。当我得到'Err:0x18'时,它意味着我从未得到0x18,它只是意味着我被卡住了。我得到的实际值是0x06,我不知道它来自哪里。

uint8_t u8ebyte;
uint8_t u8erbyte;
uint16_t u16eaddress = 0x0002;
#define EEDEVADR 0x36

void TWInit (void)
{   
    TWSR = 0x00;    // prescaler 1
    TWBR = 0xFF;   //0xFF; //smallest TWBR value possible is 0x10
    TWCR = (1<<TWEN);  // Enable TWI-interface and release TWI pins.
}

void TWIStart(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}
//send stop signal
void TWIStop(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void TWIWrite(uint8_t u8data)
{
    TWDR = u8data;
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

uint8_t TWIReadACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}
//read byte with NACK
uint8_t TWIReadNACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

uint8_t TWIGetStatus(void)
{
    uint8_t status;
    //mask status
    status = TWSR & 0xF8;
    return status;
}

uint8_t I2CReadByte(uint16_t u16addr, uint8_t *u8data)
{
    //uint8_t databyte;
    TWIStart();
    if (TWIGetStatus() != 0x08){
        USART_Transmit_string("ERR:0x08");
        TWIStop();
       return -1;
    }
    //select device 
    TWIWrite((EEDEVADR)|((uint8_t)((u16addr& 0x0700)>>7)));

    //TWIWrite(((EEDEVADR)<<1|0));
    if (TWIGetStatus() != 0x18){
        USART_Transmit_string("ERR:0x18");
        return -1;
    }

    //send the rest of address
    TWIWrite((uint8_t)(u16addr));
    if (TWIGetStatus() != 0x28){
        USART_Transmit_string("ERR:0x28");
        return -1;
    }

    //send repeated- start
    TWIStart();
    if (TWIGetStatus() != 0x10){
        USART_Transmit_string("ERR:0x10");
        return -1;
    }

    //select devise and send read bit
    TWIWrite((EEDEVADR)|((uint8_t)((u16addr & 0x0700)>>7))|1);
    if (TWIGetStatus() != 0x40){
        USART_Transmit_string("ERR:0x40");
        return -1;
    }

    *u8data = TWIReadNACK();

    if (TWIGetStatus() != 0x58){
        USART_Transmit_string("ERR:0x58");
        return -1;
    }
    TWIStop();
    USART_Transmit_string("MADE IT!!");
    return 1;
}

1 个答案:

答案 0 :(得分:0)

可能是由于这些问题:

  1. 硬件
    可能是由于线路上拉不当造成的,这取决于总线上的处理器/微控制器或传感器。

  2. 软件
    检查协议的速度(100Khz或400KHz)。主设备和从设备通信应该相同。 尝试重写TWI Start的代码,如下所示:

    void TWI_start(void){
    // Clear TWI interrupt flag, Put start condition on SDA, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);  
    while(!(TWCR & (1<<TWINT))); // Wait till start condition is transmitted
    while((TWSR & 0xF8)!= 0x08);// Check for the acknowledgement
    }
    

    这里的代码等到TWSR&amp; 0xF8变为0x08。同样重写代码并尝试!