Aufbau einer ordnungsgemäßen TWI/I2C-Kommunikation zwischen einem Atmega32-Paar

Ich bin Maschinenbauingenieur mit dem Wunsch, Elektronik zu lernen.

Ich arbeite an diesen Tagen daran, die TWI(I2C)-Kommunikation in Atmega32 zu lernen. Mit viel Internetsuche habe ich es geschafft, ein Tutorial zu bekommen, das erklärt, wie ich eine gegenseitige Kommunikation zwischen zwei Atmega32-Chips herstellen kann.

Hier ist der Code des Master-Chips

#include<avr/io.h>
#include<util/delay.h>
#include<inttypes.h>

void TWI_start(void);
void TWI_repeated_start(void);
void TWI_init_master(void);
void TWI_write_address(unsigned char);
void TWI_read_address(unsigned char);
void TWI_write_data(unsigned char);
void TWI_read_data(void);
void TWI_stop(void);

unsigned char address=0x20, read=1, write=0;
unsigned char write_data=0x01, recv_data;

int main(void)
{
    _delay_ms(2000);
    DDRB=0xff;
    TWI_init_master();   // Function to initialize TWI
    while(1)
    {
        if(write_data==0x00)    
        write_data=1;

            // Function to send start condition
        TWI_start();
        // Function to write address and data direction bit(write) on SDA
        TWI_write_address(address+write);
        // Function to write data in slave
        TWI_write_data(write_data);
        // Function to send stop condition
        TWI_stop();


        _delay_ms(10);  // Delay of 10 mili second

        TWI_start();    
        // Function to write address and data direction bit(read) on SDA
        TWI_read_address(address+read); 
        TWI_read_data();
        // Function to read data from slave 
        TWI_stop();

        _delay_ms(1000);    

        write_data = write_data * 2;
    }


}

void TWI_init_master(void) // Function to initialize master
{
    TWBR=0x01;  // Bit rate
    TWSR=(0<<TWPS1)|(0<<TWPS0); // Setting prescalar bits
    // SCL freq= F_CPU/(16+2(TWBR).4^TWPS)
}

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
}

void TWI_repeated_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 restart condition is transmitted
    while((TWSR & 0xF8)!= 0x10); // Check for the acknowledgement
}

void TWI_write_address(unsigned char data)
{
    TWDR=data;  // Address and write instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8)!= 0x18);  // Check for the acknowledgement
}

void TWI_read_address(unsigned char data)
{
    TWDR=data;  // Address and read instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte received
    while((TWSR & 0xF8)!= 0x40);  // Check for the acknowledgement
}

void TWI_write_data(unsigned char data)
{
    TWDR=data;  // put data in TWDR
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x28); // Check for the acknowledgement
}

void TWI_read_data(void)
{
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x58); // Check for the acknowledgement
    recv_data=TWDR;
    PORTB=recv_data;
}

void TWI_stop(void)
{
    // Clear TWI interrupt flag, Put stop condition on SDA, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);  
    while(!(TWCR & (1<<TWSTO)));  // Wait till stop condition is transmitted
}

Während der Code des Slave-Chips lautet:

#include<avr/io.h>
#include<util/delay.h>

void TWI_init_slave(void);
void TWI_match_read_slave(void);
void TWI_read_slave(void);
void TWI_match_write_slave(void);
void TWI_write_slave(void);

unsigned char write_data,recv_data;

int main(void)
{
    DDRB=0xff;
    TWI_init_slave(); // Function to initialize slave
    while(1)
    {
        //Function to match the slave address and slave direction bit(read) 
        TWI_match_read_slave(); 
        // Function to read data
        TWI_read_slave();

        // Togglem the receive data
        write_data=~recv_data;

        //Function to match the slave address and slave direction bit(write) 
        TWI_match_write_slave();
        // Function to write data
        TWI_write_slave();
    }
}

// Function to initialize slave
void TWI_init_slave(void)
{
    // Fill slave address to TWAR
    TWAR=0x20;
}

void TWI_write_slave(void) // Function to write data
{
    // Fill TWDR register with the data to be sent 
    TWDR= write_data;
    // Enable TWI, Clear TWI interrupt flag 
    TWCR= (1<<TWEN)|(1<<TWINT);
    // Wait for the acknowledgement
    while((TWSR & 0xF8) != 0xC0);
}

// Function to match the slave address and slave 
void TWI_match_write_slave(void)dirction bit(write) 
{
    // Loop till correct acknowledgement have been received
    while((TWSR & 0xF8)!= 0xA8)
    {
        // Get acknowledgment, Enable TWI, Clear TWI interrupt flag
        TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT);    
        while (!(TWCR & (1<<TWINT)));  // Wait for TWINT flag
    }
}

