Forum: Mikrocontroller und Digitale Elektronik I2C Ansteuerung ATMega128


von Bernhard G. (bgwh)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich soll eine I2C Interface zwischen einem PIC (dsPIC30f6014A) als 
Master und einem ATMEL als Slave (ATMega128) herstellen. Ich habe auch 
soweit die Software fertig und auch das Signal des PIC ist soweit in 
Ordnung, nur leider reagiert der TWI Interrupt am Atmel nicht!!

Hier das Ausgangssignal des PIC: Gesendet wird zuerst 0xC4 (0x62 
Slave-Adresse und als LSB 0, da es win Writezyklus ist:
(habe es als Anhang hinzugefügt)


Nun zum Atmel, der irgendwie nichts mit dem Signal anfangen kann bzw. 
nicht reagiert.
Das ist mein Assembler Code für den Atmel-Slave:
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <avr/wdt.h>
4
#include <util/delay.h>
5
#include <math.h>
6
#include <avr/pgmspace.h>
7
8
#include <util/twi.h> //enthält z.B. die Bezeichnungen für die Statuscodes in TWSR
9
#include <avr/interrupt.h> //dient zur behandlung der Interrupts
10
#include <stdint.h> //definiert den Datentyp uint8_t
11
12
#define SLAVE_ADRESSE 0x62
13
14
#define SIG_2WIRE_SERIAL _VECTOR(34)  // Interrupt Vektor für TWI
15
16
void init_twi_slave (uint8_t adr);
17
void delay_ms(unsigned int period);
18
19
extern const prog_uint8_t Font1[], Font2[];
20
uint8_t data=0;
21
uint8_t contr=0;
22
23
int main(void)
24
{
25
   LCD_Init();
26
   delay_ms(1000);
27
   init_twi_slave(SLAVE_ADRESSE);
28
   
29
   Orientation = Landscape;      
30
   LCD_Cls(yellow);
31
   delay_ms(1000);
32
  
33
   while(1)
34
   {
35
      if(data != 0)
36
      {
37
    switch(data)
38
    {
39
       case '1':
40
                    ...
41
        break;
42
           
43
       case '2':
44
                    ...
45
        break;
46
         
47
       case '3':
48
                    ...
49
        break;
50
           
51
       default:
52
                    ...
53
    }
54
    data = 0;
55
      }
56
   } 
57
   return 0;
58
  
59
}
60
61
void init_twi_slave (uint8_t adr)
62
{
63
    TWAR = 0xC4;   //Slave-Addr.: 0x62 (Bit1-Bit7)
64
       //General Call deaktivieren (Bit0)
65
  
66
    TWCR &= ~((1<<TWSTA)|(1<<TWSTO));  // TWSTA und TWSTO auf 0 setzen
67
      //TWEA...TWI Enable Acknowledge Bit
68
      //TWEN...TWI Enable
69
      //TWIE...TWI Interrupt Anforderung erlauben
70
    TWCR |= (0<<TWEA)|(1<<TWEN)|(1<<TWIE);
71
72
    sei();    //enable global interrupts
73
}
74
75
76
//TWI ISR
77
SIGNAL(SIG_2WIRE_SERIAL)
78
{
79
    LCD_Cls(green);
80
    delay_ms(1000);
81
  
82
  ...
83
}


Hoffe es hat jemand einen Tipp warum die Übertragung nicht funktioniert. 
Bin schon leicht verzweifelt, wäre also über jede Art von Hilfe 
dankbar!! :)
Vielleicht hat auch schon jemand einen ATMega als Slave verwendet und 
könnte mir da ein paar Tipps geben.

Schoene Grueße
 Bernhard

von Dennis (Gast)


Lesenswert?

-  es ist ein C-Programm, kein ASM :-)

- "SIGNAL" gibt es schon eine Weile nicht mehr, statt dessen ISR

- INT: TWI_vector

von BGWH (Gast)


Lesenswert?

@Dennis: Erstmals Danke für deine rasche Antwort

[quote]
-  es ist ein C-Programm, kein ASM :-)
[/quote]

:) okay danke. Ist zum ersten Mal, dass ich ein uC-Programm in C und 
nicht in Assembler schreibe, deshalb noch kleine Verwirrungen. :)

[quote]
- "SIGNAL" gibt es schon eine Weile nicht mehr, statt dessen ISR
- INT: TWI_vector
[/quote]

Okay habe ich geändert. Aber bedeutet beides dasselbe und hat auch an 
der Funktion nichts geändert.

Im File iom128.h (wo die Makros sind) steht:
 #define TWI_vect    _VECTOR(33)
obwohl der TWI Interrrupt eigentlich laut Datenblatt Nummer34 ist, zählt 
da der Reset Interrupt nicht??

Vielleicht hat noch jemand andere Vorschläge, wieso die Verbindung nicht 
geht, wäre sehr dankbar!!

Sg Bernhard

von Jörg X. (Gast)


Lesenswert?

Und das TWEA Bit musst du natürlich setzen, wenn der Atmega reagieren 
soll (also ein ACK senden soll...)
Außerdem würde ich die Init() vereinfachen:
1
void init_twi_slave (uint8_t adr)
2
{
3
    TWAR = SLAVE_ADRESSE << 1 | (0<<TWGCE);
4
    //General Call deaktivieren (Bit0)
5
  
6
    TWCR = (0<<TWSTA)
7
          |(0<<TWSTO)  
8
          |(1<<TWEA)  // auf adresse reagieren
9
          |(1<<TWEN)  // TWI aktiv
10
          |(1<<TWIE); // Interrupt an
11
}
und nur ein "sei()", vor der main-loop

hth. Jörg

ps. vergleiche mal die Nummerierung im Datenblatt und im io*.h-File 
(stichwort: "offset")

von Bernhard G. (bgwh)


Lesenswert?

Danke schön für eure Hilfe!! Die Übertragung funktioniert jetzt 
wunderbar!!

Da dieses Forum echt toll ist und sehr schnell beantwortet wird hätte 
ich bitte noch ein paar ganz kurze Fragen zur Bitadressierung in C:

1. Was heißt z.B. was Jörg X. geschrieben hat:
 SLAVE_ADRESSE << 1   bedeutet das, dass ab Bit 1 die Slave Adresse 
hinzugefügt wird??

2. Was ist der Unterschied zwischen:

 TWCR |= 1<<TWINT;    und   TWCR = 1<<TWINT;   ??

Ich meine er setzt doch bei beiden nur das TWINT-Bit? Oder werden beim 
rechten, wenn es nicht noch verodert wird, die anderen Bits auch 
geändert bzw, gelöscht??

3. Warum müssen, wenn man mehrere Bits löschen bzw. setzen will die 
einzelnen Elemente verodert werden??:
 z.B. TWCR = (0<<TWSTA)
            |(0<<TWSTO)
            |(1<<TWEA)  // auf adresse reagieren
            |(1<<TWEN)  // TWI aktiv
            |(1<<TWIE); // Interrupt an


Schoene Grueße
 Bernhard

von Matthias (Gast)


Lesenswert?

>1. Was heißt z.B. was Jörg X. geschrieben hat:
> SLAVE_ADRESSE << 1   bedeutet das, dass ab Bit 1 die Slave Adresse
>hinzugefügt wird??

Es Bedeutet, dass der Wert SLAVE_ADRESSE um 1 Bit nach links geschoben 
wird.
Oder mathematisch: Eine Multiplikation mit 2 stattfindet. Bei der I2C 
Adresse ist ja das unterste Bit das R/W Flag.

>Was ist der Unterschied zwischen:

> TWCR |= 1<<TWINT;    und   TWCR = 1<<TWINT;   ??

>Ich meine er setzt doch bei beiden nur das TWINT-Bit? Oder werden beim
>rechten, wenn es nicht noch verodert wird, die anderen Bits auch
>geändert bzw, gelöscht??

Richtig. Beim rechten werden die restlichen Bits gelöscht.

Die 1 wird ja als "0000 0001" interpretiert. Und TWINT hat z.B. (ich 
such jetzt nicht im datenblatt) den Wert 2. Also wird "0000 0001" um 2 
Bits nach links geschoben => "0000 0100" und dann ins TWCR Register 
geschrieben. Wie man sieht, sind die anderen Bits alle 0. Deshalb werden 
für Bitmaipulationen
auch sog. Read-Modify-Write Routinen benötigt. (siehe AVR-C Tutorial).

>3. Warum müssen, wenn man mehrere Bits löschen bzw. setzen will die
>einzelnen Elemente verodert werden??:
> z.B. TWCR = (0<<TWSTA)
>            |(0<<TWSTO)
>            |(1<<TWEA)  // auf adresse reagieren
>            |(1<<TWEN)  // TWI aktiv
>            |(1<<TWIE); // Interrupt an

Das mit dem (0<<TWSTA) ist für einen Neuling vielleicht nicht ganz 
nachvollziehbar. Es dient hier nur der Information des Programmieres.
Explizit löschen tut das das Bit an der Stelle nicht. Der 
Programmierstil dient vor allem dazu, dass man weiss, welche Bits man 
nicht setzen will (man könnte ja was vergessen haben) und für "faule" 
Programmierer, dass man nur die 0 zuur 1 oder umgekehrt ändern muss, 
wenn man mehrere Tests mit verschiedenen Bitkombinationen macht.

von Bernhard G. (bgwh)


Lesenswert?

@Matthias:

 Vielen Dank für deine ausführlichen Antworten!! Hat mir sehr geholfen!!


Schoene Grueße
 Bernhard

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.