Forum: Mikrocontroller und Digitale Elektronik I2C Verbindung fehlerhaft


von Thomas M. (Gast)


Lesenswert?

Hallo zusammen,

ich möchte gerne zwei ATMEGA(32/64) miteinander über I2C kommunizieren 
lassen. Dazu habe ich auch schon Probeaufbauten gemäß des I2C Standards 
aufgebaut und mit der Programmierung angefangen. Weil der Code gut 
geschrieben ist, habe ich ihn u.a. von [[AVR TWI Master und Slave 
Funtionen in C
]] übernommen. Ein IC fungiert als Master, der andere als Slave.

Stecke ich z.B. einen DS1307 (i2c fähige RealTimeClock) alleine an den 
Bus, funktioniert die Verbindung problemlos. Stecke ich aber alleine 
oder zusätzlich zur DS1307 den als Slave fungierenden ATMEGA auf die I2C 
Leitung, bleibt der Master in der unten markierten Stelle hängen. Jetzt 
kann ich mir leider nicht genau erklären warum er gerade dort hängen 
bleibt, obwohl meines Erachtens nach alles korrekt eingestellt wurde.

Leider habe ich hier und auf jeglichen Suchmaschinen keine mögliche 
Antwort auf mein Problem gefunden.


Mein zusammengefasster Code aus der Library:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/twi.h>
4
5
///////////////////////////////////////////////////////////////////////////////////////
6
//////////////////////////    MASTER Chain    ///////////////////////////////////
7
///////////////////////////////////////////////////////////////////////////////////////
8
_Bool TWIM_Init(uint32_t bitrate) {
9
  TWBR = ((F_CPU / bitrate) - 16) / 2;
10
  if (TWBR < 11)
11
    return false;
12
  return true;
13
}
14
15
_Bool TWIM_Start(uint8_t adress, uint8_t RW) {
16
  uint8_t twst;
17
18
  // Sende Startbefehl
19
  TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
20
  // Warten bis fertig
21
// BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG
22
  // BUG: sobald ATMEGA Slave angeschlossen wird bleibt er in der while schleife
23
  while (!(TWCR & (1 << TWINT))) {
24
 // Ausgabe, ob der IC hier bleibt
25
    PORTB ^= (1 << PB3);
26
    _delay_ms(100);
27
  }
28
  // Statusregister checken
29
  twst = TWSR & 0xf8;
30
  if ((twst != TWI_START) && (twst != TWI_REP_START))
31
    return false;
32
  // sende ansprechadresse
33
  TWDR = (adress << 1) + RW;
34
  TWCR = (1 << TWINT) | (1 << TWEN);
35
  // Warte bis Befehl zuende und ACK/NACK empfangen
36
  while (!(TWCR & (1 << TWINT)))
37
    ;
38
  // Statusregister checken
39
  twst = TWSR & 0xf8;
40
  if ((twst != TWI_MTX_ADR_ACK) && (twst != TWI_MRX_ADR_ACK))
41
    return false;
42
  return true;
43
}
44
45
void TWIM_Stop(void) {
46
  // Sende Stop Befehl
47
  TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
48
  // Warte bis Befehl fertig
49
  while (TWCR & (1 << TWSTO)) {
50
51
  }
52
}
53
54
_Bool TWIM_Write(uint8_t byte) {
55
  uint8_t twst;
56
  // Sende Daten an die vorher eingestellte Adresse
57
  TWDR = byte;
58
  TWCR = (1 << TWINT) | (1 << TWEN);
59
  // Warte bis die Übertragung fertig ist
60
  while (!(TWCR & (1 << TWINT))) {
61
    PORTB ^= (1 << PB3);
62
    _delay_ms(100);
63
  }
64
  // Statusregister checken
65
  twst = TWSR & 0xf8;
66
  if (twst != TWI_MTX_DATA_ACK)
67
    return true;
68
  return false;
69
}
70
71
uint8_t TWIM_ReadAck(void) {
72
  TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
73
  while (!(TWCR & (1 << TWINT)))
74
    ;
75
  return TWDR;
76
}
77
78
uint8_t TWIM_ReadNack(void) {
79
  TWCR = (1 << TWINT) | (1 << TWEN);
80
  while (!(TWCR & (1 << TWINT)))
81
    ;
82
  return TWDR;
83
}
84
85
///////////////////////////////////////////////////////////////////////////////////////
86
////////////////////////////    SLAVE Chain    ///////////////////////////////////
87
///////////////////////////////////////////////////////////////////////////////////////
88
89
_Bool TWIS_Init(uint8_t adress, uint32_t bitrate) {
90
  TWBR = ((F_CPU / bitrate) - 16) / 2;
91
  if (TWBR << 11)
92
    return false;
93
  // Setze die Slave Adresse, geshiftet, denn TWGCE
94
  TWAR = adress * 2;
95
  // Aktiviere das TWI Interface
96
  TWCR = (1 << TWEN) | (1 << TWEA);
97
  return true;
98
}
99
100
void TWIS_Stop(void) {
101
  TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWEA);
