Forum: Mikrocontroller und Digitale Elektronik I2C Implementierung ATmega32 in C funktioniert nicht


von M. K. (m4k)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich möchte mit meinem ATmega32 die Sensorwerte (Temperatur, Druck, 
Luftfeuchtigkeit) von einem MS8607-PHT-Sensor auslesen.

Den ATmega32 programmiere ich in C mit Microchip Studio.

Für den Sensor habe ich diese Bibliothek gefunden: 
https://github.com/TEConnectivity/MS8607_Generic_C_Driver

Um die Bibliothek zu benutzen, muss die Datei i2c.h platformspezifisch 
implementiert werden:
1
The header "i2c.h" has to be implemented for your own platform to 
2
conform the following protocol :
3
4
enum i2c_transfer_direction {
5
  I2C_TRANSFER_WRITE = 0,
6
  I2C_TRANSFER_READ  = 1,
7
};
8
9
enum status_code {
10
  STATUS_OK           = 0x00,
11
  STATUS_ERR_OVERFLOW  = 0x01,
12
  STATUS_ERR_TIMEOUT  = 0x02,
13
};
14
15
struct i2c_master_packet {
16
  // Address to slave device
17
  uint16_t address;
18
  // Length of data array
19
  uint16_t data_length;
20
  // Data array containing all data to be transferred
21
  uint8_t *data;
22
};
23
24
void i2c_master_init(void);
25
enum status_code i2c_master_read_packet_wait(struct i2c_master_packet *const packet);
26
enum status_code i2c_master_write_packet_wait(struct i2c_master_packet *const packet);
27
enum status_code i2c_master_write_packet_wait_no_stop(struct i2c_master_packet *const packet);

Ich habe meine Implementierung der Funktionen angehängt (i2c.h).
Die Werte lese ich dann wiefolgt in meiner main aus:
1
float *p, *h, *t;
2
ms8607_read_temperature_pressure_humidity(t, p, h);

In meiner Implementierung der Funktionen muss aber ein Fehler vorliegen, 
denn alle drei Sensorwerte sind 0,0

Was hab ich bei der Implementierung falsch gemacht?

von holperdistolper (Gast)


Lesenswert?

M. K. schrieb:
> Was hab ich bei der Implementierung falsch gemacht?

Zunächst mal Prinzipielles.

In eine *.h Datei gehört weder (Programm-)Code noch Variablen-
Deklaration. Dagegen ist eine Typ-Definition (deine Struct) dort
richtig. Wohlgemerkt eine Typ-Definition, nicht die Variable
(struct i2c_master_packet{} ) selbst.

von grundschüler (Gast)


Lesenswert?

sieht so aus, als würde es i2c.c nicht geben

von foobar (Gast)


Lesenswert?

m4k schrieb:
1
> float *p, *h, *t;
2
> ms8607_read_temperature_pressure_humidity(t, p, h);

Sicher?  Sollte das nicht eher:
1
float p, h, t;
2
ms8607_read_temperature_pressure_humidity(&t, &p, &h);
sein?

von PittyJ (Gast)


Lesenswert?

foobar schrieb:
> m4k schrieb:
>
1
> float *p, *h, *t;
2
>> ms8607_read_temperature_pressure_humidity(t, p, h);
3
>
>
> Sicher?  Sollte das nicht eher:
>
1
float p, h, t;
2
> ms8607_read_temperature_pressure_humidity(&t, &p, &h);
3
>
> sein?

Man könnte wohl auch
  float *p;
  p= (float*) malloc( sizeof(float) );
  ms8607_read_temperature_pressure_humidity(t, p, h);

t und h entsprechend.

von M. K. (m4k)


Lesenswert?

holperdistolper schrieb:
> In eine *.h Datei gehört weder (Programm-)Code noch Variablen-
> Deklaration. Dagegen ist eine Typ-Definition (deine Struct) dort
> richtig. Wohlgemerkt eine Typ-Definition, nicht die Variable
> (struct i2c_master_packet{} ) selbst.

grundschüler schrieb:
> sieht so aus, als würde es i2c.c nicht geben

Für einen ersten Test habe ich habe die Funktionen einfach mit in der 
Header-Datei definiert.
Ihr habt vollkommen Recht, dass sowas da eigentlich nicht hingehört.

foobar schrieb:
> Sollte das nicht eher:float p, h, t;
> ms8607_read_temperature_pressure_humidity(&t, &p, &h);
> sein?

Kommt das gleiche bei raus.

von M. K. (m4k)


Lesenswert?

Um meine Frage noch einmal klar zu formulieren:

Wie implementiere ich die folgenden Funktionen für den ATmega32 in C?
1
void i2c_master_init(void);
2
enum status_code i2c_master_read_packet_wait(struct i2c_master_packet *const packet);
3
enum status_code i2c_master_write_packet_wait(struct i2c_master_packet *const packet);
4
enum status_code i2c_master_write_packet_wait_no_stop(struct i2c_master_packet *const packet);

Die Bibliothek sagt hier nur, dass die Funktionen implementiert werden 
müssen, gibt aber keine nähere Auskunft als den Funktionsnamen.

Wenn mir jemand sagen kann, was die Funktionen inhaltlich machen sollen, 
wäre mir das auch schon eine große Hilfe.

von Oliver S. (oliverso)


Lesenswert?

Was die Funktionen machen sollen, steht doch in ihren Namen.

Und implementieren musst du nicht mehr und nicht weniger als eine 
vollständige I2C-Kommunikation.

Deine Überschrift ist insofern völlig falsch, als du ja überhaupt keine 
I2C-Lib hast. Der „generic driver“ ist keine, der braucht eine.

i2C-libs für AVR gibt es einige, Google wird dir da sicher weiterhelfen. 
Wenn du gar nicht weiterkommst, schau halt mal in die Artikelsammlung 
hier.

Oliver

von MaNi (Gast)


Lesenswert?

Es liegt zwar nahe dass es an der von dir implementierten HAL liegt, 
aber woher weißt du das es kein Hardware Problem ist.
Spannung am Sensor OK?
Alles richtig angeschlossen?
Pullups haben gültige Werte?

Ansonsten sieht für mich die Implementierung des TWI Status falsch aus.
1
enum status_code {
2
  STATUS_OK           = 0x00,
3
  STATUS_ERR_OVERFLOW  = 0x01,
4
  STATUS_ERR_TIMEOUT  = 0x02,
5
};
6
uint8_t I2C_Status()
7
{
8
  uint8_t status;
9
  status = (TWSR & 0xF8);
10
  return status;
11
}

Im DB wird der Status anhand der letzten Aktion überprüft(siehe S.182ff) 
Beispiel aus dem DB:
1
if ((TWSR & 0xF8) != START)
2
ERROR();

Wenn das nicht stimmt wird in jeder anderen Funktion die Sequenz 
abgebrochen.
Dann steht das auf den Variablen was vorher draufstand. Wahrscheinlich 
0.

von grundschüler (Gast)


Lesenswert?

Du musst erstmal verstehen, wie der i2c-bus funktioniert.

Wenn die i2c-lib in das Projekt eingebunden ist, erstmal testen ob die 
Kommunikation slave ./. master stattfindet:
1
uint8_t i2c_start(uint8_t adr)
2
{
3
i2c_start_cond();
4
uint8_t AckBit = i2c_write(adr);
5
 return AckBit;
6
}

Erst wenn hier das Ack-Bit vom slave korrekt zurückkommt funktioniert 
der Bus. Dann kannst du dich um den ganzen Rest kümmern.

von MaNi (Gast)


Lesenswert?

Lass dir Mal noch bei deinem Aufruf den Status zurückgeben. Wenn etwas 
ungleich 0 draufsteht ist es klar wieso es nicht geht:
1
status_code st = ms8607_read_temperature_pressure_humidity(t, p, h);
2
3
if(st != STATUS_OK )
4
{
5
//ERROR
6
}

