Ich versuche den Temperatursensor LM75 auszulesen. Allerdings klappt es
nicht ganz, weil ich nur ein Byte anstatt 2 empfangen kann. Das heißt,
wenn ich das 2. Byte mittels i2c_readNak() auslesen möchte, hängt das
Programm ewig fest. Das erste Byte scheint das richtige Ergebnis (26) zu
haben. Ich hab das ganze in einer Endlosschleife implementiert, welche
jede Sekunde die Temperatur ausliest, dabei aber erstmal nicht das 2.
Byte anfordert. Der 1. Durchlauf funktioniert problemlos, beim nächsten
Durchlauf hängt das Programm aber schon beim Lesen dess 1. Bytes.
Hier der Code:
Ich habe mal ein Bild vom Mega88PA angehängt. Der Temperatursensor ist
direkt an den 2 roten Pins angeschlossen. Ich hab gehört, das Pullups
nötig sind, aber tuns die internen Pullups auch (sind aktiviert)?
Bin für jede Hilfe dankbar.
Anonymus schrieb:> Ich hab gehört, das Pullups> nötig sind, aber tuns die internen Pullups auch (sind aktiviert)?
Nein.
Die internen Pullups sind viel zu hochohmig. Häng extern 4,7k dran.
Ok, ich habe zwischen +5 - SDA und +5 - SCL jeweils ein Pullup
eingebaut. Das Problem besteht jedoch weiterhin... Kann es sein das ich
den Sensor geschädigt habe, weil ich vorher keine Pullups drinnen gehabt
habe?
Hmm, eine kleine google Suche nach LM75 und AVR bringt massig Beispiele
in div Programmiersprachen - ist Dein Google kaputt?
Ich habe mal etwas auf der Platte gekramt: Als ich mal mit dem LM75
'rumspielte', hatte ich die Routinen von Chris Efstathiou benutzt. Auch
danach kann man suchen. Die funzten auf Anhieb.
Wieso kann es nur an der Hardware liegen?
Ich kenne mich mit "C" nicht aus, glaube aber erkennen zu können, du
initialisierst i2c um dann 1 Sekunde später wieder abzuschalten.
Dann folgt deine Abfrageschleife innerhalb du wieder 1 Sekunde wartezeit
eingebaut hast. Warum? Bremst du dich bzw das Programm damit nicht aus?
Die Funktion "i2c_stop" sendet nur ein Stopsignal an den Slave, also sie
schaltet TWI nicht ab. Ich habs natürlich auch ohne Stop versucht,
ändert sich aber nichts am Verhalten. Hab mal gelesen dass es hilfreich
sein soll. Das mit der Wartezeit in der Schleife liegt daran, das ich
die Temperatur im Sekundentakt auslesen möchte.
Also um das Problem jetzt deutlicher zu formulieren: Ich kann maximal 1
Byte mittels 'i2c_readAck()' auslesen. Wenn ich das nächste Byte
auslesen will (egal ob ich danach stoppe und den Slave erneut mit seiner
Adresse anspreche) hängt das Programm an der stelle ewig fest. An den
while - Schleifen die in der Datei 'twimaster.c' sind liegt das nicht,
denn auch wenn ich diese raus nehme hängts weiter. Erst wenn ich den
Controller resette kann ich wieder ein Byte lesen.
Mit 100kHz, laut Datenblatt und den Beispielen die ich gefunden hab ist
das auch in ordnung. Hier die Formel:
1
TWBR=((F_CPU/SCL_CLOCK)-16)/2
Demnach ist 'TWBR = 32' und 'TWSR = 0'. Ich hab den Wert von TWBR auch
probeweise mal auf 16 und TWSR auf 0 gesetzt, was aber keinen
Unterschied gemacht hat.
Danke für das Beispiel. Aber auch hier ist das selbe Problem :(. Ich
habe letztens mal den Sensor mit dem Messgerät gecheckt und
festgestellt, dass durch SDA permanent 4,2V fließen. Das dürfte
eigentlich nicht sein, oder?
Anonymus schrieb:> Danke für das Beispiel. Aber auch hier ist das selbe Problem :(. Ich> habe letztens mal den Sensor mit dem Messgerät gecheckt und> festgestellt, dass durch SDA permanent 4,2V fließen. Das dürfte> eigentlich nicht sein, oder?
Willst du da was anderes sehen? Mit nem Messgerät geht vieles, aber die
Bits siehst du nicht ;)
Hallo!
Ich verwende die I2C-Lib von Peter Fleury und habe eine Frage zum
Auslesen des Temperaturregisters.
Ich gebe das High-Byte und das Low-Byte direkt am PortC und PortB aus
und lasse mir das Ergebnis mit LED´s anzeigen.
Das Ergebnis bei Raumtemperatur (rund 22°C):
High Byte: 0010 0000 = 0x20h
Low-Byte: 0001 0111 = 0x17h
Lt. Datenblatt sollte das Ergebnis im High-Byte rund 0x32h betragen.
So wie ich das verstanden habe, ist das MSB im High-Byte für das
Vorzeichen (+-), die restlichen 7 Datenbits stellen den Temperaturwert
dar und das LSB ist in dem Fall das MSB vom Low-Byte und steht für die
Nachkommastelle.
Keine Ahnung, wie ich diese Werte erhalte?
Hier mein C-Code:
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#include"i2cmaster.h"
4
5
#define DevLM75 0x90 // device address of EEPROM 24C02, see datasheet
6
7
intmain(void)
8
{
9
unsignedcharret,High_Byte,Low_Byte;
10
11
DDRB=0xFF;// use all pins on port B for output
12
DDRC=0xFF;// use all pins on port B for output
13
PORTB=0x00;
14
PORTC=0x00;
15
16
i2c_init();// init I2C interface
17
18
while(1)
19
{
20
/* write 0x75 to eeprom address 0x05 (Byte Write) */
21
ret=i2c_start(DevLM75+I2C_WRITE);// set device address and write mode
22
if(ret)
23
{
24
/* failed to issue start condition, possibly no device found */
0x32 sagt das Datenblatt für +25°C, nicht für ungefähr 22 ;)
Rechne den Wert mal in Temperatur um und lass ihn dir anzeigen.
Beispiel:
1
unsignedshortget_lm75(unsignedcharaddress){
2
charbuffer[2];
3
unsignedshortreturn_value;
4
5
// hier einlesen, buffer[0] = high byte, buffer[1] = low byte
6
7
return_value=(buffer[0]<<8);
8
return_value|=(buffer[1]);
9
return(return_value>>7);
10
}
11
12
doubleget_lm75_celsius(unsignedshortlm75val){
13
floatret=(int)(lm75val&~0x80);
14
ret/=2;
15
if(lm75val&0x80)ret*=-1;
16
returnret;
17
}
//edit: Der Code ist sehr ungünstig für Controller, sinnlose
Arrayzugriffe und Teilen statt schieben, wurde aber auch für Linux und
nicht für AVR/... geschrieben. Würde ich vielleicht nochmal
überarbeiten, wenn ich den auf einem Controller haben wollen würde.
> Das Ergebnis bei Raumtemperatur (rund 22°C):>> High Byte: 0010 0000 = 0x20h> Low-Byte: 0001 0111 = 0x17h
High-Byte und Low Byte vertauscht?
Wenn das was du da geschrieben hast stimmt, dann behauptet dein LM bei
dir sind 32°C. Dreht man aber die beiden Bytes um, dann hat man 23°C
Das High-Byte gibt direkt die Grad als ganze Zahl an (0x17 == 23). Erst
wenn du die 0.5 Grad auch noch haben willst, brauchst du das andere
Byte. (Aber bitte nicht so brutal, wie Nils das gemacht hat)
Karl Heinz Buchegger schrieb:> (Aber bitte nicht so brutal, wie Nils das gemacht hat)
Das sieht tatsächlich sehr stark nach "von hinten durch die Brust ins
Auge" aus.
Nils S. schrieb:>>(Aber bitte nicht so brutal, wie Nils das gemacht hat)> Danke :)
:-)
Das H-Byte (noch als Byte) zuerst auf signed char umcasten, dann auf
signed int (damit die Vorzeichenerweiterung gemacht wird), dann mal 2
(um Platz für das fehlende Bit vom L-Byte zu bekommen) und das L-Bit zb
mit einer Abfrage des MBIT vom LByte einodern.
((int16_t)(int8_t)High_Byte)*2 + LowByte & 0x80 ? 1 : 0;
Oder
int16_t Temperatur = ((int16_t)(int8_t)High_Byte)*2;
if( LowByte & 0x80 )
Temperatur++;
Der WErt ist dann jeweils das Doppelte der tatsächlichen Temperatur.
Karl Heinz Buchegger schrieb:>> High-Byte und Low Byte vertauscht?>> Wenn das was du da geschrieben hast stimmt, dann behauptet dein LM bei> dir sind 32°C. Dreht man aber die beiden Bytes um, dann hat man 23°C
Und genau so ist es auch ! :-)
Vielen Dank!
Warum aber?
Wird normalerweise nicht das High-Byte zuerst ausgelesen?
H. G. schrieb:> Karl Heinz Buchegger schrieb:>>>> High-Byte und Low Byte vertauscht?>>>> Wenn das was du da geschrieben hast stimmt, dann behauptet dein LM bei>> dir sind 32°C. Dreht man aber die beiden Bytes um, dann hat man 23°C>> Und genau so ist es auch ! :-)> Vielen Dank!>> Warum aber?
Beim Ablesen der LED die Ports falsch zugeordnet (kann auch ein
optischer Irrtum sein!)?
Karl Heinz Buchegger schrieb:> ((int16_t)(int8_t)High_Byte)*2 + LowByte & 0x80 ? 1 : 0;
Wie ich schon schrieb, auf einem Controller ist mein Code nicht sehr
brauchbar, aber auf einem Rechner mit mehreren hundert mhz oder mehr,
Multitasking und einem Betriebssystem ist mir das egal ;)
So hab ich meine Zahl, fertig mit Kommastelle und Vorzeichen für printf
usw. und zum Rechnen.
Karl Heinz Buchegger schrieb:> Beim Ablesen der LED die Ports falsch zugeordnet (kann auch ein> optischer Irrtum sein!)?
Ja, Ports vertauscht! -> jetzt funzt alles!
Das ganze werde ich im nächsten Schritt auf eine 7-Segment-Anzeige
bringen.
Positive Temperaturen darzustellen ist mir klar.
Wie zeige ich aber die negativen Temperaturen richtig an?
Hast du da einen Tip für mich?
Nils S. schrieb:> Wenn das Bit für negativ gesetzt ist, dann setze den Pin, der ein Minus> auf der 7seg leuchten lässt.
Ok! Dann habe ich z.B. für -25°C folgendes:
1 1100 1110 = -206
H. G. schrieb:> Nils S. schrieb:>> Wenn das Bit für negativ gesetzt ist, dann setze den Pin, der ein Minus>> auf der 7seg leuchten lässt.>> Ok! Dann habe ich z.B. für -25°C folgendes:>> 1 1100 1110 = -206
Nö.
Du hast 2-er Komplement.
Das linkste Bit sagt dir, dass es sich um eine negative Zahl handelt.
Daher muss zur Ausgabe die Zahl an sich erst mal positiv gemacht werden.
Alle Bits umdrehen und 1 dazuzählen
1 1100 1110
0 0011 0001
+1
0 0011 0010
das ist 0x32 oder dezimal 50. 50 halbe Grade sind 25.0°C
Also muss auf der Anzeige -25.0 stehen.
Aber um den ganzen 2-er Komplement Kram musst du dich nicht kümmern. Um
aus einer negativen Zahl eine positive zu machen, schreibst du einfach
Zahl = -Zahl;
und der Compiler erledigt die Drecksarbeit.
Edit: D.h. wenn du (wie weiter oben), die beiden Bytes korrekt zu einer
16 Bit 2-er Komplement Zahl zusammengesetzt hast. Wenn du das nicht
gemacht hast, dann musst du dich natürlich selber drum kümmern. Ich
würde dir aber raten, erst mal eine korrekte 16 Bit Zahl aus den beiden
Bytes zu machen. Schon alleine deswegen, weil dann auch vergleiche auf
wärmer/kälter, die du vielleicht irgendwann mal machen wirst, (zb für
Minimum/Maximum) wieder korrekt funktionieren.
1
voidAusgeben(int16_tAnzeigewert)
2
{
3
if(Anzeigewert<0){
4
LEDfür'-'einschalten
5
Anzeigewert=-Anzeigewert
6
}
7
else
8
LEDfür'-'ausschalten
9
10
Anzeigewert/10aufdielinke7-Segment
11
Anzeigewert%10aufdierechte7-Segment
12
}
wie du dann den Teil 'auf die xx 7-Segment' realisierst, musst du
wissen. Ich schätze mal, dass da ein Multiplex beteiligt sein wird.
> Karl Heinz Buchegger schrieb:>> ((int16_t)(int8_t)High_Byte)*2 + LowByte & 0x80 ? 1 : 0;
Danke für die ausführliche Anleitung!
Eine Frage habe ich noch zur Typumwandlung.
((int16_t)(int8_t)High_Byte)*2 + LowByte & 0x80 ? 1 : 0;
bis auf den letzten Teil verstehe ich die Zeile!
Was aber bedeutet ? 1 : 0;