Hallo Leute! Möchte gerne mittels I2C eine Verbindung zwischen zwei Atmegas (16 und 32) aufbauen. Leider klappt momentan gar nichts: Für den Master hab ich die lib von Peter Fleury verwendet. Ich hab daran nichts verändern, sollte eigentlich so klappen. Beim Slave bin ich mir da gar net sicher: Der Quellcode ist von Roboternetz (Überschrift: TWI Slave mit avr-gcc). Bin mir net sicher ob des so klappt... Mein Problem besteht momentan einfach darin, dass ich zwei Unbekannte habe, was die Fehlersuche recht schwierig für mich gestaltet. Hat hier irgendjemand eine einfache Routine für mich, mit dem ich zwei AVR´s mittels I2C kommunizieren lassen kann?Also eine für Master und eine für den Slave. Vielen Dank!
Hast du an die Pullupwiderstände gedacht die du zwischen SDA (Daten) und VCC und CSL(Clock) und VCC schalten mußt?
Stelle mal meinen Quellcode online, vllt findet ja jemand den Fehler. Nochmal ne genau Beschreibung was ich in diesem Testprogramm machen will: Habe zwei PollinFunkBoards, die ich über ein IDE-Kabel zusammengeschalten habe. Am 3.Stecker des Kabels hab ich die Pullups reingeschalten (jeweils 2k2). Diese Boards haben am PortD Pin6 eine LED. Ich möchte jetzt dem Slave ein Byte schicken, welches diese LED einschaltet (also 0x01000000). Der Slave soll die Adresse 0x5 haben. Die Master Lib ist von peter Fleury. Die Slave lib von [[http://www.roboternetz.de/wissen/index.php/TWI_Slave_mit_avr-gcc]] rauskopiert. Leider tut sichnach dem Hochladen auf den Controller gar nichts. Hier mein Quellcode für den Master:
1 | #include <avr/io.h> |
2 | #include "i2cmaster.h" |
3 | #define F_CPU 16000000UL
|
4 | #include <util/delay.h> |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | int main(void) |
11 | {
|
12 | |
13 | |
14 | |
15 | i2c_init(); // initialize I2C library |
16 | |
17 | while(1) |
18 | {
|
19 | |
20 | i2c_start_wait(0b1010); /*101 für Adresse 5 und der letzte Nuller für schreiben*/ |
21 | i2c_write(0x01); /*Bufferadresse: möchte in rxbuffer[1] des Slaves schreiben*/ |
22 | |
23 | i2c_write(0b01000000); /*Schreibe 0b01000000 in rxbuffer[1],also Pin 6 wird gesetzt*/ |
24 | i2c_stop(); |
25 | }
|
26 | |
27 | /*Ablauf so korrekt???*/
|
28 | |
29 | }
|
Hier die Routine für den Slave
1 | #include <avr/io.h> |
2 | #include "twislave.h" /*Im Beispiel von Roboternetz als "twislave.c" eingebunden, bringt aber Fehler beim Compilieren*/ |
3 | #define F_CPU 16000000UL
|
4 | #include <util/delay.h> |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | int main() |
11 | {
|
12 | DDRD=0b11111111; |
13 | init_twi_slave (0b101);/*Slave Adressse soll 0x5 sein*/ |
14 | |
15 | |
16 | |
17 | while(1) |
18 | {
|
19 | |
20 | PORTD=rxbuffer[1];/*Soll LED einschalten, die sich am PIND6 befindet*/ |
21 | }
|
22 | |
23 | return 0; |
24 | |
25 | }
|
Findet hier jemand einen Fehler! Wäre echt super, wenn mir jemandhelfen würde, bin am verzweifeln!! Vielen Dank!
Keiner der mir weiter helfen kann? Was ich bis jetzt rausgefunden habe: Die Interruptroutine des Slaves wird nicht aufgerufen. Hab da einen Befehl für ne angeschlossene LED reingetan und LED leuchtet zu keinem Zeitpunkt. Außderdem ist mir ein vermeindlicher Fehler bei der Slave lib aufgefallen: TWAR= adr; laut Datenblatt darf das LSB aber nicht für die Adresse benutzt werden. Hab das umgeändert in: TWAR= (adr<<1); trotzdem kein Erfolg:)
> Hier die Routine für den Slave
wenn das alles an Programm ist, kann der Slave nicht funktionieren.....
Wahrscheinlich hast Du zu wenig von der "Slave lib " kopiert.
Otto
da hast du natürlich recht, dass das nicht alles ist: ich hab beim slave hier eine twislave.h mit eingebunden in die ich den Code von roboternetz (siehe link oben) kopiert habe
Hier mal die Routine für den Slave:
1 | #ifndef _TWISLAVE_H
|
2 | #define _TWISLAVE_H
|
3 | |
4 | #include <util/twi.h> //enthält z.B. die Bezeichnungen für die Statuscodes in TWSR |
5 | #include <avr/interrupt.h> //dient zur behandlung der Interrupts |
6 | #include <stdint.h> //definiert den Datentyp uint8_t |
7 | |
8 | |
9 | |
10 | |
11 | //%%%%%%%% von Benutzer konfigurierbare Einstellungen %%%%%%%%
|
12 | |
13 | #define buffer_size 8 //Größe der Buffer in Byte (2..254)
|
14 | |
15 | |
16 | //%%%%%%%% Globale Variablen, die vom Hauptprogramm genutzt werden %%%%%%%%
|
17 | |
18 | /*Der Buffer, in dem die empfangenen Daten gespeichert werden. Der Slave funktioniert ähnlich wie ein normales
|
19 | Speicher-IC [I2C-EEPROM], man sendet die Adresse, an die man schreiben will, dann die Daten, die interne Speicher-Adresse
|
20 | wird dabei automatisch hochgezählt*/
|
21 | volatile uint8_t rxbuffer[buffer_size]; |
22 | |
23 | /*Der Sendebuffer, der vom Master ausgelesen werden kann.*/
|
24 | volatile uint8_t txbuffer[buffer_size]; |
25 | |
26 | |
27 | //%%%%%%%% Funktionen, die vom Hauptprogramm aufgerufen werden können %%%%%%%%
|
28 | |
29 | /*Initaliserung des TWI-Inteface. Muss zu Beginn aufgerufen werden, sowie bei einem Wechsel der Slave Adresse
|
30 | Parameter: adr: gewünschte Slave-Adresse*/
|
31 | void init_twi_slave (uint8_t adr); |
32 | |
33 | |
34 | |
35 | //%%%%%%%% ab hier sind normalerweise keine weiteren Änderungen erforderlich! %%%%%%%%//
|
36 | //____________________________________________________________________________________//
|
37 | |
38 | #include <util/twi.h> //enthält z.B. die Bezeichnungen für die Statuscodes in TWSR |
39 | |
40 | |
41 | //Bei zu alten AVR-GCC-Versionen werden die Interrupts anders genutzt, daher in diesem Fall mit Fehlermeldung abbrechen
|
42 | #if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
|
43 | #error "This library requires AVR-GCC 3.4.5 or later, update to newer AVR-GCC compiler !"
|
44 | #endif
|
45 | |
46 | //Schutz vor unsinnigen Buffergrößen
|
47 | #if (buffer_size > 254)
|
48 | #error Buffer zu groß gewählt! Maximal 254 Bytes erlaubt.
|
49 | #endif
|
50 | |
51 | #if (buffer_size < 2)
|
52 | #error Buffer muss mindestens zwei Byte groß sein!
|
53 | #endif
|
54 | |
55 | |
56 | volatile uint8_t buffer_adr; //"Adressregister" für den Buffer |
57 | |
58 | /*Initaliserung des TWI-Inteface. Muss zu Beginn aufgerufen werden, sowie bei einem Wechsel der Slave Adresse
|
59 | Parameter: adr: gewünschte Slave-Adresse
|
60 | */
|
61 | void init_twi_slave (uint8_t adr) |
62 | {
|
63 | /**TWAR= adr; Adresse setzen. vermeindlicher Bug!!! Bit0 ist nicht Bestandteil der Adresse!!**/
|
64 | TWAR= (adr<<1); |
65 | TWCR &= ~(1<<TWSTA)|(1<<TWSTO); |
66 | TWCR|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); |
67 | buffer_adr=0xFF; |
68 | sei(); |
69 | |
70 | }
|
71 | |
72 | |
73 | //Je nach Statuscode in TWSR müssen verschiedene Bitmuster in TWCR geschreiben werden(siehe Tabellen im Datenblatt!).
|
74 | //Makros für die verwendeten Bitmuster:
|
75 | |
76 | //ACK nach empfangenen Daten senden/ ACK nach gesendeten Daten erwarten
|
77 | #define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
|
78 | //NACK nach empfangenen Daten senden/ NACK nach gesendeten Daten erwarten
|
79 | #define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
|
80 | //switched to the non adressed slave mode...
|
81 | #define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
|
82 | |
83 | //Die Bitmuster für TWCR_ACK und TWCR_RESET sind gleich. Dies ist kein Fehler und dient nur der Übersicht!
|
84 | |
85 | |
86 | /*ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann
|
87 | ein Statuscode, anhand dessen die Situation festgestellt werden kann.
|
88 | */
|
89 | ISR (TWI_vect) |
90 | {
|
91 | uint8_t data=0; |
92 | PORTD=32;/*Test: rechte LED sollte leuchten*/ |
93 | |
94 | |
95 | switch (TW_STATUS) //TWI-Statusregister prüfen und nötige Aktion bestimmen |
96 | {
|
97 | |
98 | case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert |
99 | TWCR_ACK; // nächstes Datenbyte empfangen, ACK danach |
100 | buffer_adr=0xFF; //Bufferposition ist undefiniert |
101 | break; |
102 | |
103 | case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen |
104 | data=TWDR; //Empfangene Daten auslesen |
105 | if (buffer_adr == 0xFF) //erster Zugriff, Bufferposition setzen |
106 | {
|
107 | |
108 | //Kontrolle ob gewünschte Adresse im erlaubten bereich
|
109 | if(data<=buffer_size) |
110 | {
|
111 | buffer_adr= data; //Bufferposition wie adressiert setzen |
112 | }
|
113 | else
|
114 | {
|
115 | buffer_adr=0; //Adresse auf Null setzen. Ist das sinnvoll? |
116 | }
|
117 | TWCR_ACK; // nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern |
118 | }
|
119 | else //weiterer Zugriff, Daten empfangen |
120 | {
|
121 | rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben |
122 | buffer_adr++; //Buffer-Adresse weiterzählen für nächsten Schreibzugriff |
123 | if(buffer_adr<(buffer_size-1)) //im Buffer ist noch Platz für mehr als ein Byte |
124 | {
|
125 | TWCR_ACK;// nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern |
126 | }
|
127 | else //es kann nur noch ein Byte kommen, dann ist der Buffer voll |
128 | {
|
129 | TWCR_NACK;//letztes Byte lesen, dann NACK, um vollen Buffer zu signaliseren |
130 | }
|
131 | }
|
132 | break; |
133 | |
134 | case TW_ST_SLA_ACK: //?!? |
135 | case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert |
136 | |
137 | if (buffer_adr == 0xFF) //zuvor keine Leseadresse angegeben! |
138 | {
|
139 | buffer_adr=0; |
140 | }
|
141 | TWDR = txbuffer[buffer_adr]; //Datenbyte senden |
142 | buffer_adr++; //bufferadresse für nächstes Byte weiterzählen |
143 | if(buffer_adr<(buffer_size-1)) //im Buffer ist mehr als ein Byte, das gesendet werden kann |
144 | {
|
145 | TWCR_ACK; //nächstes Byte senden, danach ACK erwarten |
146 | }
|
147 | else
|
148 | {
|
149 | TWCR_NACK; //letztes Byte senden, danach NACK erwarten |
150 | }
|
151 | break; |
152 | |
153 | case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert |
154 | case TW_SR_DATA_NACK: //0x88 |
155 | case TW_ST_LAST_DATA: //0xC8 Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received |
156 | case TW_SR_STOP: // 0xA0 STOP empfangen |
157 | default:
|
158 | TWCR_RESET; //Übertragung beenden, warten bis zur nächsten Adressierung |
159 | break; |
160 | |
161 | |
162 | } //end.switch (TW_STATUS) |
163 | } //end.ISR(TWI_vect) |
164 | |
165 | |
166 | #endif //#ifdef _TWISLAVE_H
|
167 | ////Ende von twislave.c////
|
Alles was ich benötige ist eine Funktionierendes Beispiel um 2 uC per I2C kommunizieren zu lassen.... Man hört von i2c sehr viel interessante Sachen, gerade im Roboterbereich, aber funktionierende Routinen findet man (ich) nicht:(
Doch - in der Codesammlung - das Assemblerbeispiel z. B. funktioniert einwandfrei. Das C-Besipiel: Beitrag "AVR TWI Master und Slave Funtionen in C" habe ich nicht getestet. Evtl. versuchst Du es mal damit. Gruss Otto
Assembler möcht ich nicht nehmen, da ich neben dem Bus noch viele weitere Funktionen implemetieren muss.Aber Danke schön! Im Moment kenn ich mich gar nimmer aus: Dein vorgeschlagenes Beispiel, löst das den ein Interrupt beim Slave aus? Die Verzweiflung zwingt mich jetzt ins Bett, vllt versteh ich morgen früh wieder mehr. Trotzdem vielen Dank!
Du schriebst, dass Du keine Beispiele findest. Daher der Hinweis auf die Codesammlung. Evtl. vergleichst Du den anderen Slave mit Deinem, um den Fehler einzugrenzen. Die Slave-Adresse 0x5 ist mir persönlich ein wenig suspekt. Otto
Bin jetzt einen kleinen Schritt weitergekommen: Der Befehl "i2c_start_wait()" wartet ja anscheinend solange, bis sich der anzusprechende Slave meldet. ich hab nach diesem Befehl eine Portausgabe gemacht und eine LED angesprochen. Diese leuchtet auch tatsächlich, wenn ich die richtige Adresse eingeben (aber auch wenn falsche adresse und sehr oft reset bei master und slave, wohl aber eher dann ein zufälliges verhalten). Das heißt also: Der Slave reagiert schon. Nur die interruptroutine wird immer noch nicht aufgerufen...?? Welche Bedingungen müssen eigentlich herrschen, damit diese aufgerufen wird? Ausm Datenblatt werd ich momentan net schlau . 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.