Probleme TWI (I2C) Atmega 16 Im Unterforum Microcontroller - Beschreibung: Hardware - Software - Ideen - Projekte
Autor |
Probleme TWI (I2C) Atmega 16 Suche nach: i2c (581) atmega (404) |
|
|
|
|
BID = 698407
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
|
Jupi!!!!!
Mit der Zip is es jetzt bombig. Kann alles ohne Probleme lesen.^^ Das Programm muss ich aber morgen testen, jetzt ist es ein wenig zu spät. xD
Aber ein rießen Dankeschön für dein Engagement!!!!
Gruß Bastian |
|
BID = 698408
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
|
Offtopic :
| Wieso - ist doch erst 3:08 -_- |
_________________
|
|
BID = 698481
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
Ohje, bin langsam am verzweifeln.... Bin schon die ganze Zeit am durchprobieren und am Vergleichen, aber irgendwie klappt immernoch nix. Glaub langsam, dass ich einfach zu unfähig dafür bin... Hab jetzt alles abgeändert und nochmal mit deiner Lib verglichen. Eigentlich müsste alles stimmen nach meiner Meinung...
PullUp-Widerstände sind drin, die zwei Leitungen muss man ja nur 1 zu 1 durchverdrahten. Und sonst wüsste ich auch net, was man am Aufbau noch falsch machen könnte.
Statusmeldung wird leider immernoch die Gleiche angezeigt, das heißt, dass denk ich mal mit der Adressierung irgendwas nicht stimmt. Der Master sendet 0x04 und der Slave hat die Adresse 0x02.
Kann nur nochmal mein Programm posten, in der Hoffung, dass du vielleicht doch noch einen Fehler findest. Bin langsam mit meinem Latein am Ende...
Master:
Code : |
#define F_CPU 8000000UL
#include <avr/delay.h>
#include <avr/io.h>
void i2c_init(void)
{
TWSR = 0; // kein Vorteiler
TWBR = 32; // Da Quartz bei 8 MHz
}
void start_i2c()
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // Starte I2C
while (!(TWCR & (1<<TWINT))); // Warte, bis fertig
}
void stop_i2c()
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // Stoppe I2C
// Hier darf keine Warteabfrage hin, da I2C gestoppt ist.
}
void senden_i2c(char daten)
{
TWDR = daten; // Sende Daten
TWCR = (1<<TWINT) | (1<<TWEN);
while( !(TWCR & (1<<TWINT)) );
}
unsigned char i2c_empfangen(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}
int main (void)
{
DDRB=0xFF;
PORTB=0xFF;
i2c_init();
int daten2 = 0xAA;
while(1)
{
PORTB = 0x01;
// Sende 0xAA an Slave 1
start_i2c(); // Start I2C
_delay_ms(500);
PORTB = 0x02;
senden_i2c(0x04); // Adressierung Slave 1
_delay_ms(500);
PORTB = 0x03;
senden_i2c(daten2); // Daten übertragen
_delay_ms(500);
stop_i2c();
PORTB = 0x04;
}
}
|
|
Slave:
Code : |
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#include <avr/delay.h>
#include <avr/io.h>
#define enable_interrupts() asm volatile ( "sei" )
#define disable_interrupts() asm volatile ( "cli" )
uint8_t twi_flag;
ISR(TWI_vect)
{ /* wir wurden gerade adressiert */
twi_flag = 1;
}
void i2c_init (uint8_t const Address)
{
TWBR = 0;
TWAR = Address;
TWCR = 1<<TWEN|1<<TWIE|1<<TWEA;
}
unsigned char i2c_empfangen(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}
int daten = 0x00;
int main(void)
{
DDRA=0xFF;
PORTA=0xFF;
enable_interrupts(); // Interrupts anschalten um TWINT zu ermöglichen
i2c_init(0x02);
while(1)
{
PORTA = TWSR;
if ( twi_flag == 1)
{
PORTA = TWSR;
disable_interrupts();
PORTA = 0x02;
_delay_ms(500);
PORTA = TWSR;
TWCR |= (1<<TWEA); //TWEA auf 1 setzten um Ack zu senden
PORTA = 0x03;
daten = i2c_empfangen();
_delay_ms(500);
PORTA = TWSR;
PORTA = daten;
twi_flag = 0;
enable_interrupts();
}
}
}
|
|
Gruß Bastian
|
BID = 698555
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Hallo,
du hast leider immer noch nicht genau verstanden, wie der Bus funktioniert bzw. die Hardware im AVR.
(Welchen nutzt du gerade nochmal?)
Also:
Du initialisierst beim Slave die Hardware mit
TWAR = Address;
.
Aufrufen tust du die Funktion mit der Adresse 0x2. Schaut man sich das Register TWAR aber an, sieht man, dass das LSB (das unterste, kleinste Bit) nicht zur Adresse gehört! Dieses Bit muss auf 0 geschrieben werden, wenn man regulär (über die eigene Adresse) adressiert werden soll. So, 0x2 in diesem Register bedeutet, dass das 2. Bit 1 ist. Dort liegt aber nunmal das erste Adsressbit. Also hat dein Slave im Endeffekt nur die Adresse 0x1 und nicht 0x2. Das hatte ich bereits 20mal erwähnt und so ist das auch in meiner Bibliothek implementiert. Dort wird die übergebene Adresse um ein Bit nach links verschoben. Auf das LSB wandert automatisch eine 0.
Es muss also TWAR = Address << 1; heißen.
Der Master sollte soweit stimmen, setze aber mal den Wert für TWBR auf 64. Dann liegst du bei gut 50kHz und nicht 100kHz SCL-Takt.
Schreibe die Empfangsroutine folgendermaßen um:
uint8_t daten;
if( twi_flag )
{
twi_flag = 0;
daten = i2c_receive(NACK);
}
Und fertig.
Erklärung:
Die TWI-Hardware wartet auf die eigene Adressierung. Sobald ihre Adresse empfangen wurde, bestätigst sie den Empfang automatisch mit ACK und es wird das entsprechende Interrupt ausgeführt. Dort wird die Flagge twi_flag gesetzt und die ISR beendet.
Im Hauptprogram fragst du sie immer wieder ab, bis sie gesetzt ist. Wenn dem so ist, löscht du sie wieder.
Dann holst du mit i2c_receive(NACK); die Daten ab. Die Adresse wurde ja schon empfangen. Du musst unbedingt ein NACK (nicht ACK) zurücksenden, damit der Master weiß, dass die Verbindung nach einem Byte beendet wurde und der Slave keine weiteren Daten mehr will. Sendet der Slave jedoch ein ACK zurück, sendet der Master das nächste Byte usw.
Deswegen ist
TWCR |= (1<<TWEA); //TWEA auf 1 setzten um Ack zu senden
PORTA = 0x03;
daten = i2c_empfangen();
auch so fatal, weil du die gesamte Transaktion unterbrichst / cancelst, weil du einfach so TWCR änderst! Das passiert jedoch nur in i2c_empfangen bzw. meiner Routine i2c_receive(NACK).
In i2c_empfangen() jedoch bestätigst du grundsätzlich mit ACK. Die Verbindung muss aber mit NACK abgebaut werden. Daher ist diese Routine schlecht.
Offtopic :
|
Hier sieht man schon, wie wichtig es ist, die Statuskodes auszuwerten: wurde der Slave adressiert, weiß er erstmal noch nicht, ob der Master Daten von ihm haben will, oder ob er Daten entgegen nehmen soll.
In diesem Fall weißt du ja schon, dass der Master den Slave immer nur schreibend adressiert. Aber sobald die Möglichkeit gegeben ist, dass der Master auch mal lesen will, musst du über die Statuskodes herausfinden, was der Master will.
Denn davon ist essentiell abhängig, wie der Programmfluss weitergeht. Sendet der Master SLA+R, du reagierst aber nicht drauf, und wartest auf ankommende Daten (die While-Schleife wird zur Endlosschleife), stürzen beide Systeme ab, Master und Slave.
Wählt man die asynchrone Übertragung, stürzt nichts ab, es kommt aber auch nicht zu einem Datenaustausch.
Merke also: sobald mehr als nur eine Datenrichtung und Datenlänge im Protokoll vorkommen kann, müssen die Statuskodes ausgewertet werden.
|
Und edit:
Nimm bitte endlich als Datentyp entweder unsigned char, char oder gleich ordentlich uint8_t statt int.
int hat per Definition mindestens 16 Bit Wortbreite und der Compiler hält sich bis auf einige Ausnahmen auch daran.
int auf AVRs ist nicht, wie man meinen sollte, 8 Bit breit sondern eben, da so standardisiert, mindestens 16 Bit groß, also auch bei AVRs.
Man kann den Standard abschalten, indem man die Compiler-Flagge -mint8 setzt.
Das ist wie gesagt unschön. Daher sollte man gleich die schönen und eindeutigen Datentypen uintN_t, intN_t usw. nehmen.
Die liegen im Header inttypes.h.
Wenn du sie nicht hast, machst du sie dir selbst:
typedef unsigned char uint8_t;
_________________
[ Diese Nachricht wurde geändert von: DonComi am 25 Jun 2010 20:09 ]
|
BID = 698720
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
So, hab jetzt die Adressierung wieder geändert. Hatte das mit dem Verschieben vorher eigentlich drin, aber aus Verzweiflung hab ich es dann doch nochmal rausgemacht zum probieren. Die Hoffnung stirbt zuletzt.^^ Aber irgendwas muss da noch sein, dass der Slave nichts empfängt glaub ich. Hab jetzt die main so geändert.
int main(void)
{
DDRA=0xFF;
PORTA=0xFF;
enable_interrupts(); // Interrupts anschalten um TWINT zu ermöglichen
i2c_init(0x01);
while(1)
{
PORTA = TWSR;
uint8_t daten;
if( twi_flag )
{
PORTA = TWSR;
twi_flag = 0;
daten = i2c_empfangen(NACK);
}
}
Also müsste sich ja auf meinem PortA der Zustand von TWSR ändern, wenn er richtig adressiert ist bzw richtig arbeitet bis dahin. Aber leider passiert immernoch nix. Ich glaub langsam, dass es einfach nur ein kleiner dummer Fehler is, der so ne rießen auswirkung hat. Sprich einfach ein leichtsinnsfehler, der man gern übersieht. Aber ich komm einfach net drauf...
Die inttypes.h hab ich übrigens auch noch mit eingebunden und die variablen dementsprechend abgeändert.
Aber komischerweise zeigt er mir bei i2c_empfangen(NACK) noch nen Fehler an:
../TA_SLAVE.c:65: error: too many arguments to function 'i2c_empfangen'
obwohl ich wie bei dir in der lib noch das
#define ACK 1<<TWEA
#define NACK 0<<TWEA
reingemacht hab.
Aber ich wäre froh, wenn ich schon so weit wäre. Der größte Schritt ist einfach, dass der Slave mal antworten soll.^^ Aber das komische ist daran, dass es eigentlich funktionieren sollte, aber einfach net tut...
Gruß Bastian
|
BID = 698726
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Och man,
es macht so keinen Spaß...
Nimm doch endlich mal meine lib, wenn es damit klappt, kannst du die meinetwegen komplett umschreiben, wenn dir danach ist.
Oder schreib wenigstens korrekt ab und nicht nur so halbe Sachen.
Wie soll denn i2c_empfangen(NACK); funktionieren, wenn du das Argument in der Definition von i2c_empfangen(void) nicht aufnimmst? Außerdem muss es natürlich noch mit dem Registerinhalt verodert werden.
Du initialisierst übrigens erneut mit falscher Adresse. Da muss weiterhin 0x2 für den Slave sein, die Adresse, der der Master schickt ist dementsprechend 0x4. Die implizite 0 im LSB steht dabei für "schreiben".
Und in i2c_init bitte die Adresse, wie tausendmal erläutert, um ein Bit nach links schieben oder meinetwegen mit 2 multiplizieren, ist das selbe.
Dann lad mal alle C-Dateien, vom Master und Slave hoch. Komplett, nichts weglassen.
Weiterhin male bitte exakt auf, wie die beiden AVRs verschaltet sind, mit jedem Kondensator, mit jedem Widerstand.
Und bitte exakt so, wie es in der Wirklichkeit zusammengeschaltet ist, nicht, wie es sein sollte!
GGfs. Foto vom Aufbau.
Oszilloskop vorhanden?
Wenn ja, dann ist spätestens jetzt die Zeit gekommen, die beiden Leitungen mal elektrisch zu betrachten. Außerdem solltest du, immer wenn sich TWINT ändert, den Statuskode ausgeben und aufschreiben, ich werte sie dir sogar aus.
Muss doch endlich mal weitergehen hier.
P.S.: nimm mal eine andere Adresse bitte: der Slave soll 0x46 haben (also i2c_init(0x46);, der Master schickt als Adresse 0x8C.
Vielleicht waren gerade diese niedrigen Adresse der Grund dafür, dass es nicht klappt.
_________________
|
BID = 698777
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
So, ich hoffe du schlägst mich jetzt nicht.^^
Habe jetzt 2 neue Projekte gemacht und hab beidemale erstmal deine C und H Dateien eingebunden. (Ich weiß, ich bin unwürdig deine Sachen zu verpfrimeln , aber ich wollte einfach jede mögliche Fehlerquelle ausschließen) Und dann habe ich noch meine Funktionen reingepackt. Also beim Master die main() und beim Slave die main() , die ISR usw, und natürlich noch die Namen der Funktionen geändert in den beiden main() von mir. Ich hoffe du bist mir nicht böse, wenn ich deine Arbeit quasi so verschandle und lässt nochmal Gnade vor Recht walten.^^
Aber komischerweise habe ich nun auf meinem Slave einen anderen Statuscode. Nämlich 01101010 also 0x6A, welcher sich aber leider wieder nicht ändert. Der Master läuft wie gehabt durch und zeigt nacheinander die binäre 1,2 und 3 auf den LED's an PORTA an. Wenn ich aber beim Master die anzeige von 0x01, 0x02, 0x03 nach jedem Schritt zu TWSR ändere, bleibt diese anzeige nun bei 10100011 also 0xA3 und ändert sich auch nichtmehr.
Im Anhang hab ich mal beide C-Codes, eine Zeichnung der Schaltung und ein Bild per Digicam(Leider nicht so gute Qualität, weil es ne billig Digicam is).
P.S. Wie gesagt, ich hoffe du lässt nochmal Gnade vor Recht walten.^^ Ich weiß ich bin glaub ein schwieriger Fall, aber ich will das Projekt endlich fertig bekommen und bringe es wohl leider nicht alleine auf die Reihe.
Gruß Bastian
|
BID = 698779
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Sag nicht, dass du die beiden Pull->>>Up<<<--Widerstände nach Masse geschaltet hast, so wie es im Schema zu sehen ist.
_________________
|
BID = 698781
Kleinspannung Urgestein
Beiträge: 13360 Wohnort: Tal der Ahnungslosen
|
Zitat :
DonComi hat am 26 Jun 2010 23:39 geschrieben :
|
Sag nicht, dass du die beiden Pull->>>Up<<<--Widerstände nach Masse geschaltet hast,
|
Wetten das?
_________________
Manche Männer bemühen sich lebenslang, das Wesen einer Frau zu verstehen. Andere befassen sich mit weniger schwierigen Dingen z.B. der Relativitätstheorie.
(Albert Einstein)
|
BID = 698783
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Ein Kasten Bier
Also, die Programme habe ich mir angeschaut - sie sind zwar nicht (mehr ) so schön wie vorher, sollten so aber funktionieren.
Also, Pullup-Widerstände von SCL und SDA nach +5V (nimm 4k7 - 10kΩ), und spendiere bitte beiden µCs einen Kondensator 100nF (egal ob Folie oder Keramik) von GND nach +5V. Es müssen nicht genau 100nF sein, aber diese Größenordnung.
Dazu noch einen Elko 1-10µF parallel zum kleinen 100nF.
(Es sollte auch so schon gehen, aber diese Kondensatoren stützen beide die Versorgung der AVRs.)
Edit:
Noch zwei Stunden vielleicht Uni-Berichte schreiben, dann hol ich mein raus...)
_________________
[ Diese Nachricht wurde geändert von: DonComi am 26 Jun 2010 23:49 ]
|
BID = 698785
Kleinspannung Urgestein
Beiträge: 13360 Wohnort: Tal der Ahnungslosen
|
Zitat :
DonComi hat am 26 Jun 2010 23:48 geschrieben :
|
Ein Kasten Bier
|
Offtopic :
|
Ok,gilt.
Wenn der Pull-Down gebaut hat,zahlt er,wenn nicht kriegste einen von mir.
|
_________________
Manche Männer bemühen sich lebenslang, das Wesen einer Frau zu verstehen. Andere befassen sich mit weniger schwierigen Dingen z.B. der Relativitätstheorie.
(Albert Einstein)
|
BID = 698815
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
Ne hab ich nicht.^^ Sorry, war in der Zeichnung falsch. xD
P.S. Die uCs hängen an der selben Spannungsversorgung von der ISP-Schnittstelle. Ist des schlimm?^^ Wenn nein, also nur ein Kondensator? Eigentlich sollte es am Aufbau auch nicht liegen, da ja meine Temperaturauswertung mit dem Selben Aufbau auch schon funktioniert hat.
Gruß Bastian
[ Diese Nachricht wurde geändert von: terrorfreak am 27 Jun 2010 2:02 ]
[ Diese Nachricht wurde geändert von: terrorfreak am 27 Jun 2010 2:03 ]
|
BID = 698816
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Also,
Systematischer:
Sind die Pegel auf SDA und SCL im Ruhezustand auf 5V?
Hast du ein Oszi?
Gebe bitte nach jeder Aktion wie i2c_start(), i2c_transmit(), ... , die Statuskodes aus und schreibe sie mir in der Form Aktion: Statuskode (in Hex oder binär, aber dann bitte richtig).
Sie sind wie folgt auszugeben: PORT = TWSR & 0xf8;
Denke daran: die unteren drei Bits müssen dann immer null sein. Es geht gar nicht anders.
Das wird uns die Lösung des Problem bringen, aber ich will alle Statuskodes haben. Vom Master und vom Slave und bitte so, dass ich sie eindeutig zuordnen kann. Sprich: auch dreimal gleichwertig vorgehen und nicht zu schnell posten. Lieber ordentlich und etwas langsamer als schnell und falsch.
Edit:
Zitat :
| der selben Spannungsversorgung von der ISP-Schnittstelle |
Wieviel kann die denn liefern (in Ampere?) Mit deinen 16 Leuchtdioden belastest du sie aber schon deutlich. Es kann sein, dass du durchaus Einbrüche hast, die den µC zum Neustart zwingen (Brownout)!
Dann können wir uns noch lange unterhalten, ohne Lösung...
_________________
[ Diese Nachricht wurde geändert von: DonComi am 27 Jun 2010 2:17 ]
|
BID = 698818
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
kk, dann werd ich morgen erstmal noch nen festspannungsregler wieder mit reinmachen. Des Netzteil war gestern auf nem gig für mein Funk im Einsatz.^^
|
BID = 698903
terrorfreak Neu hier
Beiträge: 36 Wohnort: Weikersheim
|
Also ich habe jetzt mehrere Versuche gestartet. Beim Master kommt immer der Statuscode 11101000 und beim Slave 11111000. Bei beiden ohne Änderung. Hatte aber beim Master auch 1-mal 11111000 und 1-mal 10101000. Aber das war nur jeweils 1-mal bei ca 15 Versuchen.
Ich hoffe, damit kannst du was anfangen. Ich leider nicht.^^
Gruß Bastian
P.S. Bei den obigen Versuchen war die Spannungsquelle immer mein Festspannungsregler. Wenn ich nur die ISP-Spannung (also von USB) nehme, habe ich beim Master 10100000 und beim Slave immernoch 11111000 nonstop.
[ Diese Nachricht wurde geändert von: terrorfreak am 27 Jun 2010 15:15 ]
P.P.S. Wie würdest du das Programm schreieben? Vielleicht liegts doch an meiner Art zu programmieren... Also ich mein, weil ich halt doch noch blutiger Anfänger bin.^^
[ Diese Nachricht wurde geändert von: terrorfreak am 27 Jun 2010 15:18 ]
|
|
Zum Ersatzteileshop
Bezeichnungen von Produkten, Abbildungen und Logos , die in diesem Forum oder im Shop verwendet werden, sind Eigentum des entsprechenden Herstellers oder Besitzers. Diese dienen lediglich zur Identifikation!
Impressum
Datenschutz
Copyright © Baldur Brock Fernsehtechnik und Versand Ersatzteile in Heilbronn Deutschland
gerechnet auf die letzten 30 Tage haben wir 19 Beiträge im Durchschnitt pro Tag heute wurden bisher 3 Beiträge verfasst © x sparkkelsputz Besucher : 182421539 Heute : 578 Gestern : 5459 Online : 308 29.11.2024 6:13 1 Besucher in den letzten 60 Sekunden alle 60.00 Sekunden ein neuer Besucher ---- logout ----viewtopic ---- logout ----
|
xcvb
ycvb
0.0787498950958
|