PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Temperatur via I2C



Haveaniceday
28.08.2007, 15:36
Ich versuche mich gerade an der Programmierung meiner Terrarium Steuerung, aber komme leider bis jetzt noch nicht sehr weit.
Was mir besonders großes kopfzerbrechen berreitet, ist das auslesen der Temperatur sensoren (DS1621).
Wie lese ich die Sensoren im Program aus? Wie weise ich jedem Sensor auch seine Temperatur zu (Adreesierung der Sensoren)?
Habe leider keine Tourials oder Anleitung über I2C gefunden.

Danke,
ciao Hannes

izaseba
28.08.2007, 16:42
Hallo,
Das ist denkbar einfach(Dattenblatt zu DS hast Du ?), so ein DS1621 hat 3 ? Adresspins,
wenn alle 3 auf Low liegen hat er die adresse 0x90, Du kannst auch welche auf High legen, dadurch änderst Du die Adressen(steht im Dattenblatt, wie die Werte zusammenkommen)
Wichtig ist, daß Du keine 2 mit gleicher Adresse hast ;-)
Dann besorgst Du Dir die i2cmaster lib von hier (http://homepage.hispeed.ch/peterfleury/avr-software.html)
Es gibt da zwar TWI und USI, je nach Controller, aber die lib von Peter Fleury ist erste Sahne; klein, schnell, gut.
Jetzt mußt Du alle DS1621 "in den Hintern treten" um die Messung zu starten.
Man sendet 0xEE an alle Bausteine.
Mit der lib von Fleury z.B. so:


#define I2CTHERMO 0x90
#define STARTCONVERT 0xEE
...
unsigned char i2cstatus;
i2cstatus = i2c_start(I2CTHERMO+I2C_WRITE);
if (i2cstatus){
LCD_puts("Error");
i2c_stop();
} else {
i2c_write(STARTCONVERT);
i2c_stop();
LCD_puts("Convert starting...");

so Werte abholen:


#define GETTEMP 0xAA
...
...
i2c_start_wait(I2CTHERMO+I2C_WRITE);
i2c_write(GETTEMP);
i2c_rep_start(I2CTHERMO+I2C_READ);
i2cpuffer[0] = i2c_readAck();
i2cpuffer[1] = i2c_readNak();
i2c_stop();

in i2cpuffer[0] steht die Temperatur drin, in i2cpuffer[1] die 0,5 Grad
Einfach ?
Am besten probierst Du erstmal mit einem Baustein...
Und die Pullups am Bus nicht vergessen, sonst klappt es nicht!
Gruß Sebastian

P.S. Es gibt noch andere schöne Sachen, die Du mit dem DS1621 machen kannst, wie Thermostatfunktion usw.
Was man Ihm dann zuflüstern muß kannst Du auch in Dattenblatt nachschlagen.

Wenn noch fragen offen sind, dann frag einfach

Haveaniceday
28.08.2007, 18:20
Super, hast mir erstmal echt weiter geholfen.
Nur verstehe die zeilen noch nicht so ganz die du da Programmiert hast, z.B. "LCD_puts("Error");"
Sehe ich das richtig, das diese Zeile für ein LCD display vorgesehen ist? (Will erstmal keins verwenden, nur die Temperatur Regeln)

Ja, das Datenblatt habe ich, aber habe da nix gefunden von der Adressierung.
Die Pullup Widerstände sind meine ich schon auf meinem Board (http://www.pollin.de/shop/downloads/D810038B.PDF) (ATMEL Evaluations-Board Version) drauf

izaseba
28.08.2007, 18:44
Ja, das Datenblatt habe ich, aber habe da nix gefunden von der Adressierung.
Doch,doch, habe gerade das Dattenblatt rausgehollt Seite 8 unter Slave Address oder so.
Die Adresse setzt sich wie folgt zusammen:
1 0 0 1 A2 A1 A0 0
wobei A2-A0 die 3 vorhingenannten Pins sind.
Legst Du alle auf LOW sieht die Adresse so aus 10010000 was 0x90 ergibt
Legst Du A2 auf HIGH bekommst Du 10011000 was 0x98 gibt usw.
Der Letzte Bit LSB gibt die Dattenrichtung, das erledigt aber sie Software, für Adresseberechnung nimmst Du immer 0...
Sorry, die LCD_puts Funktion habe ich nicht rausgelöscht, es sollte nur zur Debugzwecken drin stehen, wenn alles klappt, braucht man das natürlich nicht ;-)

Achso in der i2clib mußt Du noch Deine Pins einstellen, schau mal in der i2cmaster.S ganz am Anfang, bei mir steht da z.B.


;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA 5 // SDA Port D, Pin 4
#define SCL 4 // SCL Port D, Pin 5
#define SDA_PORT PORTE // SDA Port D
#define SCL_PORT PORTE // SCL Port D

Das ist dann alles, was Du einstellen mußt...
die i2cmaster.S muß noch im Makefile unter
ASRC=i2cmaster.S stehen und in Deinem Hauptprogramm mußt Du
#include"i2cmaster.h" reinschreiben.
Beide Dateien im gleichem Ordner wie Dein Hauptprogramm !
Sorry, aber ich kenne Deinen Wissenstand nicht, und bevor Du fragen mußt... ;-)

Viel erfolg

Gruß Sebastian

Haveaniceday
29.08.2007, 14:31
Sorry, aber ich kenne Deinen Wissenstand nicht, und bevor Du fragen musst... ;-)