102
}
103
104
void TWIS_Write(uint8_t byte) {
105
  TWDR = byte;
106
  TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
107
  while (!(TWCR & (1 << TWINT)))
108
    ;
109
}
110
111
uint8_t TWIS_ReadAck(void) {
112
  TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
113
  while (!(TWCR & (1 << TWINT))) {
114
    PORTB ^= (1 << PB0);
115
    _delay_ms(100);
116
  }
117
  return TWDR;
118
}
119
120
uint8_t TWIS_ReadNack(void) {
121
  TWCR = (1 << TWINT) | (1 << TWEN);
122
  while (!(TWCR & (1 << TWINT))) {
123
    PORTB ^= (1 << PB0) | (1 << PB1);
124
    _delay_ms(100);
125
  }
126
  return TWDR;
127
}
128
129
_Bool TWIS_ResponseRequired(uint8_t *typ) {
130
  *typ = TWSR;
131
  return (TWCR & (1 << TWINT));
132
}

Jetzt habe ich in meiner main folgendes (da ich gerade kein Display 
habe, lasse ich mir die Zustände auf dem PortB in Form von LEDs 
ausgeben:
1
#define ADRESSE 15
2
#define TWI_BITRATE 100000
3
4
int main(void) {
5
  init();
6
7
  DDRB = 0xff;
8
  PORTB = 0xff;
9
10
  uint8_t TWI_Response = 0;
11
  uint8_t data[8];
12
13
  cli();
14
15
  if (MASTER) {
16
    _delay_ms(1000);
17
    _delay_ms(1000);
18
    if (!TWIM_Init(TWI_BITRATE))
19
      while (1) {
20
        PORTB ^= (1 << PB0) | (1 << PB1);
21
        _delay_ms(100);
22
      }
23
    //else
24
    //  PORTB &= (1 << PB0);
25
  } else {
26
    _delay_ms(500);
27
    if (!TWIS_Init(ADRESSE, TWI_BITRATE))
28
      while (1) {
29
        PORTB ^= (1 << PB0) | (1 << PB2);
30
        _delay_ms(100);
31
      }
32
    //else
33
    //  PORTB &= ~ ((1 << PB1) | (1 << PB0));
34
  }
35
36
  sei();
37
38
  while (1) {
39
40
    if (MASTER) {
41
      if(!i2c_start((52 * 2))) {
42
      //if (TWIM_Start(52, TWI_READ)) {
43
        PORTB &= ~(1 << PB5);
44
        for(int i = 0; i < 7; i++)
45
          data[i] = TWIM_ReadAck();
46
        data[7] = TWIM_ReadNack();
47
        TWIM_Stop();
48
        //PORTB |= (1 << PB5);
49
        PORTB = ~data[4];
50
      } else {
51
        PORTB ^= (1 << PB3);
52
        TWIM_Stop();
53
      }
54
    } else {
55
      if (TWIS_ResponseRequired(&TWI_Response)) {
56
        switch (TWI_Response) {
57
        case TWI_SRX_ADR_ACK:
58
          PORTB = ~(TWIS_ReadNack());
59
          TWIS_Stop();
60
          break;
61
        case TWI_STX_ADR_ACK:
62
          for (int i = 0; i < 8; i++) {
63
            TWIS_Write(PIND);
64
          }
65
          TWIS_Stop();
66
          break;
67
        default:
68
          while (1) {
69
            PORTB = ~(TWI_Response);
70
          }
71
          break;
72
        }
73
      }
74
    }
75
76
    PORTB ^= (1 << PB7);
77
    _delay_ms(100);
78
  }
79
80
  // Never reached
81
  return 0;
82
}

Lieben Dank,
Thomas

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.