Forum: Mikrocontroller und Digitale Elektronik Erste Schritte mit TWI


von Drazor (Gast)


Lesenswert?

Guten Abend,

ich bin gerade dabei einen "Termalscanner" zu bauen, der ein Wärmebild 
von einem Bereich erzeugt. Die Sensorsteuerung ist soweit fertig.
Irgendwie komme ich mit dem Infrarotsensor aber nicht weiter. Ich hoffe, 
ihr könnt mir da weiter helfen. Es handelt sich um den MLX90614.
Vielleicht hat jemand sogar schon mit dem Sensor gearbeitet.
Zwar findet man jede menge Quellcode zu dem Sensor, aber ich kann nichts 
davon 1zu1 adaptieren, da meine Zielplattform kein Arduino ist.
Nutzen kann ich diese library:
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.c
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.h
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_generic.c
https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_generic.h
1
#define ADDRESS    0x5A
2
3
int16_t i2c_MLX90614_read_temperature() 
4
{
5
  int16_t data = 0;
6
  uint8_t data_4lsb, data_4msb;
7
  
8
  // Start
9
  if (!i2c_master_select(ADDRESS, TW_WRITE))  { return 0x00; }
10
  
11
  // Wait // ? hier nötig?
12
  if (i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)  { return 0x00; }
13
  
14
15
  // Write
16
  TWDR = 0x07;
17
  if (i2c_master_transmit_with_ack() != TW_MR_DATA_ACK) { return 0x00; }
18
  
19
20
  /* select the slave in read mode */
21
  TWDR = (chipaddress << 1) | TW_READ;
22
  
23
  // Rep Start
24
  if (i2c_master_start() != TW_REP_START) { return 0x00; }
25
  if (i2c_master_transmit_with_ack() != TW_MR_DATA_ACK)  { return 0x00; }
26
  
27
  data_4lsb = TWDR; // least significant bit
28
29
  if (i2c_master_transmit() != TW_MR_DATA_NACK) { return 0x00; }
30
  
31
  data_4msb = TWDR; // most significant bit
32
  if (i2c_master_transmit() != TW_MR_DATA_NACK) { return 0x00; }
33
  
34
  data |= data_4msb;
35
  data |= data << 8;
36
  data |= data_4lsb;
37
  
38
  i2c_master_stop();
39
  return data;
40
}

PS: Ich würde mein Projekt auch hier vorstellen, wenn interesse besteht 
:)

von Drazor (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe das Datenblatt auch mal angehängt.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du solltest dir etwas bessere Fehlercodes ausdenken, so das du auch 
mitkriegst, wo es hakt. Im Moment wirst du wahrscheinlich nur ne 0x00 
zurückkriegen und rätseln, was denn nun schiefläuft. Nützlich ist z.B. 
ein globales Errorbyte, indem du eine Fehlernummer speicherst. Sollte 
deine Routine also Null zurückgeben, lässt du dir die Fehlernummer 
zeigen. Das kann auch für andere Unterroutinen praktisch werden.

Ich kenne den Sensor nicht, könnte mir aber vorstellen, das er 
kalibriert werden muss, bevor es sinnvolle Daten gibt.

von Drazor (Gast)


Lesenswert?

Ich habe mir mal dein Tipp zu Herzen genommen.

Zuerst einmal:
Der Sensor wir schonmal gefunden:
1
i2c detect
2
detected at: 0x0 (0)
3
detected at: 0x5a (90)


Ich poste erstmal den ersten Teil des Codes, welcher schon nicht richtig 
arbeitet:
1
  uint8_t data_4lsb, data_4msb, data_crc;
2
  int8_t data;
3
4
  uint8_t address = 0x5A;
5
6
  
7
  #ifdef DEBUG_I2C
8
    debug_printf("I2C::MLX90614 start\n");
9
  #endif
10
  
11
  /////////////////////////
12
  // Start Condition
13
  /////////////////////////
14
  if (!i2c_master_select(address, TW_WRITE))
15
  {
16
    #ifdef DEBUG_I2C
17
      debug_printf("I2C::MLX90614 address(%d) not selectable\n", address);
18
    #endif
19
20
    goto end;
21
  }
22
  
23
  if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
24
  {
25
    #ifdef DEBUG_I2C
26
      debug_printf("I2C::MLX90614 address selected, no sla_ack\n");
27
    #endif
28
29
    //goto end;
30
  }
31
  
32
  // Read out
33
  TWDR = 0x07;
34
  
35
  if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
36
  {
37
    #ifdef DEBUG_I2C
38
      debug_printf("I2C::MLX90614 command, no data_ack\n");
39
    #endif
40
41
    goto end;
42
  }

Als Ausgabe bekomme ich:
1
D: I2C::MLX90614 start
2
D: i2c master select adr+mode 0xB4
3
D: I2C::MLX90614 address selected, no sla_ack
4
D: I2C::MLX90614 command, no data_ack

Laut Datenblatt sollte ich 2 Acks bekommen. Diese bleiben aber aus.
Wundert euch nicht, warum ich nach SLA und DATA ACK abfrage. Ich wollte 
nur auf Nummer sicher gehen.
Hat da jemand eine idee?

von mgue (Gast)


Lesenswert?

Ich nehme mal an, dass du etwas schreiben (TW_WRITE) und nicht lesen 
(TW_READ) willst.

Mach aus jedem
1
if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
ein
1
if (i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
bzw.
1
ret = i2c_master_transmit_with_ack();
2
if (ret != TW_MT_DATA_ACK)
TW_MT_SLA_ACK ist hier nicht nötig (siehe weiter unten).

---
1
if (i2c_master_transmit_with_ack() != TW_MT_SLA_ACK || i2c_master_transmit_with_ack() != TW_MT_DATA_ACK)
2
  {
3
    #ifdef DEBUG_I2C
4
      debug_printf("I2C::MLX90614 address selected, no sla_ack\n");
5
    #endif
6
7
    //goto end;
8
  }
Dieser Part ist falsch. Es steht zu diesem Zeitpunkt nichts (sinnvolles) 
im TWDR Register.
Auf TW_MT_SLA_ACK wird bereits in i2c_master_select geprüft:

https://github.com/ethersex/ethersex/blob/master/hardware/i2c/master/i2c_master.c#L94

Zur Vollständigkeit: Bei
1
end:
sollte stehen:
1
i2c_master_stop();

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.