Nix für ungut, hast das schon richtig erkannt, habe noch nicht wirklich die Ahnung^^.

Habe jetzt aber noch eine Frage, wie bekomme ich die beiden werte zusammengefügt?
i2c_readAck();
i2c_readNak();
Habe das jetzt so verstanden, das der i2c_readAck() die vor Komma stelle ausließt und der i2c_readNak() die nach Komma stelle ausließt. Die sollten Praktischer weise zu einer Zahl zusammen gefügt werden.
Muss ich dafür eine Variable anlegen? Wenn ja was für eine? Eine float?

ciao Hannes

izaseba
29.08.2007, 16:17
i2c_readAck();
i2c_readNak();
Habe das jetzt so verstanden, das der i2c_readAck() die vor Komma stelle ausließt und der i2c_readNak() die nach Komma stelle ausließt. Die sollten Praktischer weise zu einer Zahl zusammen gefügt werden.
Das hast Du richtig verstanden, es hat aber was mit I2C Protokol zu tun, wenn Du mit i2C_readAck() liest, sendet der Master noch ein ACK Puls an den Slave, um zu sagen,
"Hallo wir sind noch nicht fertig, ich will weitere Daten lesen"
Mit i2c_read(Nack) wird halt kein Ack erzeugt womit der Master sagt, "wir sind jetzt fertig, will nichts meh von Dir" darauf folgt Stop und der Bus wird wieder Freigegeben :-)

Tja, das zusammenfügen...
kommt drauf an, was Du willst...
Auf den LCD willst Du sie nicht darstellen(hast Du oben schon gesagt)
Über Uart versenden ? dann mußt Du das ganze in ASCII wandeln
Rechnen ? Da stellt sich die Frage, wie genau ?
Muß es bis auf 0,5 Grad genau gehen ?
Mann könnte das ganze in float wandeln, frage ist nur, ob es lohnt, float ist so eine Sache bei AVR, aber hier ein Beispiel, wie das gehen könnte


float temperatur;
temperatur = i2cpuffer[0];
if (i2cpuffer[1])
temperatur +=0.5;

Eventuell muß man bei der ersten Zuweisung ein cast machen (float)i2cpuffer[0] ?

Gruß Sebastian

Haveaniceday
29.08.2007, 16:40
Es wäre schon schöner wenn ich die 0,5°C genau messen könnte, aber zu not geht es erstmal auch ohne Kommar Stelle.
Will die ganze vorgehensweise erstmal verstehen.

Hier mal mein "Progamm" was ich bis jetzt geschrieben habe, bzw. mit deinen Codes zusammen geflickt habe ^^
Kannst du bitte mal gucken ob es totaler unsin ist, oder was ich da noc ändern muss?



#include <stdio.h>
#include <avr/io.h>

#include"i2cmaster.h"

#define GETTEMP 0xAA
#define I2CTHERMO 0x90
#define STARTCONVERT 0xEE


