PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Über I2C den Akkuwert aus dem Atmel auslesen



PIC-Nico
26.08.2011, 17:33
Hallo zusammen,
ich versuche mich derzeit zum ersten mal am I2C Bus. Mein Vorhaben ist, dass ich den digitalen 10 Bit Akkuwert aus dem RP6 bzw. aus dem Atmel auf der Hauptplatine auslesen möchte. Ich habe auf einer Erweiterungsplatine einen PIC18F2550 mit 8Mhz Keramik Resonator, welcher mit SDL(RB0) und SDC(RB1) am I2C Bus des RP6 hängt (Die Pins sind als Eingang geschaltet). In den RP6 habe ich das Beispielprogramm RP6Base_I2CSlave.hex geladen.

Durch das Handbuch des RP6 und meinen sonstigen Kenntnissen über den I2C Bus habe ich mir das Vorhaben folgendermaßen (vereinfacht dargestellt) vorgestellt:


Vom Master (PIC) zum Slave (AVR) sende ich die Adresse des Slave (dez.: 10)
Hier die Zeile zur Slave Adresse aus der RP6Base_I2CSlave.c Datei:

// The Slave Address on the I2C Bus can be specified here:
#define RP6BASE_I2C_SLAVE_ADR 10


Vom Master zum Slave sende ich ein String: I2C_REG_ADC_UBAT_L
Vom Slave lese ich nun den Low-Wert ein
Das selbe nochmal mit dem High-Wert


Hinweis: Ich programmiere meinen PIC in C mit dem C18 Compiler und verwende die Librarie i2c.h

Das Problem: Meine beiden Variablen (AKKUL und AKKUH) bleiben leer.


Hier ist mein Codeausschnitt:



//I2C
IdleI2C(); //Warten bis der IIC Bus frei ist
StartI2C(); //I2C Bus starten
WriteI2C(10); //Adresse des ATMEL senden


IdleI2C(); //Warten bis der IIC Bus frei ist
StartI2C(); //I2C Bus starten
putsI2C("I2C_REG_ADC_UBAT_L"); //Befehl zum Auslesen der Akku Variablen senden


AKKUL=ReadI2C();
StopI2C(); //I2C Bus stoppen


IdleI2C(); //Warten bis der IIC Bus frei ist
StartI2C(); //I2C Bus starten
WriteI2C(10); //Adresse des ATMEL senden


IdleI2C(); //Warten bis der IIC Bus frei ist
StartI2C(); //I2C Bus starten
putsI2C("I2C_REG_ADC_UBAT_H"); //Befehl zum Auslesen der Akku Variablen senden

AKKUH=ReadI2C();
StopI2C(); //I2C Bus stoppen



Ich würde mich sehr über Eure Hilfe freuen..

Mit freundlichen Grüßen
Nico

PIC-Nico
27.08.2011, 09:45
Mittlerweile sieht meine Routine so aus (funktioniert allerdings immer noch nicht):


//I2C
IdleI2C();
StartI2C(); //Start I2C
WriteI2C(0x0A|0x00); //Adresse senden (nächster Befehl schreibend)
while(WriteI2C(0x15)!=0); //Schreiben
IdleI2C(); //
RestartI2C(); //
IdleI2C(); //
WriteI2C(0x0A|0x01); //Adresse senden (nächster Befehl lesend)
getsI2C(Akku,2); //Lesen und Ergebnis in Akku
Akku[2]='\0'; //Abschluss '0'
NotAckI2C(); //Not acknowledge
while( SSPCON2bits.ACKEN!=0); //
CloseI2C(); //I2C beenden

Dirk
27.08.2011, 21:37
Hallo PIC-Nico:

Das I2C-Slave Programm erwartet an die Slave-Adresse 10 einfach die Registeradresse (I2C_REG_ADC_UBAT_L), also den Wert 21.
Danach müßtest du 2 Bytes lesen.

Gruß Dirk

PIC-Nico
27.08.2011, 21:41
Hi Dirk,
genau so habe ich es ja auch versucht (siehe mein 2. Post)- Kurzfassung:

WriteI2C(0x0A|0x00); //Adresse senden (nächster Befehl schreibend daher: | 0x00)
while(WriteI2C(0x15)!=0); //Schreiben (0x15 = dez.: 21)
WriteI2C(0x0A|0x01); //Adresse senden (nächster Befehl lesend daher: | 0x01)
getsI2C(Akku,2); //Lesen und Ergebnis in Akku (2x lesen)

Dirk
27.08.2011, 22:46
Ok,
ich kenne den I2C-Slang, den du da nutzt, nicht wirklich,- man hätte aber darauf kommen können ...

Was ich noch probieren würde:

1. Das Idle und Restart zwischen Schreiben und Lesen evtl. mal probeweise rausnehmen.

2. Wie liest du die Zahl weiter ein? Wenn ich das hier: Akku[2]='\0';
... lese, denke ich, dass du später einen String ausliest,- kann das sein?
Du müßtest aber mit den 2 Bytes rechnen:
ADC-Wert = Erster gelesener Wert + Zweiter gelesener Wert * 256

PIC-Nico
27.08.2011, 22:57
Danke schon mal bis hier her.. Ich versuche es morgen weiter..

PIC-Nico
28.08.2011, 09:24
Aktueller Stand:

Ich hatte in der Init des PICs einen Fehler: Beim Power on wurde fälschlicherweise ein Steuerbefehl (unbeabsichtigt) auf dem Bus ausgelöst und zwar indem ich zum Start die Port-Pins SDA und SDC als Ausgang definiert habe. Hier wurde kurzzeitig SCL und SDA zur selben Zeit auf Masse gezogen - das habe ich behoben. Mit dem Oszi konnte ich jetzt zumindest schon mal feststellen, dass die Adresse (0x0A bzw. dez.: 10) anscheinend richtig übertragen wird, siehe Anhang:

19810

Ich werde weiter machen, melde mich mit Neuigkeiten.
Gruß Nico

PIC-Nico
28.08.2011, 09:53
Der Slave schickt irgendwie kein ACK:

Es wird korrekt die Adresse (0x0A) übertragen, mit dem 8.Bit die "0", sprich nachfolgender Befehl ist schreibend. Danach müsste der Slave doch die SDA Leitung auch LOW ziehen um das ACK zu signalisieren. Warum tut er das nicht?

19811

SlyD
28.08.2011, 11:29
Hallo,

läuft das Slave Programm im AVR auch? Also hast Du es mit dem Start/Stop Taster gestartet? Geht auch indem man auf dem I2C Bus einmal die SDA Leitung für ein paar Millisekunden auf low schaltet (einmal start+stop generieren), dann etwas WARTEN weil da im Slave Programm am Anfang 500ms Pause drin sind. Das muss alles separat VOR der ersten Datenübertragung passieren.
Mach sonst auch mal ein paar setLED Befehle in die einzelnen Funktionen im Slave Programm rein damit man sieht obs überhaupt läuft.



auf dem Bus ausgelöst und zwar indem ich zum Start die Port-Pins SDA und SDC als Ausgang definiert habe.

Du verwendest die Pins aber auch allgemein richtig, das müssen OPEN DRAIN Ausgänge sein, d.h. aktiv Low ist OK, aber aktiv High ist verboten für High müssen die Pins als Eingang konfiguriert werden - den Rest erledigen die externen Pullup Widerstände.
(sonst ist Ausgang an Ausgang geschaltet und wenn einer High und einer Low ist wäre das schlecht... )


MfG,
SlyD

PIC-Nico
28.08.2011, 11:56
Hi,
ich habe nun mal folgendes ausprobiert: Start, SDA-low, Warteschleife >1s, SDA-high, Warteschleife >1s, normaler Ablauf

Hat aber nicht geholfen (um sicher zu stellen, dass das I2C Slave Programm läuft. Ich werde jetzt mal das I2C Slave Programm mit setLED Befehlen ausstatten, wie du gesagt hast mal sehen ob das Prog auf der Base überhaupt läuft.

Zu den Pins: Ich verwende ja eine fertige Librarie, ich meine, dass der Port Pin einfach zwischen Ausgang (=low) und Eingang (hochohmig=high) wechselt.

Gruß Nico

PIC-Nico
28.08.2011, 12:55
Nur Probleme :mad: --> Compilieren im PN2 funktioniert nicht. Ich habe die WinAVR Umgebung runter geladen (also sind die Befehle schon drin MAKE ALL und MAKE CLEAN). Dann habe ich einfach ein Beispielprojekt geöffnet aber er will einfach nicht:

> "make.exe" all
"make.exe": Interrupt/Exception caught (code = 0xc00000fd, addr = 0x4217b3)

> Process Exit Code: 255
> Time Taken: 00:01

SlyD
28.08.2011, 12:57
Welche WinAVR Version (aktuellste)? Welches Betriebssystem?

PIC-Nico
28.08.2011, 13:04
Okay, man darf bei der Installation den Installations-Ordner nicht ändern --> wtf? :)


Edit: Also das I2C Slave Programm arbeitet.

PIC-Nico
28.08.2011, 19:30
Habe gerade gelesen, dass die Adresse wohl nicht 10 sondern 5 ist: http://www.arexx.com/forum/viewtopic.php?f=19&t=1466

^^ nochmal ran an den Speck

PIC-Nico
29.08.2011, 11:19
Guten Morgen zusammen,
ich habe jetzt die Beispielprogramm der Version 20080510 herunter geladen, da in der Version 20080915 scheinbar ein Fehler in der Slave Adressierung steckt (Die Slave Adresse ist wohl durch einen "Fehler" nicht dez. 10 sondern dez. 5, was aber verboten ist, da die Adresse nur in den oberen 7 Bit stehen darf). Naja wie auch immer. Mit der älteren Version kann ich den AVR jetzt jedenfalls ohne Probleme ansprechen. Allerdings tut sich das nächste Problem auf. Hier mal kurzgefasst wie die Kommunikation i.M. aussieht:


-> Adressierung 0x0A
<- ACK
-> Senden 16h
-> Adressierung 0x0B
<- ACK
<- Empfange FFh
-> ACK

Problem: Ich empfange immer FFh. Egal ob ich das 21. Register oder das 22. auslese :( Hat evtl. schon einmal jemand das Problem gehabt oder kann eine Aussage treffen warum ich nur "Mist" empfange?

Mein aktueller Code (Ausschnitt):


IdleI2C();
StartI2C(); //Start I2C

Data = SSPBUF; //
do
{
Status = WriteI2C(ADR|0x00); //Adresse senden bis die..
if(Status == -1) //Bus Kollision?
{
Data = SSPBUF; //
SSPCON1bits.WCOL=0; //Bus Kollisions Bit löschen
}
}
while(Status!=0); //..Übertragung erfolgreich war

WriteI2C(22); //Dezimal: 22 Schreiben
WriteI2C(ADR|0x01); //Adresse senden (+1)
AKKUH=ReadI2C(); //Lesen und Ergebnis in AKKUH
IdleI2C(); //Ist der Bus verfügbar?
AckI2C(); //Sende Acknowledge
IdleI2C(); //Ist der Bus verfügbar?
CloseI2C(); //I2C beenden

Viele Grüße
Nico :cool: