Forum: Mikrocontroller und Digitale Elektronik Code anpassen (DS18S20)


von Tobias N. (silberkristall)


Lesenswert?

Hallo,

ich habe mir etwas zum auslesen eines DS18S20 geschrieben. Das auslesen 
mittels SkipRom klappt perfekt. Nur würde ich gerne noch mittels ROm 
Code auslesen können.

Hier mal die Codes:
1
// SkipRom
2
3
unsigned char Read_Skip_Temp(void)
4
{
5
    char get[10];
6
    int k;
7
    char temp_c;
8
      
9
    ow_reset();
10
    ow_wr_byte(0xCC); //Skip ROM
11
    ow_wr_byte(0x44); // Start Conversion
12
    _delay_ms(800);
13
    ow_reset();
14
    ow_wr_byte(0xCC); // Skip ROM
15
    ow_wr_byte(0xBE); // Read Scratch Pad
16
    for (k=0;k<9;k++){get[k]=ow_rd_byte();}
17
18
    temp_c = get[0]; // Temp data plus lsb
19
    temp_c = temp_c/2;
20
21
  return (temp_c);
22
}
23
24
// MatchRom
25
26
unsigned char Read_Match_Temp(unsigned char* romaddr)
27
{
28
    int get[10];
29
    int k;
30
    int i;
31
    int temp_c;
32
      
33
    ow_reset();
34
    ow_wr_byte(0x55);
35
    for (i=0; i<8; i++)
36
      {
37
        ow_wr_byte(romaddr[i]);
38
      }
39
40
    ow_wr_byte(0x44); // Start Conversion
41
    _delay_ms(800);
42
    ow_reset();
43
    
44
    ow_wr_byte(0x55);
45
    for (i=0; i<8; i++)
46
      {
47
        ow_wr_byte(romaddr[i]);
48
      }
49
    
50
    ow_wr_byte(0xBE); // Read Scratch Pad
51
    for (k=0;k<9;k++){get[k]=ow_rd_byte();}
52
    
53
    temp_c = get[0];
54
    temp_c = temp_c / 2;
55
56
  return (temp_c);
57
}

Den RomCode habe ich wie folgt in der c datei abgelegt:
1
*** Devices ***/
2
unsigned char sensor1[8] = {16,157,172,77,2,8,0,86};
3
/*** Devices ende ***/

Der MatchRom code klappt garnicht, ich dachte mir an einen aufruf wie

temp = Read_Match_Temp(sensor1);

dabei soll die temperatur dann in temp stehen. Mit SkipRom klappt das 
wunderbar.

Dann hätte ich gerne noch nachkomma stellen und "minus" Temperaturen. 
Leider verlässt mich da mein wissen.

Enweder so das temp dann temp[0] die vorkomma und temp[1] die nachkomma 
temperatur enthält oder noch besser das temp bereits die temperatur 
inkl. nachkomma enthält. Bei Minus dann noch das - (minus Zeichen davor) 
und vielleicht so das man als wert noch eine 1 für plus und eine 0 für 
minus oder so in der art hat um das im Code dann weiter verarbeiten zu 
können.

Wäre toll wenn mir das jemand so anpassen könnte.

Danke euch

Tobias

von Chris (Gast)


Lesenswert?

Hi,

was mir zumindest mal aufgefallen ist:

Deine Funktion Read_Match_Temp ist vom Typ insigned char:

unsigned char Read_Match_Temp(unsigned char* romaddr)


Sie gibt bei dir allerdings einen int zurück, da du temp_c als int 
deklariert hast:

int temp_c;

Soweit ich weiß, hat beim AVR-GCC ein int standardmäßig 16bit,

Eventuell liegt da der Fehler.

lg
Chris

von Tobias N. (silberkristall)


Lesenswert?

Jau, also jetzt klappt das auch mit dem RomCode, also ich kann jetzt die 
Temperatur mittels temp = Read_Match_Temp(sensor1); auslesen, aber halt 
noch ohne nachkomma und minus werten, wäre toll wenn das auch noch 
klappen würde :)

