Forum: Mikrocontroller und Digitale Elektronik LM75 mit Atmaga 8 auslesen und auf LCD ausgeben [c]


von Daniel S. (fsaut)


Lesenswert?

Hallo,
ich möchte einen Temperatursensor LM75 über i²C auslesen und die 
Temperatur auf einem 2x16 Zeichen-Display ausgeben. Meine Hardware ist 
ein myavr mk2 Board mit Atmega8 und ein LCD-Add-on, ebenfalls von my 
avr.Weiterhin habe ich einen LM75 (auf einer Laborplatine verlötet) mit 
an das Board angeschlossen.

Hardwaremäßig funktioniert das ganze (mit der Software 
mySmartusbTerminal kann ich den LM75 auslesen und auch Temperaturen für 
den Schaltausgang zum LM75 schreiben; ich habe ein LED am Schaltausgang, 
die geht also auch bei entsprechender Einstellung). Software soll in C 
erstellt werden.

Da ich absoluter Einsteiger in die Materie bin, habe ich mir im Internet 
Quellcode und Libs gezogen und ein eignes kleines Main geschrieben, aber 
ich bekomme damit noch keine vernünftige Anzeige aufs Display, es steht 
nur immer für den Temperaturwert "1636" und anschließend dann 
abwechselnd irgendwelche Hieroglyphen auf dem Display.

Hier mal mein main:

#define F_CPU 3686400UL

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdint.h>


#include "lcd.h"
#include "I2C.h"
#include "lm75.h"

volatile unsigned short temp;

int main()
{
  while(1)
    {
    lcd_init();
    lcd_on();
    lcd_clear();
    lcd_goto(1,1);
    itoa(lm75_get_temperature, temp, 10 );
    lcd_write_s( "Temp:" );
    lcd_goto(1,6);
    lcd_write_s( temp );
    lcd_goto(2,1);
    lcd_write_s( "Grad Celsius" );
    _delay_ms(3000);
    }
   return 0;
}
 und dazu der Ausschnitt aus dem lm75c, (das ich aus dem Internet habe) 
in dem der Sensor ausgelesen werden soll:

unsigned short lm75_get_temperature (unsigned char address)
{

  unsigned short temperature = 0;
  lm75_init ();
  lm75_send_start ();
  lm75_send_add_rw (address, 1);
  temperature = (lm75_read_byte () << 8);
  temperature |= lm75_read_last_byte ();
  lm75_send_stop ();
  /*returned value will be right-aligned and negative*/


  if (temperature & (1<<15))
  {
    temperature >>= 7;
    temperature |= 0xFEFF;
    return temperature;
  }
  else
  {
    /*returned value will be right-aligned and positive*/
    return (temperature >> 7);
  }

ich versteh jetzt nicht so richtig, wohin eigentlich der ausgelesene 
Wert aus dem Temperaturregister abgespeichert wird (nach meinem 
rudimantären C-Verständnis müßte es doch eine Variable geben, in die der 
ausgelesene Wert abgespeichert wird?) "temperature" kennt allerdings das 
main nicht als globale Variable, hab jetzt mal den Namen der Funktion 
(lm75_get_temperature) im main aufgerufen. So wie ich das verstehe, ist 
das lm75.c ein Unterprogramm, dass sich seinerseits wieder am 
Unterprogramm für die i²C-Kommunikation bedient und mir einen "fertigen" 
Wert für die Temperatur übergibt, den ich dann im main nur noch mit itoa 
umwandeln muss, damit er als ASCII-Code ins Display geschrieben werden 
kann? Vielleicht kann mir jemand weiterhelfen? Bei Bedarf kann ich auch 
mal mein Projekt-Datei (ich arbeite mit AVR-Studio 4.18) hochladen.

Gruß

von Oliver J. (skriptkiddy)


Lesenswert?

itoa erwartet einen char-pointer als 2. Argument.
1
char *  itoa ( int value, char * str, int base );

versuchs mal so:
1
...
2
char temp[10];
3
...
4
itoa(lm75_get_temperature, temp, 10 );
5
...
6
lcd_write_s( temp );
7
...

von Daniel S. (fsaut)


Lesenswert?

Ok, Danke erstmal.
Ich habe das jetzt mal so gemacht und bekomme nun "361" als ausgabe, ist 
schonmal besser als das vorher ;-)
Hab jetzt beim itoa-Befehl mal Basis 2 also:

itoa(lm75_get_temperature, temp, 2)

eingegeben und dann die Anzeige: "101101001" bekommen. Beim Vergleich 
mit dem Datenblatt des LM75 passt es ja insofern, als das es 9 Bit mit 
Informationen sind, da ja (wenn ich das richtig verstanden habe) Bit 0-6 
des Temperaturregisters nicht belegt sind, erst ab Bit 7 gehts los und 
Bit 15 ist das Vorzeichen, sprich eigentlich hätte ich jetzt 
Minus-Temperaturen? Ich weiß halt nicht, wie die Temperatur in dem 
Register des LM 75 kodiert ist, weil es passt ja weder mit bcd-Code, 
noch wenn ich es als 8-Bit Dualzahl lese und in einenDezimalwert 
umrechne. Ich dachte eigentlich, dass die Umkodierung schon im lm75.c 
erfolgt? jedenfalls ist dort die Abfrage nach dem 15.Bit wegen dem 
Vorzeichen drin.

Gruß

von Oliver J. (skriptkiddy)


Lesenswert?

Interpretier mal das erste ausgelesene Byte (MSB) als int8_t. Das ist 
dann die Temperatur in °C als 2er-Komplement.

Daniel S. schrieb:
> Ich dachte eigentlich, dass die Umkodierung schon im lm75.c
> erfolgt?
Zeig mal den Code.


Gruß Oliver

von Lötlackl *. (pappnase) Benutzerseite


Lesenswert?

Vielleicht hilft's ja.
Geklaut aus einem STM32-Beispiel:
1
  /* Get double of Temperature value */
2
  TempValue = LM75_ReadTemp();
3
4
  LM75_ShutDown(DISABLE);
5
6
...
7
8
  if (TempValue == 0) {
9
    /* Zero temperature measured */
10
    lcd_putchar(' ');
11
12
    /* Initialize the temperature sensor value*/
13
    TempValueCelsius = TempValue;
14
  } else if (TempValue <= 250) {
15
    /* Positive temperature measured */
16
    lcd_putchar('+');
17
18
    /* Initialize the temperature sensor value*/
19
    TempValueCelsius = TempValue;
20
  } else {
21
    /* Negative temperature measured */
22
    lcd_putchar('-');
23
    /* Remove temperature value sign */
24
    TempValueCelsius = 0x200 - TempValue;
25
  }
26
27
  /* Calculate temperature digits in °C */
28
  if ((TempValueCelsius & 0x01) == 0x01)
29
  {
30
    TempCelsiusDisplay[1] = 0x05 + 0x30;
31
  } else {
32
    TempCelsiusDisplay[1] = 0x00 + 0x30;
33
  }
34
35
  TempValueCelsius >>= 1;
36
37
...
38
  lcd_putstring("Temp: ");
39
...
40
  printf("%i", TempValueCelsius);
41
  lcd_putstring(TempCelsiusDisplay);
42
  lcd_putchar(0xF8);      // '°'
43
  lcd_putchar('C');

von Marcus D. (maex84)


Angehängte Dateien:

Lesenswert?

Hallo Daniel,

ich bin auch grad am LM75 und habe auch Probleme.

Ich kann zwar Werte auslesen, doch diese haben 16er 
Sprünge(0..16...32...48..64...80..96..112..0...16...usw..)

Man muss diesen Ascii Code in Dezimal umwandeln.


Du kannst mal deinen Code schicken.

Hier ist meiner




Gruss
Marcus

von Oliver J. (skriptkiddy)


Lesenswert?

>temp.low >>=1;
>temp.high<<=9;
>ganzzahl= temp.low | temp.high;
Ich sage mal vorsichtig: das kann nicht richtig sein.


Ich würde an deiner Stelle Folgendes tun:

1. Mal nach 2er-Komplement googeln.

2. Genau überlegen was in einem 8-Bit-Wert bei einem Shift um 9 Stellen
   nach links alles herausfällt.

3. Nochmal das Datenblatt des LM75 zu Rate ziehen und schauen, ob auch
   wirklich ein Shift um eine Stelle reicht, um das LSB an die richtige
   Stelle zu bringen.

4. Genau überlegen, ob es auch wirklich notwendig ist das assemblermäßig
   über Shiftoperationen zu machen.

5. Abwägen ob es nicht eventuell reicht die Auflösung zu halbieren und
   das MS-Byte als Temperatur in °C zu interpretieren.


Gruß Oliver

von Daniel S. (fsaut)


Angehängte Dateien:

Lesenswert?

Hallo,
hier mal der Code von der c-Datei für den LM75 (den hab ich wie gesagt 
so aus dem Internet übernommen). Außerdem das komplette AVR Studio 
Projekt. Wenn ich das Byte, bzw. meine 9 Bit komplementär betrachte, 
passt es leider immer noch nicht:

also ich hatte:

101101001 macht komplemenatär

010010110

geh ich jetzt mal davon aus, dass das MSB das Vorzeichen ist, passt das 
zwar (0 entspricht positiver Temperatur), aber der Rest passt nicht, 
BCD-Code würde Dezimal 96° ergeben, als 8-Bit-Wert Dezimal 150°. Im 
Datenblatt stehen ja auch Beispiele:

+125°C     0 11111010
+25°C      0 00110010
+0.5°C     0 00000001
0°C        0 00000000
— 0.5°C    1 11111111

auch wenn ich hier das Komplement nehem, z.B. bei 25° komm ich nicht auf 
den Dezimalwert, weder BCD noch als zusammenhängende 8 Bit. Das einzige, 
was passt, wäre das LSB als 1. Nachkommastelle zu lesen, d.h. bei 0 sind 
es xxx,0° ; bei 1 wären es xxx,5°.

dann hätte ich aus irgendeinem Grund noch ca. die doppelte Temperatur 
(361=36,5=18,5°?), das deckt sich dann in etwa mit meinem Temometer hier 
im Zimmer?

Gruß

von Daniel S. (fsaut)


Lesenswert?

Was mir grad noch aufgefallen ist:

-wenn der MCU neu gestartet wird, erscheint beim ersten 
Schleifendurchlauf die zweite Zeile im Display (so will ich das 
eigentlich auch haben), nachdem das erste Mal die Delay-Zeit abgelaufen 
ist, wird nur noch die erste Zeile geschrieben, jemand ne Idee, woran 
das liegt?

-der Wert von 361 wird nicht aktualisiert, ich habe den Sensor mal 
erwärmt und abgekühlt, mit dem mySmartUSBTerminal reagiert die 
Temperatur entsprechend, in meinem Programm passiert nichts, es sthet 
immer nur 361 auf dem Display. Durch die Schleife im main  müßte doch 
etwa alle 3s der Wert neu abgefragt werden? oder ich frag irgendwas 
andres ab, aber nicht wie gewollt das Temperatur-Register?

Gruß

von Marcus D. (maex84)


Lesenswert?

Guten Morgen,

danke auch für den Denkanstoss von Oli !
ich hab´s gestern abend kurz vor 12 Uhr noch geschafft.
Es funktioniert jetzt.. logischerweise über das 9Bit Muster.

+125°C   0    1    1    1    1    1     0      1     0

        VZ   64    32  16   8     4     2      1   0,5



@Daniel

Wenn du den Code haben möchtest, schreib mir eine Sms.

bin aber bald in Skiurlaub ! (grins)

Gruss
Marcus

von Alex (Gast)


Lesenswert?

Hallo,

ich habe gerade das gleiche Problem, dass ich den Wert 185 auf LCD habe. 
Der Wert aktualisiert sich nicht und ist immer der gleiche. Deer 
Raumtemp. bei uns ist so etwa 25 °C. Kann mir jemdand helfen die 
richtige Temperatur anzeigen zu lassen.

Danke
Alex

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.