PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Texas Instruments tmp100 über i2c Auflösung einstellen



Cysign
05.04.2013, 12:13
Hallo miteinander,

ich spiele seit gestern zum ersten Mal mit einem i2c-fähigen Sensor.
Dazu habe ich ihn über einen Raspberry Pi angeschlossen und werte ihn über die GPIO-Pins aus.

Ich habe einen Codefetzen im Netz gefunden, der auf den tmp102 ausgerichtet war, mit aber auch die Temperatur des tmp100 ausgibt:



#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
unsigned int temp = 0;
unsigned char msb, lsb;

int fd; // File descritor
char *fileName = "/dev/i2c-1"; // Name of the port we will be using
int address = 0x4f; // Address of TP102
unsigned char buf[10]; // Buffer for data being read/ written on the i2c bus

if ((fd = open(fileName, O_RDWR)) < 0)
{ // Open port for reading and writing
printf("Failed to open i2c port\n");
exit(1);
}

if (ioctl(fd, I2C_SLAVE, address) < 0)
{ // Set the port options and set the address of the device we wish to speak to
printf("Unable to get bus access to talk to slave\n");
exit(1);
}


buf[0] = 0; // This is the register we wish to read from

if ((write(fd, buf, 1)) != 1)
{ // Send register to read from
printf("Error writing to i2c slave\n");
exit(1);
}

if (read(fd, buf, 1) != 1)
{ // Read back data into buf[]
printf("Unable to read from slave\n");
exit(1);
}
else
{




for (;;)
{
msb = buf[0];

if (read(fd, buf, 1) != 1)
{
printf("Unable to read from slave\n");
exit(1);
}
else
{
lsb = buf[0];
temp = (msb<<8) | lsb;
temp >>= 4;
printf("Temp: %f \n",temp*0.0625);
printf("Raw: %f \n\n", temp*1.00);
usleep(1000000);
}
}




}
return 0;
}


Laut Datenblatt soll der tmp100 ein einstellbare Auflösung haben. Aber ich bin noch nicht wirklich dahinter gestiegen, wie ich die Auflösung einstellen kann.
Momentan kann ich nur Messwerte in 1°C-Schritten auslesen. Da der Sensor einen Messbereich von 180°C hat und mit 12Bit = 4096 Werten auflösen können soll, ergibt sich doch theoretisch eien Schrittweite von 180/4096 von 0.0439453125°C.
Allerdings bekomme ich imemr nur volle Werte alla 23.06250°C oder 24.06250°C ausgegeben.

Die Zahl dieht verdammt nach dem Umrechnungsfaktor aus. Aber ohne den Multiplkator bekomme ich nichts ausgegeben.

Wie kann ich den Sensor nun dazu bewegen, feiner aufgelöste Werte auszuspucken?

Klebwax
05.04.2013, 12:51
Welchen Abschnitt im Datenblatt verstehst du nicht?

MfG Klebwax

Cysign
05.04.2013, 14:12
Puh, da gibts mehrere Denkschwierigkeiten.
Das wären einmal die Bitoperatoren im Code


msb = buf[0];
...
lsb = buf[0];
temp = (msb<<8) | lsb;
temp >>= 4;


Und dann gehts im Datenblatt los auf Seite 5 unten:
Temperaturregister:
P1: 0 P0: 0
Read only
...12-bit read only register