void TWI_read_slave(void)
{
    // Clear TWI interrupt flag,Get acknowledgement, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);   
    // Wait for TWINT flag
    while (!(TWCR & (1<<TWINT)));
    // Wait for acknowledgement
    while((TWSR & 0xF8)!=0x80);
    // Get value from TWDR
    recv_data=TWDR;
    // send the receive value on PORTB
    PORTB=recv_data;
}

//Function to match the slave address and slave direction bit(read)
void TWI_match_read_slave(void)
{
    // Loop till correct acknoledgement have been received
    while((TWSR & 0xF8)!= 0x60)
    {
        // Get acknowlegement, Enable TWI, Clear TWI interrupt flag
        TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT);    
        // Wait for TWINT flag
        while (!(TWCR & (1<<TWINT))); 
    }
}

Der Code funktioniert gut in der Simulation für die allererste Phase von MasterTransmitter-SlaveReceiver.

Für die zweite Phase von MasterReceiver-SlaveTransmitter scheint die Simulation jedoch keine Aktion zu zeigen und wechselt nicht einmal in den MasterTransmitter-SlaveReceiver-Modus.

Antworten (5)

Die Funktion TWI_match_read_slave()sieht für mich falsch aus. Sie müssen TWAR und TWCR aktivieren, bevor Sie prüfen, ob der Slave die Selbstadressierung durchgeführt hat.

Geben Sie hier die Bildbeschreibung ein

void TWI_slave_Rx_init()
{
    TWBR=1;         
    //Setting up the SCL frequency by writing a value in TWBR
    TWSR|=(0<<TWPS1)|(0<<TWPS0);    
    //Fscl=     Fcpu/(16+2*(TWBR)*(4^TWPS))
    TWAR=0b00000010;        
    //The first seven bits indicate the slave address 
    TWCR|=(1<<TWINT);
    TWCR|=(1<<TWEN)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO);    
    //Enabling Acknowledge function
    while (!(TWCR & (1<<TWINT)));   
    //Wait for the interrupt to be cleared as it will indicate the successful reception
    while(TWCR&(0xF8)!=(0x60)); 
    //Checking if the self-address+W has been received and ACK has been sent

}

So sollte es sein, da das Setzen von TWEA allein nicht bedeutet, dass Sie das Bestätigungsbit gesendet haben.

Das Einstellen von TWEA erzeugt NUR WENN die folgenden Bedingungen erfüllt sind, einen Bestätigungsimpuls:

Geben Sie hier die Bildbeschreibung ein

Diese Antwort wäre noch besser, wenn sie Referenzen hätte . Könnten Sie einige hinzufügen?
Es steht alles im Datenblatt des ATmega16A. Seite Nummer. 196 & 180 jeweils für die Bilder. Der Code wurde von mir geschrieben, muss aber noch getestet werden. Ich werde den Kommentar aktualisieren, sobald ich ihn überprüft habe. Ich bin ein Neuling, was I2C betrifft, und ich schreibe eine Bibliothek dafür.
Wenn Sie dies überprüft haben, bearbeiten Sie Ihre Antwort bitte so, dass sie das Ergebnis enthält, und fügen Sie bitte auch einen Link zu dem Datenblatt hinzu, auf das Sie sich beziehen. Danach können wir diese Kommentare entfernen.
electronicdatasheets.com/pdf-datasheets/atmel/ATmega16A Das Datenblatt des ATmega16A steht hier zum Download bereit.
Verzeihung! Die Seitennr. sind 192 & 180

Verwenden Sie Ihr DMM und überprüfen Sie den Spannungspegel an SDA und SCL. Wenn es stecken bleibt, liegt es normalerweise daran, dass der Slave sich verlaufen hat und SDA immer noch niedrig hält.

In der Slave-Datei: Ich bin mir nicht sicher, aber beide Variablen write_data, mrecv_data sind nicht initialisiert, vielleicht ist das dein Problem. In The Master file: recvdata wird ebenfalls nicht initialisiert

Danke für die Hilfe, aber wie ich denke, setzt der Compiler die nicht initialisierten deklarierten Variablen auf den Wert 0x00. Um sicherzugehen, habe ich alle deklarierten Variablen auf den Wert 0x00 initialisiert, aber ich erhalte das gleiche unerwartete Ausgabeverhalten.
@DiaaAbidou - Es ist wahrscheinlich eine gute Idee, niemals davon auszugehen, dass nicht initialisierte Variablen einen bestimmten Wert haben, es sei denn, die Compiler-Dokumentation gibt dies ausdrücklich an. Hier scheint es aber kein Problem zu sein.

Ich ändere die Stoppfunktion im Master und löse das Problem:

void TWI_Stop(void)
{
   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

und ich überprüfe dieses Programm in Proteus ohne Probleme.

Bin ich nur einer, der diese Zeile sieht?

void TWI_match_write_slave(void)dirction bit(write)

sollte sein

void TWI_match_write_slave(void)

Entschuldigen Sie meine Taubheit, aber ich verstehe den Rest des Codes in dieser Zeile nicht, jede Hilfe ist willkommen