Danke schonmal :)

von Cyblord -. (cyblord)


Lesenswert?

Tobiiiiii....Nicht schon wieder...Wie lange kann man sich an sowas 
eigentlich aufhalten? Vor allem wenn man bedenkt dass du einen 
kompletten Bordcomputer mit Sensoren in 6-8 Wochen gebaut hast ;-)

Aber gut:
Das Problem der Nachkommastellen hat nichts mit dem auslesen zu tun, 
sondern mit der Darstellung. Und die hängt davon ab, wie und worauf du 
den Wert darstellen willst. Der Wert den du ausliest hat bereits alle 
Infos, Vorzeichen und Nachkommastellen enthalten.

Ist dir klar dass die Temperatur in 16tel Grad angegeben wird? Also eine 
Ganzahldivision durch 16 gibt dir die ganzen Grad Celcius. Eine 
Modulo-Division durch 16 gibt dir die Nachkommastellen. Jetzt musst du 
nur noch die ganzen Grade in einen String, ein Komma daneben, dann die 
Nachkommastellen anhängen. Fertig.

Wenn du die 2 Bytes für die Temp in C in eine int16_t Variable steckst, 
hast du automatisch eine Variable mit korrektem Vorzeichen. Da musst du 
sonst gar nichts mehr machen. Wenn die dann mittels itoa in einen String 
umgewandelt wird dann ist auch dort das Vorzeichen korrekt.

gruß cyblord

von Tobias N. (silberkristall)


Lesenswert?

egal ob ich int16_t double float was auch immer nehme, ich kriege immer 
nur GANZzahlen, egal was ich mache und versuche.

von Karl H. (kbuchegg)


Lesenswert?

Tobias N. schrieb:
> egal ob ich int16_t double float was auch immer nehme, ich kriege immer
> nur GANZzahlen, egal was ich mache und versuche.

Tja.
Dann solltest du spätestens jetzt mal herzeigen, was du jetzt machst 
oder versuchst.

von Cyblord -. (cyblord)


Lesenswert?

Tobias N. schrieb:
> egal ob ich int16_t double float was auch immer nehme, ich kriege immer
> nur GANZzahlen, egal was ich mache und versuche.

Du liest ja auch nicht was ich dir schreibe. Die int16_t gibt dir die 
negativen Zahlen. Komma musst du selber ausrechnen und einfügen.

gruß cyblord

von Tobias N. (silberkristall)


Lesenswert?

ok, also ich habe jetzt mal die berechnung aus einem anderen code 
kopiert aber trotzdem nur ganzzahlen, ich vermute schon es liegt an der 
ausgabe selbst, hier mal die codes:


Das auslesen:
1
unsigned char Read_Match_Temp(unsigned char* romaddr)
2
{
3
    int get[10];
4
    int k;
5
    int i;
6
    float temp_c;
7
      
8
    ow_reset();
9
    ow_wr_byte(0x55);
10
    for (i=0; i<8; i++)
11
      {
12
        ow_wr_byte(romaddr[i]);
13
      }
14
15
    ow_wr_byte(0x44); // Start Conversion
16
    _delay_ms(800);
17
    ow_reset();
18
    
19
    ow_wr_byte(0x55);
20
    for (i=0; i<8; i++)
21
      {
22
        ow_wr_byte(romaddr[i]);
23
      }
24
    
25
    ow_wr_byte(0xBE); // Read Scratch Pad
26
    for (k=0;k<9;k++){get[k]=ow_rd_byte();}
27
    
28
    temp_c=(get[0]-0.25f+(((float)get[7]-(float)get[6])/(float)get[7]));
29
    temp_c = (floor(temp_c*10.0+0.5)/10);  
30
    
31
    //temp_c = get[8];
32
    //temp_c = temp_c / get[7];
33
    //temp_c = temp_c * 10;
34
    //temp_c = temp_c / 2;
35
    //temp_c = temp_c / 10;
36
    
37
  return (temp_c);
38
}

Und hier wie ich das in der main.c aufrufe:
1
int main (void)
2
{
3
4
// Timer
5
  // Global Interrupts aktivieren
6
  sei();
7
      
8
    TIMSK |= (1<<TOIE1);
9
    TCCR1B |= (1<<CS11) |  (1<<CS10);     //Prescaler = 64
10
    TCNT1 = 0xFFFF;         //Zaehlregister vorladen mit FFFF zum Sofortstart
11
12
  char Buffer[20];
13
  float temp;
14
    //init lcd
15
    lcd_init();
16
    lcd_clear();
17
  
18
  //lcd_draw_fullscreen_bmp(img);
19
  
20
  while(1)
21
  {
22
  
23
  uhr(minute, stunde);
24
  
25
  ow_reset();
26
  temp = Read_Match_Temp(sensor1);
27
  
28
  itoa(temp, Buffer, 10);
29
  lcd_set_cursor(10,LINE7);
30
  lcd_puts(small_font, "Temperatur: ");
31
  lcd_puts(small_font, Buffer);
32
  }
33
}

von Karl H. (kbuchegg)


Lesenswert?

cyblord ---- schrieb:
> Tobias N. schrieb:
>> egal ob ich int16_t double float was auch immer nehme, ich kriege immer
>> nur GANZzahlen, egal was ich mache und versuche.
>
> Du liest ja auch nicht was ich dir schreibe. Die int16_t gibt dir die
> negativen Zahlen. Komma musst du selber ausrechnen und einfügen.

@TO
Und wenn 0.5°C Auflösung reichen (es gibt selten einen Grund warum das 
nicht reichen sollte), dann ist das auch besonders einfach:
Einfach das MSB und das LSB aus dem Scratchpad zusammenfügen und man 
erhält das Doppelte der Gradzahl vorzeichenrichtig. Bei der Ausgabe kann 
man dann immer noch die Division durch 2 machen und so dann für die 
Ausgabe die Kommastelle generieren.
Aber das alles hat cyblord ja schon geschrieben. Wo also ist dein 
Problem?

von Tobias N. (silberkristall)


Lesenswert?

Naja, er gibt mir bei get[0] 45 aus, wenn ich das durch 2 teile würde 
ich 22,5 bekommen, er gibt mir aber nur 22 auf meinem display aus. laut 
meinem multimeter sind hier 22,7C also 22,5 naja würde ja dann schon 
passen, aber ich erhalte in der ausgabe nie eine nachkomma zahl.

von Karl H. (kbuchegg)


Lesenswert?

