Forum: Mikrocontroller und Digitale Elektronik Mehrere Dallas


von Torsten (Gast)


Lesenswert?

Hallo zusammen,

sitze nun schon mehrere Tage daran mehrere Temperatursensoren von Dallas 
auszulesen.
Ich kann sie einzeln sowohl als auch mit dem March-Rom Befehl auslesen. 
Da ich aber ein System mit mehreren ca. 50 Temperatursensoren vor hab zu 
bauen wollte ich jetzt nicht jede ID von den Sensoren hinterlegen wegen 
dem Speicher.
Es gibt jetzt ja den Search-Rom Befehl.
Ich schreibe jetzt den Search-Rom Befehl auf die Leitung und lese 
anschließend die ID des Sensors ein. Anschließend Schreibe ich mit dem 
Match-Rom die Sensor ID auf die Leitung und sage dem der soll die 
Temperatur messen. Ein kurze Pause und ich spreche wieder den Sensor mit 
Match Rom an und lese die Sensor Daten mit dem Read-Scratchpad aus.
Wenn ich einen Sensor hab geht das. Wenn ich jetzt zwei Sensoren habe 
geht das nicht mehr. Auch die ID’s der Sensoren kommen nicht mehr 
richtig an, das ist ein wir war zwischen den beiden.

ID1:        10 0F B7 E4 02 08 00 BF
ID2:        10 52 BD 16 03 08 00 BB
ID1 und 2:  10 02 B5 04 02 08 00 BB
Und Temperaturwerter bekomme ich auch nur wirwar.

Hier mal mein Code

Zum suchen der Dallas und lesen der Temperaturwerter
1
               Bus_Reset();
2
    Byte_Schreiben(Search_Rom);
3
    Rom_Code_Einlesen();
4
    
5
    Byte_Schreiben(Match_Rom);
6
    for (int k=0; k<9; k++)
7
    {
8
      Byte_Schreiben(Rom_Code[k]);
9
    }
10
    Byte_Schreiben(Convert_T);
11
    _delay_ms(1000);
12
13
    Byte_Schreiben(Match_Rom);
14
    for ( int k=0; k<9; k++)
15
    {
16
      Byte_Schreiben(Rom_Code[k]);
17
    }
18
    
19
    Byte_Schreiben(Read_Scratchpad);    
20
    // 9 Byte großen Scratch Pad-Inhalt einlesen
21
    for (int k=0; k<9; k++)
22
    {
23
      Sensordaten[k] = Byte_Lesen();
24
    }

und hier die neben Funktionen
1
unsigned char Rom_Code_Einlesen(void)
2
{
3
  unsigned char i;
4
  Bus_Reset();
5
  Byte_Schreiben(Read_Rom); // "READ ROM"
6
  for (i = 0; i <= 8; i++) {
7
    Rom_Code[i] = Byte_Lesen();
8
        
9
  }
10
  return Rom_Code;
11
}
12
13
void Byte_Schreiben(unsigned char Daten)
14
{
15
  unsigned char i;
16
  for (i = 0; i < 8; i++) {
17
    Bit_Schreiben((Daten & (1<<i)) ? 1 : 0);
18
  }
19
}
20
21
uint16_t Byte_Lesen(void)
22
{
23
  unsigned char i;
24
  unsigned char Byte_Wert = 0;
25
  for (i = 0; i < 8; i++) {
26
    if( Bit_Lesen() == 1 )
27
    Byte_Wert |= (1 << i);
28
  }
29
  return Byte_Wert;
30
}

Oder mache ich da irgendwas gravierend falsch?.

MFG
Torsten

von Peter D. (peda)


Lesenswert?

Torsten schrieb:
> Ich schreibe jetzt den Search-Rom Befehl auf die Leitung und lese
> anschließend die ID des Sensors ein.