von M. K. (m4k)


Lesenswert?

MaNi schrieb:
> aber woher weißt du das es kein Hardware Problem ist.
> Spannung am Sensor OK?
> Alles richtig angeschlossen?
> Pullups haben gültige Werte?

Ich habe noch ein weiteres Gerät am I2C-Bus angeschlossen und das 
funktioniert einwandfrei, dafür hatte ich eine fertige Bibliothek 
gefunden.

MaNi schrieb:
> Lass dir Mal noch bei deinem Aufruf den Status zurückgeben

Ich bekomme den Status 2 / "ms8607_status_i2c_transfer_error" beim 
Aufruf von ms8607_read_temperature_pressure_humidity zurück.
Die Werte t, p und h behalten den Wert, den sie vor dem Funktionsaufruf 
hatten, werden also gar nicht beschrieben.

von Oliver S. (oliverso)


Lesenswert?

M. K. schrieb:
> dafür hatte ich eine fertige Bibliothek
> gefunden.

Ja, dann nimm die doch. Zwei verschiedene I2C-libs auf der selben 
Harwareschnittstelle gibt eh nur Chaos.

Oliver

von PittyJ (Gast)


Lesenswert?

Vielleicht ist der Ansatz 'fertige Bibliotheken' zu nehmen nicht der 
richtige?

Evtl sollte man verstehen, was auf dem Bus passiert. Manchmal wird ja 
auch nur ein Status-Bit falsch interpretiert. Oder der Pull-up passt 
nicht, was man mit einem Oszilloskop  erkennen könnte. Oder die 
Parameter-Übergabe muss mit Pointern erfolgen. oder oder oder....

Wenn man in diesen Bereichen arbeitet, dann sollte man C können, wissen 
was ein I2C Bus macht und auch ein Scope bedienen können. Einfach nur 
fertige Bibliotheken zusammen linken, das reicht nicht aus.

von W.S. (Gast)


Lesenswert?

M. K. schrieb:
> Wie implementiere ich die folgenden Funktionen für den ATmega32 in C?

Du scheinst ein genialer Quellcode-Finder zu sein.
Also mal im Ernst: Verstehst du denn überhaupt den I2C-Bus als solchen? 
Weißt du dann, was eine Startcondition und eine Stopcondition ist? Und 
wie die Bits eines Bytes transportiert werden und dann der Empfänger des 
Bytes das mit ACK bestätigt oder nicht, was dann ein NAK ist?

Für mich sieht das Ganze bei dir eher wie ein gequirltes Durcheinander 
verschiedener Dinge aus: Was haben Zeiger wie float *p, *h, *t; beim I2C 
zu suchen? Natürlich nichts.

Für einen Master-Anschluß das I2C sehe ich nur folgende Funktionen:
1. bool OpenSlave(adresse, R oder W) - darin sind enthalten: Bus als 
Master erhalten, Slave adressieren und Datenrichtung festlegen. Das kann 
auch mal nicht funktionieren, dann wird der Mißerfolg im Ergebnis 
gemeldet. (Bus wird nicht erhalten oder Slave antwortet nicht bzw. 
quittiert die Datenrichtung mit einem NAK)
2. bool SendeByte(zu sendendes Byte)
   oder
   byte EmpfangeByte(bool ob mit ACK oder nicht)
3. void CloseSlave(void) - darin enthalten: Stopcondition und 
Busherrschaft aufgeben.

So. alles andere ist eine andere Ebene, insbesondere das Zusammenfügen 
eines Temperatur-, Druck- oder Feuchtigkeitswertes aus den Bytes, die da 
vom Slave herholbar sein sollten. Ich argwöhne, daß da zunächst an den 
Slave eine Adresse für die interessierende Stelle in dessen Ergebnis-RAM 
gesendet werden muß und dann erst der jeweilige Wert gelesen werden 
kann.

W.S.

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.