Forum: Mikrocontroller und Digitale Elektronik Sensorkommunikation I2C - Atmega32


von JP (Gast)


Lesenswert?

Hallo Leute :)

Ich beschäftige mich zurzeit damit, über TWI (I2C) mit einem Sensor zu 
kommunizieren. Jedoch komme ich nicht so wirklich klar damit. Die 
gesamte Kommunikation soll später über 3 Funktionen (TWI_initTWI, 
TWI_ReceiveData und TWI_SendData) erfolgen. Hierfür möchte ich gerne die 
Nebenfunktionen in die Receive und Send Funktion einbauen, jedoch klappt 
das nicht so recht. Könnt Ihr mir evtl weiterhelfen und sagen, wo meine 
Fehler liegen?

Hier der Code:
/*********************************************************************** 
********
*Funktion       void TWI_InitTWI_v(uint8_t BitRate, uint8_t 
PrescalerHighBit, uint8_t PrescalerLowBit)
*
*Beschreibung   Initialiesiert das TWI-Modul des Mikrocontrollers
*
*Parameter    BitRate: Bitrate die im Register TWBR eingestellt werden 
soll
*        PrescalerHighBit:  Wert der fuer TWPS1 eingestellt werden soll
*        PrescalerLowBit:  Wert der fuer TWPS0 eingestellt werden soll
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_InitTWI(uint8_t BitRate, uint8_t PrescalerHighBit, uint8_t 
PrescalerLowBit)
{
  // TWIFrequenz auswaehlen freq= F_CPU/(16+2(TWBR)*4^TWPS)
  TWBR=BitRate;                        //Bitrate setzen
  TWSR=(PrescalerHighBit<<TWPS1)|(PrescalerLowBit<<TWPS0);    // Setzen 
der prescalar bits
}


/*********************************************************************** 
********
*Funktion       void TWI_StartCondition(void)
*
*Beschreibung   Sendet eine Startbedingung fuer eine TWI Kommunikation
*
*Parameter    keine
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_StartCondition(void)
{
  // Setzt TWI interrupt flag zurueck, legt Startbedingung an SDA, 
Enable TWI
  TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while(!(TWCR & (1<<TWINT))); // wartet bis die Startbedingung gesendet 
ist
  while((TWSR & 0xF8)!= 0x08); // prueft acknowledgement
}

/*********************************************************************** 
********
*Funktion       void TWI_RepeatedStartCondition(void)
*
*Beschreibung   Sendet eine erneute Startbedingung
*
*Parameter    keine
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_RepeatedStartCondition(void)
{
  // Setzt TWI interrupt flag zurueck, legt Startbedingung an SDA, 
Enable TWI
  TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while(!(TWCR & (1<<TWINT))); // wartet bis die Startbedingung gesendet 
ist
  while((TWSR & 0xF8)!= 0x10); // prueft acknowledgement
}


/*********************************************************************** 
********
*Funktion       void TWI_SendAddress(uint8_t Adress, uint8_t Direction)
*
*Beschreibung   Sendet die Slave Adresse, ob anschließend gelesen oder 
geschriben werden soll und wartet ACK ab
*
*Parameter    Adress:  Adresse des Slaves im 8-Bit Format (letztes Bit 
egal)
*        Direction: Read=1; Write=0
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_SendAddress(uint8_t Adress, uint8_t Direction)
{
  if (Direction==0)
  {
    Adress&=0xFE;
  }
  else
  {
    Adress|=0x01;
  }
  TWDR=Adress;          // Addresse and Richtung senden
  TWCR=(1<<TWINT)|(1<<TWEN);    // Setzt TWI interrupt flag zurueck, 
Enable TWI
  while (!(TWCR & (1<<TWINT)));  // wartet bis TWDR uebertragen ist
  if (Direction==0)
  {
    while((TWSR & 0xF8)!= 0x18);  // prueft acknoledgement fuer lesen
  }
  else
  {
    while((TWSR & 0xF8)!= 0x40);  // prueft acknoledgement fuer 
schreiben
  }

}


/*********************************************************************** 
********
*Funktion       void TWI_WriteData(uint8_t char Data)
*
*Beschreibung   Sendet 8-Bit Daten und wartet auf ACK
*
*Parameter    Data: 8-Bit Daten, die gesendet werden sollen
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_WriteData(uint8_t Data)
{
  TWDR=Data;            // legt Data ins Senderegister
  TWCR=(1<<TWINT)|(1<<TWEN);    // Setzt TWI interrupt flag zurueck, 
Enable TWI
  while (!(TWCR & (1<<TWINT)));  // wartet bis TWDR uebertragen ist
  while((TWSR & 0xF8) != 0x28);  // prueft acknoledgement
}

/*********************************************************************** 
********
*Funktion       uint8_t TWI_ReadData(void)
*
*Beschreibung   Empfaengt 8-Bit Daten ueber TWI
*
*Parameter    keine
*
*Rueckgabe      8Bit Daten
*
************************************************************************ 
*******/
uint8_t TWI_ReadData(void)
{
  uint8_t ReciveData;        //Variable fuer die empfangenden Daten
  TWCR=(1<<TWINT)|(1<<TWEN);    // Setzt TWI interrupt flag zurueck, 
Enable TWI
  while (!(TWCR & (1<<TWINT)));  // wartet bis das TWDR-Byte 
uebermittelt wurde
  while((TWSR & 0xF8) != 0x58);  // prueft acknoledgement
  ReciveData=TWDR;        // liest TWDR-Byte aus
  return (ReciveData);      // Rueckgabe der Daten
}

/*********************************************************************** 
********
*Funktion       void TWI_StopCondition(void)
*
*Beschreibung   Sendet Stopp-Bedingung nach TWI-Kommunikation
*
*Parameter    keine
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_StopCondition(void)
{
  // Setzt TWI interrupt flag zurueck, legt Stoppbedingung an SDA, 
Enable TWI
  TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  while(!(TWCR & (1<<TWSTO)));  // wartet bis Stoppbedingung 
uebermittelt wurde
}

/*********************************************************************** 
********
*Funktion       void TWI_SendData(uint8_t SlaveAdress, uint8_t 
RegisterAdress, uint8_t Data)
*
*Beschreibung   Schreibt Daten ins das abgegebene Register des Slaves 
mit der angegebenen Adresse
*
*Parameter    SlaveAdress:  Adresse des Slaves, der angesprochen werden 
soll
*        Registeradress:  Register, in das geschrieben werden soll
*        Data:      Daten, die in das Register geschrieben werden sollen
*
*Rueckgabe      keine
*
************************************************************************ 
*******/
void TWI_SendData(uint8_t SlaveAdress, uint8_t RegisterAdress, uint8_t 
Data)
{
  /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/
  TWI_StartCondition();
  TWI_SendAddress(SlaveAdress, RegisterAdress);
  TWI_WriteData(Data);
  TWI_WriteData(Data);
  TWI_StopCondition();
}

/*********************************************************************** 
********
*Funktion       uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t 
RegisterAdress)
*
*Beschreibung   Empfaengt Daten des Slaves, welche unter der angebenen 
Registeradresse zu finden sind
*
*Parameter    SlaveAdresse:  Adresse des angeschlossenen Slaves im 8-Bit 
Format
*        RegisterAdress: Adresse des Registers, das gelesen werden soll
*
*Rueckgabe      8-Bit Daten
*
************************************************************************ 
*******/
uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t RegisterAdress)
{
  /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/
  TWI_StartCondition();
  TWI_SendAddress(SlaveAdress, RegisterAdress);
  TWI_ReadData();
  TWI_RepeatedStartCondition();
  TWI_StopCondition();
}

Ich hoffe, dass mir jemand weiterhelfen kann :)
LG

von spess53 (Gast)


Lesenswert?

Hi

Du solltest dich mal über I2C schlau machen:

http://www.nxp.com/documents/user_manual/UM10204.pdf
1
uint8_t TWI_ReciveData(uint8_t SlaveAdress, uint8_t RegisterAdress)
2
{
3
  /*Funktion mit Hilfe der oben gegeben Funktionen schreiben*/
4
  TWI_StartCondition();
5
  TWI_SendAddress(SlaveAdress, RegisterAdress);
6
  TWI_ReadData();
7
  TWI_RepeatedStartCondition();
8
  TWI_StopCondition();
9
}

Wie passt z.B.

TWI_SendAddress(SlaveAdress, RegisterAdress);

mit

void TWI_SendAddress(uint8_t Adress, uint8_t Direction)

zusammen?

Und was soll das TWI_RepeatedStartCondition(); in dem Code?

...


MfG Spess

von Stefan F. (Gast)


Lesenswert?

Ich mach das alles mit einer einzigen Funktion. Diese Idee habe ich von 
einer Java implementierung (Lejos) abgeguckt. Dort wird sie im Bereich 
Robotics verwendet und hat sich bewährt:
1
//========================================================================
2
// I2C Bus
3
//========================================================================
4
// Wenn der I2C Bus nicht verwendet wird, stehen dessen Pins als reguläre
5
// I/O Pins zur Verfügung. Pull-Up Widerstände nicht vergessen!
6
7
// Sendet beliebig viele Bytes an den adressierten Slave und empfängt
8
// anschließend beliebig viele Bytes von dem Slave. 
9
10
// slave_address ist die Adresse des Slave in 7bit Schreibweise (0-127).
11
// send_data zeigt auf die zu sendenden Daten, z.B. ein Array von Bytes. 
12
// send_bytes gibt an, wieviele Bytes gesendet werden sollen.
13
// rcv_data zeigt auf einen Puffer, wo die empfangenen Daten abgelegt 
14
// werden sollen, z.B. ein Array von Bytes. 
15
// rcv_Bytes gibt an, wieviele Bytes empfangen werden sollen.
16
// Der Rückgabewert zeigt an, wie viele Bytes tatsächlich empfangen wurden.
17
18
// Wenn man nur senden will, gibt man rcv_data=0 und rcv_bytes=0 an.
19
// Wenn man nur empfangen will, gibt man send_data=0 und send_bytes=0 an.
20
// Es ist erlaubt, bei send_bytes und rcv_bytes Zeiger auf den selben 
21
// Puffer zu übergeben.
22
23
uint8_t i2c_communicate(uint8_t slave_address, void* send_data, uint8_t send_bytes, void* rcv_data, uint8_t rcv_bytes) {
24
    uint8_t rcv_count=0;
25
            
26
    // Adresse ein Bit nach links verschieben, um Platz für das r/w Flag zu schaffen
27
    slave_address=slave_address<<1;
28
           
29
    if (send_bytes>0) {
30
        // Sende Start 
31
        TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
32
        while (!(TWCR & (1<<TWINT)));
33
        uint8_t status=TWSR & 0xf8;
34
        if (status != 0x08 && status != 0x10) goto error;
35
    
36
        // Sende Adresse (write mode)
37
        TWDR=slave_address;
38
        TWCR=(1<<TWINT) | (1<<TWEN);
39
        while (!(TWCR & (1<<TWINT)));
40
        if ((TWSR & 0xf8) != 0x18) goto error;
41
        
42
        // Sende Daten
43
        while (send_bytes>0) {
44
            TWDR=*((uint8_t*)send_data);
45
            TWCR=(1<<TWINT) | (1<<TWEN);
46
            while (!(TWCR & (1<<TWINT)));
47
            if ((TWSR & 0xf8) != 0x28) goto error;
48
            send_data++;
49
            send_bytes--;
50
        }
51
    }
52
    
53
    if (rcv_bytes>0) { 
54
        // Sende START
55
        TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
56
        while (!(TWCR & (1<<TWINT)));
57
        uint8_t status=TWSR & 0xf8;
58
        if (status != 0x08 && status != 0x10) goto error;
59
        
60
        // Sende Adresse (read mode)
61
        TWDR=slave_address + 1;
62
        TWCR=(1<<TWINT) | (1<<TWEN);
63
        while (!(TWCR & (1<<TWINT)));
64
        if ((TWSR & 0xf8) != 0x40) goto error;
65
    
66
        // Empfange Daten
67
        while (rcv_bytes>0) {    
68
            if (rcv_bytes==1) {
69
                // das letzte Byte nicht mit ACK quittieren
70
                TWCR=(1<<TWINT) | (1<<TWEN); 
71
            } 
72
            else {   
73
                // alle anderen Bytes mit ACK quittieren
74
                TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWEA);
75
            }
76
            while (!(TWCR & (1<<TWINT)));
77
            uint8_t status=TWSR & 0xf8;
78
            if (status!=0x50 && status != 0x58) goto error;
79
            *((uint8_t*)rcv_data)=TWDR;
80
            rcv_data++;
81
            rcv_bytes--;
82
            rcv_count++;
83
        }
84
85
    }
86
    
87
    // Sende STOP
88
    TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
89
    return rcv_count;
90
91
    error:
92
    // Sende STOP
93
    TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
94
    return 0;
95
}

Was da noch fehlt, ist die Initialisierung der Bitrate:
1
    // TWI Interface ungefähr 100kbit/section, bei 15Mhz
2
    TWBR=75;

von JP (Gast)


Lesenswert?

ich werde es mal so probieren vielen Dank :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.