Längere Zeichenfolgen automatisch ersetzen/ DS 1820 / Onewire

Hallo Forum!

Ich vermute diese Frage ist sehr simpel aber die SuFu und Tutorials konntne mir nicht weiterhelfen.

Wie kann ich in einem Sketch eine Zahlenkombination mit Leerzeichen (eine ROM Adresse im HEX Format zB) durch ein Wort ersetzen (“Sensor1” zB).
#define scheint ja nur für mathematische Werte zu funktionieren…

Hintergrund:
Ich benutze zur zur Zeit Sensoren aus der DS1820 Reihe.

Das mittgelieferte Beispielprogramm, welches ich nur teilweise verstehe weil ich ein blutiger Anfänger bin:

-sucht dabei Sensoren im Onewire (ein Bus ähnlich wie I2C)
-fragt deren Adresse ab, printet sie auf dem SerialMonitor,
-fragt die Temperatur ab und printet sie auf dem Serialmonitor.
-Springt dann zum nächsten Sensor.
-Wenn alle abgegrast sind printed es “no more adresses” und der sketch läuft von vorne. (Wie versteht das Programm welche Sensoren schon “abgegrast” sind in diesem Durchlauf des loop???)

Die Ausgabe der Adresse erfolgt im Beispielsketch im Hexformat.
Das ist mir zu umständlich beim auslesen, ich würde die Adresse gerne automatisch durch von mir gewählte Bezeichnungen ersetzen. Am Liebsten noch in den pre-compiler Angaben damit noch unbedarfteren Kollegen es schnell umändern können.

#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)

void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
  
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  } 

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present, HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}

#define scheint ja nur für mathematische Werte zu funktionieren..

Das geht mit allem. Das ersetzt dir sogar Funktionsnamen und Code wenn man nicht aufpasst. Das ist der Grund weshalb Makros i.d.r. in Großbuchstaben geschrieben werden sollten

Du kannst eine Library verwenden:
http://milesburton.com/Dallas_Temperature_Control_Library

Da gibt es mehrere Möglichkeiten die Sensoren zu adressieren. z.B. Einfach über einen Index. Wenn sich dann die Reihenfolge der Sensoren nie ändert braucht man die absoluten Adressen nicht unbedingt.

Oder man legt sich am Anfang einmal ein Arrays aus Adressen an:

DeviceAddress sensorList[] = 
{	
  { 0x28,0x68,0x2A,0xA4,0x05,0x00,0x00,0xAB },
  { 0x28,0x82,0x38,0xA5,0x05,0x00,0x00,0x3D }
};

Dann kann man das machen:

float temp = sensors.getTempC(sensorList[0]);

Das kann man dann auch über Makros ansprechen, z.B. #define SENSOR_1 sensorList[0]

Ok ich hab mal #define Termo1 "16 210 24 188 2 8 0 169" geschrieben..

das bewegt aber den serial.print noch nicht dazu die Zahlenfolge als Namen anzugeben.

Gelten für den serialmonitor oder den LCD Sonderregeln was das umschreiben von #define makros angeht?

Mit Arrays bin ich noch nicht vertraut, aber ich nehme an dass "DeviceAddress" aus der von dir vorgeschlagenen library stammt?

Was unsinnig war weil ich will ja eine makro namens "16 210 24 188 2 8 0 169" erstellen die durch TERMO1 ersetzt werden soll..

Hallo,

ohne Kenntnis der Adressen geht das nicht. Du mußt die Adresse jedes Sensors kennen. Wenn irgendwer einen Bus Scan macht und Du hast einen Sketch der die Adressen einfach der Reihenfolge nach in einen Namen wandelt, was nützt das? Woher will man wissen welcher Sensor welcher Adresse wirklich zugeordnet ist.

Du mußt jeden Sensor auslesen, Adresse notieren, nächsten Sensor auslesen, Adresse notieren ....
Danach kannste jeder Adresse einen Namen verpassen.
Bsp.
DeviceAddress sensor1 = { 0x10, 0x40, 0xDD, 0xC3, 0x2, 0x8, 0x0, 0xB4 };
DeviceAddress sensor2 = { 0x10, 0x8A, 0xB, 0xAC, 0x2, 0x8, 0x0, 0x2C };

Serenifly:

#define scheint ja nur für mathematische Werte zu funktionieren..

Das geht mit allem. Das ersetzt dir sogar Funktionsnamen und Code wenn man nicht aufpasst.

"geht mit allem" ist etwas missverständlich. Es geht mit Namen, und ersetzt die durch ziemlich alles beliebige.
Kann aber nicht "alles beliebige" in was anderes ersetzen.

Was ein Name (identifier) ist bzw. sein kann, ist definiert, (z.B. hier):

  • Ein Leerzeichen kann schnomal gar nicht drin sein.
  • Die allermeisten Sonderzeichen sind verboten. Das _ ist extra erlaubt als Teil eines Namens.
  • Kann nicht mit einer Ziffer anfangen.
  • $ und Nicht-Ascii-Zeichen (z.B. Umlaute) sind zu vermeiden. Könnte vom Compiler abhängen ob erlaubt.

Ausserdem hast du zwar recht, dass der Preprozessor vor dem Compilieren die Makros durch ihre Definitionen ersetzt, aber diesen Zwischenschritt siehst du nicht als Textdatei. Kannst du also nicht als Textverarbeitungs-programm missbrauchen, um in einer vorhandenen Datei einen Text durch einen anderen Text zu ersetzen.

Aber jeder Text-Editor sollte das können.