Nein.
Nach dem Search-Befehl mußt Du den Search-Algorithmus lt. Datenblatt 
ausführen.
Der gibt Dir dann die nächste gefundene Adresse (8 Byte) und die 
Bit-Nummer den letzten Konflikts zurück. Diese beiden merkst Du Dir dann 
für die nächste Suche.
Nach jeder Suche ist der gefundene Sensor adressiert, d.h. man kann 
dessen Temperatur auslesen.
Wird kein Konflikt mehr zurück gegeben, dann sind alle Sensoren 
gefunden.

Beitrag "DS1820, DS18B20 in C"

von Torsten (Gast)


Lesenswert?

Hallo,

also ich habe mit jetzt einen Search-Algorithmus geschrieben wo 
funktioniert, bekomme meine ganzen Dallas angezeigt.
Nur die Temperratur Berrechnung macht mir noch zu schaffen obwohl sie 
bei den anderen funktioniert hatte.
1
#define  SEARCH_FIRST  0xFF    // start new search
2
#define  PRESENCE_ERR  0xFF
3
#define  DATA_ERR  0xFE
4
#define LAST_DEVICE  0x00    // last device found
5
6
unsigned char id[8], diff;
7
char s[30];
8
unsigned char i;
9
unsigned int temp;
10
11
for( diff = SEARCH_FIRST; diff != LAST_DEVICE; )
12
{
13
  diff = w1_rom_search( diff, id );
14
15
  if( diff == PRESENCE_ERR )
16
  {
17
    uart_puts( "No Sensor found" );
18
    break;
19
  }
20
  if( diff == DATA_ERR )
21
  {
22
    uart_puts( "Bus Error" );
23
    break;
24
  }
25
  if( id[0] == 0x28 || id[0] == 0x10 )
26
  {  // temperature sensor
27
    uart_puts( "ID: " );
28
    for( i = 0; i < 8; i++ )
29
    {
30
      sprintf( s, "%02X ", id[i] );
31
      uart_puts( s );
32
    }      
33
  
34
  Byte_Schreiben(Convert_T);
35
  _delay_ms(800);
36
  Bus_Reset();
37
  Byte_Schreiben(Match_Rom);
38
  for (i=0; i<8; i++)
39
  {
40
    Byte_Schreiben(id[i]);
41
  }
42
  
43
  Byte_Schreiben( Read_Scratchpad );    // read command
44
  for (int y =0; y<9; y++)
45
  {
46
    Sensordaten[y] = Byte_Lesen();
47
    //temp = Byte_Lesen();      // low byte
48
  }
49
  SensorID1 = (Sensordaten[2]<<4);
50
    
51
  temp = Byte_Lesen();
52
53
  temp |= (uint)Byte_Lesen() << 8;    // high byte temp
54
  if( id[0] == 0x10 )      // 9 -> 12 bit
55
  temp <<= 3;
56
  
57
  sprintf( s, "  T: %04X = ", SensorID1); 
58
  uart_puts( s );
59
60
  sprintf( s, "%4d.%01døC", temp >> 4, (temp << 12) / 6553 );
61
  uart_puts( s );
62
    
63
        //Nur zum testen
64
  itoa(temp,Buffer150,10);
65
  uart_puts(Buffer150);
66
  uart_puts("\n");
67
  }
68
}

Ich bekomme die ID's der Sensoren angezeigt und auch meine zwei 
vergebenen bits. Nur bei der Temperratur bekomme ich nur schrott. Bei 
allen zeigt er mir 4095.1084.
Ein Auslese fehler kann es normal nicht sein, ich bekomme ja mein ID's
bleibt eigentlich nur ein Rechenfehler.

von Walter (Gast)


Lesenswert?

lass dir halt mal die beiden Bytes einzeln ausgeben,
was ist das eigentlich für eine magische zAHL: 6553

von Torsten (Gast)


Lesenswert?

Hallo,