Die Table 3, 4 & 6 sagen mir überhaupt nichts :(


Also liefert der Sensor eigentlich schon die ganze Zeit 12-bit-Werte? Oder muss ich das erst mit Hilfe der Tabelle 6 einstellen, da der Sensor ja 9-12 Bit liefern könnte?

Hmmm...okay, auf 12-Bit stellt man m.H. der Tabelle 7. Aber wie teile ich das dem Sensor mit?

Btw: Wenn ich nen Rohwert von buf[0] ausgebe, bekomme ich was, das ich weder lesen noch benennen kann. Ein Rechteck mit scheinbar 4 Zahlen drin.

021aet04
05.04.2013, 15:52
Der Ablauf sieht so aus:

Start
Adresse senden (beim TMP100 und ADD0 und ADD1 auf 0V => 10010000 => Hex 90)
Pointerregister senden
Variable schreiben
Stopp

für Lesen:

Start
Adresse senden (beim TMP100 und ADD0 und ADD1 auf 0V => 10010000 => Hex 90)
Pointerregister senden
Repeated Start (mit Adresse Hex 91 => durch R/W Bit)
Variable lesen
immer mit ACK bestätigen, Ausnahme letztes Byte dort mit NACK abschließen
Stopp

Wenn du jetzt also nur die Temp lesen willst schreibst du:

Start
Adresse
Pointer (0x00 => 0000 0000)
repeated start
Highbyte lesen
Lowbyte lesen
stopp

Mit diesem Code hast du 9Bit Auflösung, wenn du 12Bit brauchst/willst musst du das zuerst im Configurationregister einstellen (einmal bei Programmstart)
Der Ablauf sieht so aus:

Start
Adresse
Pointeradresse (0x01 => 0000 0001)
Configbyte schreiben (0x60 => 0110 0000)
Stopp

Das lesen funktioniert dann wie oben.

MfG Hannes

Cysign
05.04.2013, 18:06
Wenn ich ehrlich bin, ist mir das noch ne Ecke zu hoch.
Kannst du diene Erklärung vielleicht ein bisschen anfängerfreundlicher formulieren?

Es hapert schon daran, das ich nicht weiß, was ich für einen Rückgabewert bekomme.
Wenn ich buf[0] einfach ausgebe, bekomme ich etwas, das aussieht wir ein Rechteck mit 4 Ziffern drin.
Ist das ein Byte, das mittels lsb und msb in Binärcode umgeschrieben wird?

Können wir den Code vielleicht mal auseinander nehmen?


(fd = open(fileName, O_RDWR)
Hier wird festgelegt, dass auf ic2 zugegriffen wird.
Was bedeutet das O_ vor dem ReadWrite?


ioctl(fd, I2C_SLAVE, address)
ioctl = input output control?
Sensor dieser Adresse als I2C_SLAVE definieren


write(fd, buf, 1)
'buf' an Gerät 'fd' übergeben. Wofür steht die 1?
Steht buf also für ein Array, das 10 byte = 10 Register beinhaltet, die jeweils 8 bit groß sind?


read(fd, buf, 1)
Wieder diese 1. Hier wird das Array Buf also dann mit den Sensordaten gefüllt.


msb = buf[0];

lsb = buf[0];
temp = (msb<<8) | lsb;

Hier wird das erste Register, welches die Temperatur beinhaltet, aus dem Array gezogen und an lsb übergeben.
In temp wird der Rückgabewert gespeichert, der mittels
(msb<<8) | lsb; irgendwie umformatiert wird. Was geschieht hier genau?


temp >>= 4;
Und hier haben wir schon die nächste Transformation, die ich nicht verstehe.


Wofür werden die Pina ADD0 und ADD1 benötigt?

Woher kommt der Wert Hex 90?

Wie kann ich die Hex-Codes alla 0x01, 0x00, etc. interpretieren bzgl. der am Anfang stehenden "0x"?

Das sind vielleicht ein paar viele Fragen...aber ich häng schon den ganzen Tag davor und werd nicht so wirklich schlau darauß.
Irgendwie hab ich kein wirklich vollständiges Tutorial gefunden.

021aet04
06.04.2013, 09:29
Wie du den I2C Bus von deinem Controller (Raspberry) ansteuerst weiß ich nicht. Buf ist ein Array, das mit 10 definiert ist, das bedeutet 10Byte. Bei der Read bwz write Funktion könnte ich mir vorstellen das das so aufgebaut ist: z.B.

read(Ort von dem die Daten übernommen werden, Variable, Anzahl der Bytes)

jedoch kann es auch etwas anderes bedeuten. Du solltest mehr darüber im Handbuch, Hilfe,... erfahren. Eventuell findest du mehr in der Headerdatei bzw C-Datei (werden C-Dateien verwendet?).

Zu den einzelnen Umwandlungen kannst du den Windowsrechner recht gut verwenden (bei "Ansicht" umschalten auf "Programmierer").
"|" bedeutet bitweises Oder, byteweise wäre "||"
(msb<<8 ) bedeutet z.B. die Variable msb um 8 nach links schieben (beim Win Rechner ist das "RoL" => Rotate left),
das gleiche gilt auch mit >>, bedeutet rechts schieben (RoR),
temp>>=4 bedeutet temp wird gelesen, um 4 nach rechts geschoben und dieser Wert wird dann wieder in die Variable temp geschrieben (ist eine Kurzform von temp = temp>>4)

Wofür die ADD Pins sind findest du auf S8.
Die Adresse beginnt immer mit 1001, dann kommt es auf die Konfiguration der ADD Pins an, als letztes Bit ist das R/W Bit, dieses Bit wird dazu genutzt um dem Slave zu sagen ob geschrieben wird oder gelesen wird.
In der Tabelle zu den ADD Pins findest du die bezeichnung 0, 1 und Float. 0 bedeutet das dieser Pin mit Masse (GND) verbunden ist, 1 bedeutet das dieser Pin mit VCC (pos. Versorgungsspannung) verbunden ist, Float bedeutet das dieser weder mit GND, noch mit VCC verbunden ist, der Pin wird einfach unbeschalten gelassen.

Wenn du jetzt also ADD0 und ADD1 mit Masse verbindest hast du die Adressen: 1001000x (x steht für das R/W Bit), wenn du das umwandelst in Hex hast du 90 (wenn RW Bit 0 ist => Master sendet an Slave) bzw 91 (wenn RW Bit 1 ist => Master liest vom Slave). Das kannst du ebenfalls mit dem Win Rechner kontrollieren.

Ich habe z.B. 0x00 geschrieben. Das 0x ist ein Präfix und bedeutet das die Zahl als Hex geschrieben wird (du hast somit 0x00 bis 0xff bei einem Byte). Diese Schreibweise ist in C-Dateien üblich. Wenn man keinen Präfix verwendet (z.B. 100) ist das automatisch Dezimal, bei Binär muss man 0b am Anfang schreiben (also z.B. 0b10010000 bei deiner Adresse).

Hier noch ein Link zum I2C Bus http://www.timmermann.org/ralph/index.htm?http://www.ralph.timmermann.org/elektronik/i2c.htm




Wenn du die Registerbits liest musst du einmal grundsätzlich das Byte kennen bzw deren Aufbau (als Beispiel das Configuration Register), das du auf S6 findest (Table 6):

Der Aufbau ist: OS/Alert R1 R0 F1 F0 POL TM SD
Das nutzt dir aber so noch nichts, da du nicht weißt was die einzelnen Bits bedeuten. Du musst jetzt durchlesen was die einzelnen Bits bedeuten.

SD: ist das Shutdown Bit, damit kannst du den Sensor "schlafen legen", damit dieser Strom spart, er mist aber in dieser Zeit nicht. Mit einer 1 aktivierst du den Schlafmodus, mit 0 wird dieser deaktiviert.

TM: damit aktivirerst du den Thermostat Mode, dazu findest du die Tabelle

POL: damit kann man einstellen ob bei einem Fehler (Thigh oder Tlow über- bzw unterschritten) eine 1 oder 0 beim OS/Alert bzw Alarm Output (beim TMP101) geschrieben wird

F1, F0: sind die Fault Queue Bits, damit stellst du die Anzahl ein bevor ein Alarm ausgelöst wird

R1, R0: sind Auflösungsbits, damit stellst du die Auflösung des Sensors ein.

OS/Alert: Dieser hat je nach Configuration 2 Aufgaben. Wenn du im SD Bit eine 1 stehen hast (Shutdownmode) löst du mit diesem Bit eine Messung aus, der TMP geht dann wieder in den Schlafmodus zurück, wenn SD jedoch 0 ist wird dieses Bit als Alarm Bit genutzt (die Grenze im Thigh bzw Tlow Register wurde über bzw unterschritten).



Wenn du den TMP an die Versorgungsspannung legst (bei jedem einschalten) sind alle Bits 0 (außer das Temparaturregister). Somit musst du bei jedem Start einmal die Einstellungen senden (wird in einem Ram gespeichert).
Wenn du eine Funktion nicht brauchst ignorierst du es einfach.
OS/Alert => brauchst du nicht => 0
R1/R2 => für 12Bit beides auf 1 schalten (Table 8 )
F1/F0 => brauchst du nicht => beides 0
POL => Brauchst du nicht => 0
TM => Brauchst du nicht => 0
SD => Brauchst du nicht => 0

Somit ergibt sich: 0b01100000 => 96 => 0x60

MfG Hannes