Forum: Compiler & IDEs I²C Bus und LM75


von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo an alle

Ich hab wieder ein Problem ;)
Ich hoffe ihr könnt mir helfen :)

Ich hab hier einen LM75 Temperatursensor der über I²C angesteuert
wird., Als Prozessor hab ich einen Mega 8.
Als Basisaddresse hat der LM75 90.

Jedoch verstehe ich die Ansteuerung noch nicht wirklich. Ich möchte
damit nur Temperaturen auslesen

Als I²C Lib will ich die Procyon Bibliothek verwenden.

Nur leider komme ich damit überhaupt nicht zusammen. Kann mir bitte wer
eine Funktions Code zum Auslesen der Temperatur zeigen??
Oder kann mir wer das erklären?

Danke im Voraus

Gruß Robert

von wolf4124 (Gast)


Lesenswert?

Hallo

Ich bin auch Anfänger.
Ich habe es mit der unten genannten Ansteuerung hingebracht.

http://sandiding.tripod.com/Bertys.html

Gruß

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo

Eine Lib für den LM75 will ich eigentlich nicht nehemn, da ich den I²C
Bus verstehen will ;)

Ich hab einmal etwas geschriben:

#include <avr/io.h>
#include <stdlib.h>
#include "i2c.h"  //Procyon I2C LiB

#define LM75_ADRESS 0x97

int lm75_read(void);

  TEMPERATUR struct {
  uint8_t high;
  uint8_t low;
  } temp;

int lm75_read(void)
{
  TEMPERATUR struct {
  uint8_t high;
  uint8_t low;
  } temp;

  i2cSendStart();
  i2cSendByte(LM75_ADRESS); //Sende Adresse
  i2cSendByte(0X00); //Temperature Register
  i2cSendSart();

  temp.high = i2cReceiveByte();
  temp.low = i2cReceiveByte();

  i2cSendStop();
    return(0)
}

Kann das so Funktionierten?

Danke im Voraus

Gruß Robert

von Robert S. (razer) Benutzerseite


Lesenswert?

Weiß das keiner???

Ich würd mich echt über Hilfe freuen ;)

Gruß Robert

von Giancarelli (Gast)


Lesenswert?

Hallo Robert

hab vor einiger Zeit sowas mit einem LM92 gemacht

Default nach Power Up ist das Temperaturregister - darum kannst Du in
Deinem Quelltext die Sache mit dem Temperaturregister weglassen

Die Temperatur steht in den Bits D7 - D15.

Übertragen werden zwei Byte

D0 - D7   Low Byte
D8 - D15  High Byte

Du musst die Bits so schieben damit die Temperatur mit D7 rechtsbündig
in einem Register steht

Nun musst Du die ganze Sache in °C umwandeln - dazu teilst Du einfach
durch 128 (2 hoch 7 = 128 da Du um 7 Stellen nach rechts schieben
musstest)


Hoffe ich hatte das noch richtig in Erinnerung

von Tom (Gast)


Lesenswert?

Sieht doch gar nicht so schlecht aus.
Die Adresse muss natürlich 0x90 sein und die struct kannst du als
typedef deklarieren und danach verwenden.
Ach ja, und dann muss zuerst die Adresse mit write-Bit gesendet werden,
nach dem repeated start nochmal mit read-Bit.

Etwa so:

...
#define LM75_ADDRESS 0x90

int lm75_read(void);

  typedef TEMPERATUR struct {
  uint8_t high;
  uint8_t low;
  };

int lm75_read(void)
{
  TEMPERATUR temp;

  i2cSendStart();
  i2cSendByte(LM75_ADDRESS); //Sende Adresse mit write Bit
  i2cSendByte(0x00); //Temperature Register
  i2cSendStart();

  i2cSendByte(LM75_ADDRESS | 1); //Sende Adresse mit read Bit
  temp.high = i2cReceiveByte();
...

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo Tom

Danke :)

Warum aber i2cSendByte(LM75_ADDRESS | 1); Warum das??

Nach dem Repeated Start muss zuerst wieder die Adresse Senden und das
Register, das ich auslesen will, oder??

Ich will ja aus dem Temperaturregister (0x00) auslesen. Warum also das
|1?