@Michael_x:
Danke, DAS war jetzt schon mal erhellend, gibt es denn eine funktion die das ersetzen von Zahlenreihe in Wort übernehmen kann?

Da du nicht davor zurückschreckst Basiswissen zu droppen:
Was ist " 0x10, 0x40, 0xDD, 0xC3, 0x2, 0x8, 0x0, 0xB4 " für ein Format ?
Sind das die einzelnen bits aus einer Adresse?

@ DocArduino:
Erst mal Danke für die Antwort :slight_smile:

Ich hab die exakten Adressen doch schon, die werden doch seriell mit dem temperaturwert geprintet, und kann sie auch den einzelnen sensoren zuordnen, ich hab in meinem vorherigen Post sogar eine Adresse im DEC format erwähnt, die von meinem ersten Termometer.

Abgesehen davon: Termometer in die hand "16 210 24 188 2 8 0 169" zeigt 35 grad, also hat der sensor die adresse "16 210 24 188 2 8 0 169"
Warum muss ich dafür elaborierten Code schreiben?

Die einfahcste Möglichkeit wär nach wie vor die Adresse durch ein Wort zu ersetzen aber wie es aussieht geht das mit #define nicht.

Ja. Das der Prä-Prozessor auf Token Basis arbeitet und damit zu ersetzende Zeichenketten natürlich keine Leerzeichen enthalten können hatte ich übersehen :s

Die Sensoren haben eine 64 Bit Adresse. Entsprechend gibt man für die Adresse 8 Bytes an.

Schau dir halt mal die Library an. Wo ist denn das Problem am Anfang eine Liste der Adressen zu definieren? Man kann wie gesagt für jeden Sensor eine passende Variable mit einem Namen anlegen, dem eine Adresse zugeordnet ist.
Mit dem Prä-Prozessor denkst du viel, viel zu kompliziert.

Die Beispiele Sketche verwenden zwar meistens keine festen Adressen, aber wenn man die mal durch den Test-Sketch ausgelesen hat musst du wirklich nur ein paar Variablen anlegen:

OneWire oneWire(5);
DallasTemperature sensors(&oneWire);

DeviceAddress sensor1 = { 0x28,0x68,0x2A,0xA4,0x05,0x00,0x00,0xAB }; 
DeviceAddress sensor1 = { 0x28,0x82,0x38,0xA5,0x05,0x00,0x00,0x3D };

Und schon kannst du das machen:

sensors.requestTemperatures();
float temp1 = sensors.getTempC(sensor1);
float temp2 =  sensors.getTempC(sensor2);

Du hast also eine Funktion getTempC() und der übergibst du die Adresse des Sensors den du auslesen willst (als Variable). Einfacher geht es gar nicht.

Es gibt auch requestTemperaturesByAddress() mit dem man einen ganz bestimmten Sensor veranlassen kann eine Temperatur auszulesen (statt alle Sensoren am Bus).

Ok, dann mach ich mich mal ans Werk!

Hallo,

nun überleg doch mal über Sinn und Unsinn. Wenn Du die Adressen kennst, kannste Dir den Scan sparen. Demzufolge kannste gleich eindeutige Namen den Adressen zuordnen. Wenn man die Adressen von anderen Sensoren nicht kennt, nützen einem auch keine Namen, weil man noch lange nicht weis welcher Sensor zu welcher Adresse gehört.

Überleg mal was passiert, wenn jemand bei Dir, so wie Du das aktuell möchtest, einen Sensor austauscht ...

Man kann mit der Library auch per Index adressieren. Und sich die absoluten Adressen sparen. Wenn dann die Topologie gleicht bleibt und man nur einen Sensor austauscht, sollte das gleich bleiben wenn ich das richtig verstehe. Wenn man allerdings zwischendrin neue Sensoren einfügt, ändert sich auch die Reihenfolge.

Serenifly:
Mit dem Prä-Prozessor denkst du viel, viel zu kompliziert.

Die Beispiele Sketche verwenden zwar meistens keine festen Adressen, aber wenn man die mal durch den Test-Sketch ausgelesen hat musst du wirklich nur ein paar Variablen anlegen:

OneWire oneWire(5);

DallasTemperature sensors(&oneWire);

DeviceAddress sensor1 = { 0x28,0x68,0x2A,0xA4,0x05,0x00,0x00,0xAB };
DeviceAddress sensor1 = { 0x28,0x82,0x38,0xA5,0x05,0x00,0x00,0x3D };



Und schon kannst du das machen:


sensors.requestTemperatures();
float temp1 = sensors.getTempC(sensor1);
float temp2 =  sensors.getTempC(sensor2);




Du hast also eine Funktion getTempC() und der übergibst du die Adresse des Sensors den du auslesen willst (als Variable). Einfacher geht es gar nicht.

Es gibt auch requestTemperaturesByAddress() mit dem man einen ganz bestimmten Sensor veranlassen kann eine Temperatur auszulesen (statt alle Sensoren am Bus).

So hab ichs jetzt gemacht und es war wirklich am simpelsten.
Ich musste erst mal dahintersteigen dass man die bits als {0xA4,0x34...) eingeben muss.. Wie gesagt: Blutiger Anfänger.

Vielen Dank für eure Hilfe, hier kann eigtl. zu.

PS: (Das Problem mit dem Auswechseln werde ich so lösen dass ich einfahc eine Handvoll Sensoren beilege die ich ausgelesen und mit der Adresse etikettiert habe.) Dann muss man nur die Adresse im Sketch aktualisieren.)