2014-10-30 40 views
1

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

总线上还有一个基于Linux的TI DM365 SoC。 DM365可以毫无问题地与从属设备进行通信。所以基本上,这将是一个多主设置。

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

我不断收到“错误:0x18”,这是当设备地址不传输时表明总线繁忙。但是当我使用电压表(抱歉,没有示波器)时,它保持在3.3V的高电平,这意味着总线可以自由使用。我也尝试过通过物理切割DM365,但即使这样也行不通。

任何帮助或想法表示赞赏。

编辑:道歉的可怕的调试方法。当我得到'错误: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; 
} 
+0

TWIGetStatus()!= 0x18,检查状态是否为0x18或其他。 如果你想调试这个问题,你应该通过uart发送当前状态。 0x18表示:已发送SLA + W。 http://www.atmel.com/images/doc2545.pdf表22.2 – 2014-10-30 22:38:32

+0

更新了我的问题。我得到的当前状态是0x06。 – tsf144 2014-10-31 15:32:55

回答

0

可能是由于这些问题:

  1. 硬件
    可以归因于该行的不当上拉,它依赖于在总线上的处理器/微控制器或传感器。

  2. 软件
    检查协议的速度(100Khz或400KHz)。主从通信应该相同。 尝试重写TWI开始的像这样的代码:

    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 & 0xF8的变成0x08的。同样重写代码并尝试!