Wenn ich hintereinander das High und das Low Byte auslese, stimmt da
die Adresse der Bits automatisch? (Springt der Chip beim 2. Auslesen
(Low) automatisch zur Lowbyteadrese??)

Danke im Voraus

Gruß Robert

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo an alle

Ich hab das mal geändert:

#include <avr/io.h>
#include <stdlib.h>
#include "i2c.h"  //Procyon I2C LiB

#define LM75_ADRESS 0x97

int lm75_read(void);

  struct TEMPERATUR {
  uint8_t high;
  uint8_t low;
  } temp;

int lm75_read(void)
{

  i2cSendStart();
  i2cSendByte(LM75_ADRESS); //Sende Adresse mit write Bit
  i2cSendByte(0x00); //Temperature Register
  i2cSendStart();

  i2cSendByte(LM75_ADRESS | 1); //Sende Adresse mit read Bit
  temp.high = i2cReceiveByte(FALSE);
  temp.low = i2cReceiveByte(FALSE);
  i2cSendStop();
}

int main(void)
{
  i2cInit();
  i2cSetBitrate(100);
  lm75_read();
  return(0);
}

Nur wenn ich es compilieren will, dann bekomm ich immer 2
Fehlermeldunden:
lm75.c:23: error: void value not ignored as it ought to be
lm75.c:24: error: void value not ignored as it ought to be

Warum???

Danke im Voraus

Gruß Robert

von Stefanie (Gast)


Lesenswert?

Hallo Robert,

hab auch gerade erst diesen Baustein verwendet und kann zumindest
hierzu was sagen:

Warum aber i2cSendByte(LM75_ADDRESS | 1);  Warum also das |1?

Das |1 steht dafür, dass man vom Slave lesen möchte |0.

Das Temperaturregister wird automatisch ausgelesen, du brauchst also
kein 0x00 senden.

Ich habe den LM75 in ein buf[1] ausgelesen und so ausgegeben:


fprintf(uart, "Temperatur %d.%d\n\n", buf[0], (buf[1] ? 5 : 0));

Hoffe, dass ich dir etwas weiter helfen konnte.

Gruß, Stefanie

von Stefanie (Gast)


Lesenswert?

Hab mir mal deinen Code angeschaut, also ich denke, dass es so reicht:

int lm75_read(void)
{
  i2cSendStart();
  i2cSendByte(LM75_ADRESS | 1); //Sende Adresse mit read Bit
  temp.high = i2cReceiveByte(FALSE);
  temp.low = i2cReceiveByte(FALSE);
  i2cSendStop();
}

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo Stefanie

So hab ich es auch. Nur leider bekomm ich immer die eine Fehlermeldung
vom Compiler: lm75.c:21: error: void value not ignored as it ought to
be

Kann das mit dem struct zusammenhängen??

Gruß Robert

von Robert S. (razer) Benutzerseite


Lesenswert?

Weiß denn keiner was da los ist??