int Temp; /* Variable für Temperatur */
Temp=i2cpuffer[0]; /*Temperatur Wert des Seonsors der Variablen zuweisen*/

DDRA = (1 << DDA0); /*Pin0 am Port A als ausgang setzten*/

int main(void)
{
if (Temp >= 1900h) /*Bedinung, solange Temperaturwert von 25°C noch nicht erreicht ist*/
{
PORTA |= (1<<PA0);/*soll Ausgang PA0 ein sein (Heizung an)*/
}
else
{
PORTA &= ~(1<<PA0);/*Wenn Temperatur erreicht ist soll Ausgang PA0 wieder ausgeschaltet werden*/
}
endif; /*Ende der if bedinung*/
return 0;
}

i2c_start_wait(I2CTHERMO+I2C_WRITE);
i2c_write(GETTEMP);
i2c_rep_start(I2CTHERMO+I2C_READ);
i2cpuffer[0] = i2c_readAck();
i2cpuffer[1] = i2c_readNak();
i2c_stop();



unsigned char i2cstatus;
i2cstatus = i2c_start(I2CTHERMO+I2C_WRITE);
if (i2cstatus)
{
LCD_puts("Error");-
}
else
{
i2c_write(STARTCONVERT);
i2c_stop();
LCD_puts("Convert starting...");
}
endif;


Danke, ciao Hannes

izaseba
29.08.2007, 19:01
Hallo Hannes,
das sieht schonmal gut aus :-k
Hast Du das Programm durch den Kompiler gejagt ?
Kommst Du aus der Basic Welt ?
also endif gibt es in dieser Weise nicht bei C, es gibt zwar die Präprozessordirektive
#endif, das ist aber etwas anderes...
und if (temp >=1900h) sagt mir auch nichts, was heißt h ?
Hexadezimal oder wie?
Nicht so kompliziert denken ;-)
if(temp >=25) wäre hier besser gewesen...

ich schreibe Dir einfachmal das Programm, versuch es zu verstehen


#include <avr/io.h>
#include "i2cmaster.h"
#define GETTEMP 0xAA
#define I2CTHERMO 0x90
#define STARTCONVERT 0xEE

int main(void) {
char i2cpuffer[2];
DDRA = (1<<PA0);
i2c_start(I2CTHERMO+I2C_WRITE);
i2c_write(STARTCONVERT);
i2c_stop();
for(;;) {
i2c_start_wait(I2CTHERMO+I2C_WRITE);
i2c_write(GETTEMP);
i2c_rep_start(I2CTHERMO+I2C_READ);
i2cpuffer[0] = i2c_readAck();
i2cpuffer[1] = i2c_readNak();
i2c_stop();
if (puffer[0] >= 25)
PORTA |=(1<<PA0);
else
PORTA &=~(1<<PA0);
}
return 0;
}
So in etwa, es kann sein, daß da irgendwo sich ein Fehler versteckt, habe bitte Gnade mit mir, ich habe es eben so zusammengetippt...

Gruß Sebastian

Haveaniceday
29.08.2007, 19:53
Danke,
ne hab es erstmal nur in winAVR eingetippt.
Hab uhrsprünglich C++ gelernt, ist allerdings schon ca. 4 Jahre her.
Den wert 1900h hab ich ausm Datenblatt vom DS1621. Dachte das müsste ich in Hexa oder so eingeben.
Brauche ich den #include <stdio.h> nicht?

ciao Hannes

izaseba
29.08.2007, 20:38
Den wert 1900h hab ich ausm Datenblatt vom DS1621
Hmmm, hex schreibt man in C (und auch C++) 0x** und nicht mit h am Ende.
H am Ende schreibt man in Basic(glaub ich), naja, egal Du kannst auch hex schreiben, wenn Du willst, aber 1900 in hex paßt ja nie in eine 8Bit Variable rein.
stdio.h ? nein, für das kleine Programm nicht, auf dem AVR auch sehr selten,
wenn Du Funktionen, wie printf usw. brauchst dann sollte man stdio.h einbinden, ich habe es noch nie gebraucht...
Sowas braucht man eher auf dem PC.
Das Programm ist auch nicht ganz optimal, es fehlt eine Hysterese usw. aber für die ersten Schritte sollte es wohl mehr als ausreichen,,,