ich habe meinen Temperaturmessung nochmals komplett überarbeitet und 
habe auch im Internt viel recherchiert und gelesen.
Jedoch habe ich jetzt noch einen fehler denn ich nicht finde.
Meine Kommastelle ist um eins nach links noch verkehrt.
Das heist anstatt 25,00 C bekomme ich 2,500 C angezeigt.

Hier mal noch mein Überarbeitetes Programm habe es jetzt aber nur für 
einen Fühler am Bus geschrieben.
1
#define THERM_DECIMAL_STEPS_12BIT 625 //.0625
2
3
// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
4
  uint8_t temperature[2];
5
  int8_t digit;
6
  uint16_t decimal;
7
  //Reset, skip ROM and start temperature conversion
8
  Bus_Reset();
9
  Byte_Schreiben(Skip_Rom);
10
  Byte_Schreiben(Convert_T);
11
  //Wait until conversion is complete
12
  while(!Byte_Lesen());
13
  //Reset, skip ROM and send command to read Scratchpad
14
  Bus_Reset();
15
  Byte_Schreiben(Skip_Rom);
16
  Byte_Schreiben(Read_Scratchpad);
17
  //Read Scratchpad (only 2 first bytes)
18
  temperature[0]=Byte_Lesen();
19
  temperature[1]=Byte_Lesen();
20
  Bus_Reset();
21
  //Store temperature integer digits and decimal digits
22
  digit=temperature[0]>>4;
23
  digit|=(temperature[1]&0x7)<<4;
24
  //Store decimal digits
25
  decimal=temperature[0]&0xf;
26
  decimal*=THERM_DECIMAL_STEPS_12BIT;
27
  //Format temperature into a string [+XXX.XXXX C]
28
  sprintf(buffer, "%+d.%04u", digit, decimal);
29
        uart_puts(buffer);

von eProfi (Gast)


Lesenswert?

Im Post 16:23 hast Du ja die 9 Bytes des Scratchpad schon gelesen und 
willst weitere Bytes für temp lesen.
Du musst die bereits gelesenen Bytes auswerten!

>  Byte_Schreiben( Read_Scratchpad );    // read command
>  for (int y =0; y<9; y++)
>  {
>    Sensordaten[y] = Byte_Lesen();
>    //temp = Byte_Lesen();      // low byte
>  }
>  SensorID1 = (Sensordaten[2]<<4);
>
>  temp = Byte_Lesen();
>  temp |= (uint)Byte_Lesen() << 8;    // high byte temp


Und sowas erzeugt eine riesen Bitschiebe-Orgie:
void Byte_Schreiben(unsigned char Daten)
{
  unsigned char i;
  for (i = 0; i < 8; i++) {
    Bit_Schreiben((Daten & (1<<i)) ? 1 : 0);
  }
}

uint16_t Byte_Lesen(void)
{
  unsigned char i;
  unsigned char Byte_Wert = 0;
  for (i = 0; i < 8; i++) {
    if( Bit_Lesen() == 1 )
    Byte_Wert |= (1 << i);
  }
  return Byte_Wert;
}

Besser:
void Byte_Schreiben(unsigned char Daten){
  unsigned char m=1; //Maske
  do{Bit_Schreiben((Daten & m) ? 1 : 0);}while(m*=2);
//wahrscheinlich geht sogar:
  do Bit_Schreiben(Daten & m);while(m*=2);
  //m ist nach 8 Durchläufen wegen Überlauf 0, also false
}

uint16_t Byte_Lesen(void){
  unsigned char m = 1, Byte_Wert = 0;
  do{if(Bit_Lesen()) Byte_Wert |= m;}while(m*=2);
  return Byte_Wert;
}

Lies Dir mal meinen Code durch (ist für DS18S20, evtl. musst Du ihn ein 
wenig anpassen):
Beitrag "Re: DS18S20 - extended resolution bei Temperaturen um 0°C"
weiter unten ist er ausführlich kommentiert.

Viel Erfolg!

von eProfi (Gast)


Lesenswert?

Und warum ist Byte_Lesen(void)  uint16_t?

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.