Ich bekomm die Fehlermeldung nicht weg :( Ich weiß auch nicht was sie
bedeutet :(

Gruß Robert

von Werner B. (Gast)


Lesenswert?

Was steht denn in Zeile 21 von lm75.c?

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo Werner

Ich bekomm 2-mal dioe Fehlermeldung. Einmal in 20 und einmal in 21.

Die Zeilen 20 und 21:
  temp.high = i2cReceiveByte(FALSE);
  temp.low = i2cReceiveByte(FALSE);

Gruß Robert

von Werner B. (Gast)


Lesenswert?

Und wie sieht der Prototyp der Funktion i2cReceiveByte() aus?

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo

inline void i2cReceiveByte(u08 ackFlag)
{
  // begin receive over i2c
  if( ackFlag )
  {
    // ackFlag = TRUE: ACK the recevied data
    outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
  }
  else
  {
    // ackFlag = FALSE: NACK the recevied data
    outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
  }
}

Das ist der Prototyp aus der Procyon i2c Lib.

Gruß Robert

von Werner B. (Gast)


Lesenswert?

inline void i2cReceiveByte(u08 ackFlag)

void bedeutet dass die Fn NICHTS zurückliefert, die Zuweisungen
  temp.high = i2cReceiveByte(FALSE);
  temp.low = i2cReceiveByte(FALSE);
sind als Unzulässig.
Du musst Dir eine FN suchen die auch einen Rückgabewert liefert der an
temp.high bzw temp.low zugewiesen werden kann.

von Robert S. (razer) Benutzerseite


Lesenswert?

Danke Werner

Hätte ich eigentlich selber erkennen müssen :( Jetzt muss ich nur noch
das Register auslesen, oder ?

Werde ich  mal probieren

Gruß robert

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo an alle

So es funktioniert jetzt so einigermaßen. Nur die Temperaturs stimmt
noch nicht wirklich.

Hier nun die read Funktion:

int lm75_read(void)
{

  i2cSendStart();
  i2cSendByte(LM75_ADRESS | 1); //Sende Adresse mit read Bit
  i2cSendStart();
  i2cReceiveByte(FALSE);
  temp.high = i2cGetReceivedByte();
  i2cReceiveByte(FALSE);
   temp.low = i2cGetReceivedByte();
  i2cSendStop();
}

Der Prototyp von i2cGetReceivedByte():

inline u08 i2cGetReceivedByte(void)
{
  // retieve received data byte from i2c TWDR
  return( inb(TWDR) );
}

temp.low ist ja die Kommastelle. Sie steht linksbündig in der Variable
temp.low. Wenn ich sie nach Rechts verschiebe und mit 5 Multipliziere,
hab ich die Kommastelle oder??

temp.low = (temp.low>>=7)*5;

Soe meine ich das.

Die High Variable macht mir jedoch noch mehr Sorgen. Ich bekomm immer
0xFF (255) empfangen. Den empfangenen Wert muss ich ja durch 2 Teilen,
oder??

125°C entspricht 1111 1010 = 0xFA = 250
25°C enspricht   110010    =  32  = 50

Daraus schleiße ich, dass ich den Wert durch 2 dividieren muss, oder??
Muss ich sonst noch etwas mit der Zahl machen??

Gruß Robert

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo an alle

So jetzt hab ich die Routine für das Auswerten der Zahlen Fertig.

if(bit_is_set(temp.low, 0))
    nachkomma = 5;
  else
    nachkomma = 0;

  temp.low >>= 1;
  temp.high <<= 7;
  ganzzahl= temp.low | temp.high;

Das funktioniert auch so. Leider steht nach dem Auslesn im Low und im
High Byte 255. Also stimmt beim Auslesen des LM75 irgendetwas nicht.

Was stimmt den da nicht??

Ich hoffe es kann mir wer helfen

Danke im Voraus

Gruß Robert

von Tom (Gast)


Lesenswert?

Ich rate mal:
1. Du sagst die Adresse des LM75 ist 90, im Beispiel steht 0x97.
Wieso?
90 ist gleich 0x5A, da bei I2C mit 7 Bit adressiert wird und das 8. Bit
Lesen/Schreiben auswählt, müsste die korrekte Adresse 0xB4 lauten (0x5A
um eine Stelle nach rechts geschoben).

2. Mit dem Aufruf von i2cReceiveByte() wird zwar der Empfang eines
Bytes gestartet, aber wann ist dieser abgeschlossen? Da du sofort
danach das TWDR Register ausliest, kann der Transfer evtl. noch nicht
abgeschlossen sein. Du solltest das TWINT Bit abfragen, bit dieses
gesetzt ist, dann erst auslesen.

3. Ist die I2C Schnittstelle korrekt initialisiert? Ist die Bitrate in
TWBR gesetzt?

4. Temperaturumrechung ist einfach: temp.high enthält schon den
Ganzzahlanteil der Temperatur. temp.low ist entweder 0 (für 0.0) oder
0x80 (für 0.5 Grad).
Somit wäre dein Code:

if(bit_is_set(temp.low, 7))
    nachkomma = 5;
  else
    nachkomma = 0;

Gruss

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 1. Du sagst die Adresse des LM75 ist 90, im Beispiel steht 0x97.
> Wieso?

Ein LM75 kann je nach Hardwarebeschaltung zwischen 0x90 und 0x97
liegen, du kannst also maximal 8 davon an einem Bus betreiben.

Wie du deine Hardware beschaltet hast, weißt du selbst am besten.

> 90 ist gleich 0x5A,

Nein, es war 0x90 gemeint.

> da bei I2C mit 7 Bit adressiert wird und das 8. Bit Lesen/Schreiben
> auswählt, müsste die korrekte Adresse 0xB4 lauten (0x5A um eine
> Stelle nach rechts geschoben).

Nein, erstens wäre 0x5a ein Bit nach rechts geschoben 0x2d (du hast
nach links geschoben), zweitens brauchst du da nichts schieben, da ja
nur das oberste Bit zwischen Lesen und Schreiben unterscheidet, die
unteren 7 Adressbits bleiben gleich.

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo an alle

MIt den Adressen bin ich dazwischen schon selber drauf gekommen. Als
Adresse hab ich 1001 1110 = 0x9E. Wenn ich das Read/Write Byte noch
setze, hab ich 1001 1111 = 0x9F. Hardware funktionert. Ich hab das mit
einem Basic Codeschnipsel getestet.

Funktioniert die Proycon Lib erfolgreich?? Oder soll ich das ganze
selber zu Fuß schreiben?

Vielleicht habt ihr noch ein paar Tipps ;)

Gruß Robert

von Robert S. (razer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo an alle

Hallo an alle

Ich hab nun die I2C Routine fertig geschrieben Smile Jedoch
funktioniert sie noch nicht. Ich finde jedoch keinen Fehler :(

Ich hoffe es kann mir wer helfen. Im Anhang ist der Code

Danke im Voraus

Gruß Robert

von Nico Schümann (Gast)


Lesenswert?

Es wäre vielleicht ganz gut zu wissen, was nicht geht.. Zu sagen, dass
etwas nicht geht, bringt nichts. Also eine etwas ausführlichere
Fehlerbeschreibung wäre ganz nett.

Bis dann,
Nico

von Robert S. (razer) Benutzerseite


Lesenswert?

Hallo Nico

Compilieren und Flashen kann ich es. Jedoch funktioniert das auslesen
nicht. Am Display steht 79.0. In den Variablen temp.ghi und temp.low
steht 158.

Gruß Robert

von Tom (Gast)


Lesenswert?

Die Adresse bei i2c_send_start() muss 0x9f lauten, da du ja lesen
willst. In i2c_read() wird die Adresse ignoriert.
Ausserdem stimmt deine Umrechung nicht. Hab ich aber 6 Beiträge weiter
oben schon geschrieben.

Gruss

von Robert Schilling (Gast)


Lesenswert?

Hallo an alle

Die Umrechnung ist erstmals egal

Hier nun meine Receive Code mit Acknoledgement:

Ich hab nach jedem Befehl eine Lcd Ausgabe eingeführt, um zu sehen wo
es hakt.

int i2c_read_ack(void)
{
lcd_putc('1');
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
lcd_putc('2');
while(!(TWCR & (1<<TWINT)));
lcd_putc('3');

if(!(TWSR & 0x50))
{
lcd_putc('4');
return -1;
}
lcd_putc('5');
    return TWDR;
}

Am Display wird aber nur 12 angezeigt.

Es hängt also bei while(!(TWCR & (1<<TWINT)));

Weiß irgendwer, was da falsch sein könnte. Ich hab jetzt echt keinen
Plan mehr

Danke im Voraus

Gruß Robert

von Eugen (Gast)


Lesenswert?

Hallo Leute.
Ich wollte mal fragen ob ich hier ein wenig Hilfe bekommen kann. Ich 
versuche schon seid paar Tagen mit I2C die Temperatur aus meinem LM75 
aus zu lesen, aber irgendwie will es nicht funktionieren. Könnt ihr mir 
da vielleicht weiter helfen?!?

Adresse ist 1001001

der C code ist:


      int data1, data2;

      i2c_start();
      i2c_write(0x93);
      data1 = i2c_read();
      data2 = i2c_read();
      i2c_stop();


Danke schon mal im Vorraus!

von anfaenger (Gast)


Lesenswert?

Die Adresse bei i2c_write(...) muss 0x92 lauten! (und nicht 0x93)

Ansonsten müsste das so funktionieren (wenn der Rest drumherum stimmt). 
Beachte aber, dass du den LM75 nicht zu schnell hintereinander ausliest, 
weil der immer ein bißchen Zeit braucht um eine neue Messung 
durchzuführen (ich glaub so um die 100ms).

von anfaenger (Gast)


Lesenswert?

ach sorry, stimmt ja garnicht. du willst ja auslesen. also ist 0x93 als 
adresse schon richtig.

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.