Gruß Sebastian

Haveaniceday
30.08.2007, 14:01
Das ist nicht so schlim. Weil das Program sowieso noch um einiges erweitert werden soll. Z.b. soll die Temperatur in der höhe (Nachts kälter als Tagsüber) gesteuert werden, also per Zeit, welche über ein DCF77 modul eingelesen werden soll usw.
Von daher versuche ich erstmal ein Grundgerüst aufzubauen...

Wofür sind diese beiden Zeilen?

for(;;)

char i2cpuffer[2];


Ich denke mal das "for" ist ne Schleifen Bedinung, aber wofür ist das ;; in der Klammer?; bischhen
Was ich bei der Variablen i2cpuffer[2] nicht ganz verstehe, ist das sie sonst nirgend's mehr verwendet wird.

Ciao Hannes

izaseba
30.08.2007, 18:43
Wofür sind diese beiden Zeilen?

:-s 8-[ :shock:

Puh, ich dachte, das Problem liegt an der i2c Ansteuerung, jetzt sehe ich, daß wir ganz unten in der Krabbelgruppe anfangen müssen :-#

for(;; ) ist eine "never ending story" also Endlos Schleife, man kann auch while(1) schreiben, ist egal, das Programm macht nichts anderes, außer alles was in Klammern {} nach for(;; ) steht auszuführen.
char i2cpuffer[2] deklariert ein Array mit zwei char Werten, und wird wohl gebraucht,
i2cpuffer[0] bezieht sich auf den ersten Wert i2cpuffer[1] auf den zweiten :-k
Ich empfehle Dir irgendein C Buch "C programmieren von Anfang an" von Helmut Erlenkötter oder so, ist sehr gut für Anfänger geeignet, oder "Programmieren in C" von den Vätern der Sprache, ist aber etwas anspruchsvoller als das erste.
Sonst Tutorials im Netz und Üben am PC.
Sonst kannst Du natürlich weiter Fragen, wenn ich die Antwwort weiß, helf ich Dir, sonst jemand anders ;-)

Gruß Sebastian

Haveaniceday
05.09.2007, 17:26
Hi,
Ich hab da nochmal ne frage,.
Undzwar hab ich jetzt AVR sudio installiert, weil ich das Programm auch mal Simulieren wollte, aber AVR Studio zeigt mir immer folgende Fehler an:
../terra_studio.c:10: undefined reference to `i2c_start'
../terra_studio.c:11: undefined reference to `i2c_write'
../terra_studio.c:12: undefined reference to `i2c_stop'
../terra_studio.c:14: undefined reference to `i2c_start_wait'
../terra_studio.c:15: undefined reference to `i2c_write'
../terra_studio.c:16: undefined reference to `i2c_rep_start'
../terra_studio.c:17: undefined reference to `i2c_readAck'
../terra_studio.c:18: undefined reference to `i2c_readNak'
../terra_studio.c:19: undefined reference to `i2c_stop'

Aber diese Variablen sind doch in der i2cmaster.h deklariert oder? Ich hab die Header File i2cmaster.h auch im Program eingefügt, verstehe nicht wo der fehler ist. :-/

Danke, ciao Hannes

izaseba
05.09.2007, 20:12
../terra_studio.c:10: undefined reference to `i2c_start'
../terra_studio.c:11: undefined reference to `i2c_write'
../terra_studio.c:12: undefined reference to `i2c_stop'
../terra_studio.c:14: undefined reference to `i2c_start_wait'
../terra_studio.c:15: undefined reference to `i2c_write'
../terra_studio.c:16: undefined reference to `i2c_rep_start'
../terra_studio.c:17: undefined reference to `i2c_readAck'
../terra_studio.c:18: undefined reference to `i2c_readNak'
../terra_studio.c:19: undefined reference to `i2c_stop'

Bei AVRStudio kann ich Dir leider nicht helfen, ich gehe aber davon aus, daß die i2cmaster.S nicht sauber eingebunden ist...
Wo Du was anklicken musst weiß ich nicht, da sind andere gefragt ;-)


Gruß Sebastian