temp_c=(get[0]

Schon falsch.
In der Doku steht eindeutig, dass die Temperatur um das 0.5°C Bit, also 
das LSBit bereinigt werden soll.

Sieh dir doch wenigstens die Doku an. So schwer ist das nicht.

Und ja. Du musst erst mal das Scratchpad Byte 0 und 1 zu einem 16 Bit 
Wert zusammenfügen, um die Temperatur zu erhalten. Die wird dann durch 2 
divisiert und mit der erweiterten Formel um 1/16 Grad ergänzt.
Aber eigentlich ist das nur Augenauswischerei. Denn die Nachkommastelle 
hat mit einer realen Temperatur sowieso nicht viel zu tun. Oder hat es 
in deinem Zimmmer an allen Stellen exakt 24.7 Grad?

von Karl H. (kbuchegg)


Lesenswert?

Tobias N. schrieb:
> Naja, er gibt mir bei get[0] 45 aus, wenn ich das durch 2 teile würde
> ich 22,5 bekommen, er gibt mir aber nur 22 auf meinem display aus.

Logisch.
Wiew soll denn in einem Integer eine Nachkommastelle herkommen?

itoa wandelt nun mal einen Integer in seine Textrepräsentierung. Egal ob 
temp ein float ist oder nicht.

von Karl H. (kbuchegg)


Lesenswert?

Und wie soll da

unsigned char Read_Match_Temp(unsigned char* romaddr)


ein float mit Nachkommastellen zurückkommen, wenn der Returnwert der 
Funktion ein unsigned char ist?

von Karl H. (kbuchegg)


Lesenswert?

Und PS:
Wie soll in einem 'unsigned' ein Vorzeichen enthalten sein?

Schon alleine das Wort 'unsigned' impliziert, dass es eben kein 
Vorzeichen gibt.

von Karl H. (kbuchegg)


Lesenswert?

Lassen wir mal das ganze Techtelmechtel mit den 1/16 Grad weg:
1
int16_t Read_Match_Temp(unsigned char* romaddr)
2
{
3
  uint8_t get[10];
4
  uint8_t i;
5
  int16_t temp;
6
      
7
  ow_reset();
8
  ow_wr_byte(0x55);
9
  for (i=0; i<8; i++)
10
  {
11
    ow_wr_byte(romaddr[i]);
12
  }
13
14
  ow_wr_byte(0x44); // Start Conversion
15
  _delay_ms(800);
16
  ow_reset();
17
    
18
  ow_wr_byte(0x55);
19
  for (i=0; i<8; i++)
20
  {
21
    ow_wr_byte(romaddr[i]);
22
  }
23
    
24
  ow_wr_byte(0xBE); // Read Scratch Pad
25
  
26
  for (k=0;k<9;k++)
27
  {
28
    get[k] = ow_rd_byte();
29
  }
30
31
  temp = (int16_t)( ( get[1] << 8 ) | get[0] ); 
32
33
  return temp;
34
}
35
36
...
37
38
int main (void)
39
{
40
41
// Timer
42
  // Global Interrupts aktivieren
43
  sei();
44
      
45
    TIMSK |= (1<<TOIE1);
46
    TCCR1B |= (1<<CS11) |  (1<<CS10);     //Prescaler = 64
47
    TCNT1 = 0xFFFF;         //Zaehlregister vorladen mit FFFF zum Sofortstart
48
49
  char Buffer[20];
50
  int16_t temp;
51
52
  //init lcd
53
  lcd_init();
54
  lcd_clear();
55
  
56
  while(1)
57
  {
58
    uhr(minute, stunde);
59
  
60
    temp = Read_Match_Temp(sensor1);
61
62
    lcd_set_cursor(10,LINE7);
63
    lcd_puts(small_font, "Temperatur: ");
64
65
    sprintf( Buffer, "%+03d.%1d", temp/2, ( temp%2) * 5 ); 
66
    lcd_puts(small_font, Buffer);
67
68
    /* oder
69
      itoa( temp/2, Buffer, 10 );
70
      lcd_puts(small_font, Buffer);
71
      lcd_puts(small_font, ".");
72
      itoa( (temp%2)*5, Buffer, 10 );
73
      lcd_puts(small_font, Buffer);
74
 
75
      aber die sprintf Lösung hat auch noch andere Vorzüge. Unter anderem
76
      den, dass sie mit führenden 0-en nach Bedarf auffüllt. Sie hat aller-
77
      dings auch einen Nachteil: sie braucht Platz und ist vergleichsweise
78
      langsam. Wenn das keine Rolle spielt, dann ist sie aber perfekt.
79
    */
80
  }
81
}

von eProfi (Gast)


Lesenswert?

Dass sich überhaupt noch jemand mit diesem lernresistenten Ignoranten 
und Voll....... abgibt??

Am 17.01.2013 habe ich ihm bereits die Lösung vor die Nase gehalten:
Beitrag "Re: DS18S20 auslesen (finde den fehler nicht)"


Und dass mindestens 100 User die Ausgabe vor ihm auch hinbekommen UND 
dokumentiert haben, ist an ihm ebenso vorübergegangen.

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.