Autor Thema: Codeoptimierung 1-wire Temperatursensoren  (Gelesen 712 mal)

Offline PeMue

  • Developer
  • Hero Member
  • ****
  • Beiträge: 4776
Codeoptimierung 1-wire Temperatursensoren
« am: 28 März 2019, 19:48:40 »
Hallo zusammen,

ich brauche mal Hilfe von Softwareentwicklern.

Problemstellung:
Ich möchte auf einem ESP8266 1-wire Sensoren auslesen, die einzelnen Taskschritte sollten aber möglichst wenig Zeit in Anspruch nehmen, da parallel noch ein Serial Server läuft, der auf Anfragen der Heizing (Viessmann GWG Protokoll) reagieren soll.
Dazu habe ich die 1-wire Abfrage in verschiedene Tasks zerlegt und die einzelnen Zeiten gemessen.

Definitionen:
// for 1-wire
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_PIN 0
#define T_PRECISION 12
#define REQUIRESALARMS false                     // no 1-wire alarms for this firmware necessary, redefinition from library

// setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_PIN);
// pass our oneWire reference to Dallas Temperature
DallasTemperature sensors(&oneWire);
// array to hold device addresses
DeviceAddress devices[10];
int devicesFound = 0;
// array for raw temperature
float tempC[10];

1-wire Loop:
//- -----------------------------------------------------------------------------------------------------------------------
// OneWireLoop
//- -----------------------------------------------------------------------------------------------------------------------
void OneWireLoop(void)
{
  // variable for time needed for 1-wire conversion
  static long time_between_measurements;

  // save the time (in ms) since start of processor
  //static long currentMillis = millis();
  //static long currentMillis = 0;
  static long currentStateMillis = 0;
  static int wait_conv_ms = 750 / (1 << (12 - T_PRECISION));

  static enum {START, WAIT_CONV, READ, COLLECT, SEND, WAIT_NEXT, } state=START;
  //static unsigned long int warteSeit;
 
  // loop variable
  static int j=0;

  // state machine, depending on stati
  switch (state)
  {
    // START: actual time stored, count incremented, start measurement
    case START:
      // overwrite time stamp with actual time
      //currentMillis = millis(); // redundant, only for testing
      startTime = millis();
     
      // increment cycle_count
      cycle_count++;
      Serial.print("Before starting (START) "); Serial.print(millis()-startTime, DEC); Serial.println(" ms.");
      sensors.setWaitForConversion(false);  // makes it async -> can be skipped, defined above
      sensors.requestTemperatures();
      Serial.print("After request (START) "); Serial.print(millis()-startTime, DEC); Serial.println(" ms.");
      state=WAIT_CONV;
    break;

    case WAIT_CONV:
      if ((millis()-startTime)>wait_conv_ms) // if wait_conv_ms has been reached, switch to COLLECT (collect data)
      {
        currentStateMillis=millis();
        state=READ;
        Serial.print("After conversion (WAIT_CONV) "); Serial.print(millis()-startTime, DEC); Serial.print(" ms, ");
        Serial.print(millis()-currentStateMillis, DEC); Serial.println(" ms.");
      }
    break;

    case READ:
      if (j < devicesFound) // if still devices available to read temperature
      {
        currentStateMillis=millis();
        tempC[j]=sensors.getTempC(devices[j]);
        Serial.print("After read temperature (READ) loop "); Serial.print(j, DEC);
        Serial.print(" "); Serial.print(millis()-startTime, DEC); Serial.print(" ms, ");
        Serial.print(millis()-currentStateMillis, DEC); Serial.println(" ms.");
        j++;
      }
      else state=COLLECT;
    break;

    case COLLECT:
      j = 0; // set loop variable to 0 again
      currentStateMillis=millis();
      sendstr = "OK VALUES THz 1 cnt=";
      //sendstr += String(cycle_count*UPDATE_TIME/1000, DEC);
      sendstr += String(cycle_count, DEC);
      sendstr += ",";

      // print the device information, must be changed because it is too slow
      for (int i = 0; i < devicesFound; i++)
      {
        sendstr += printAddressStr(devices[i]);
        sendstr += "=";
        // previous function replaced by READ loop
        //sendstr += printTemperatureStr(devices[i]);
        sendstr += String(tempC[j]);
        if (i != devicesFound - 1)
          sendstr += ",";
      }
      Serial.print("After string collection (COLLECT) "); Serial.print(millis()-startTime, DEC); Serial.print(" ms, ");
      Serial.print(millis()-currentStateMillis, DEC); Serial.println(" ms.");
      // get the time for conversion
      //time_between_measurements = millis() - startTime;
      time_between_measurements = millis() - startTime;
      sendstr += ",time_tot=";
      sendstr += String(time_between_measurements, DEC);
      //sendstr += " ms";
      state=SEND;
    break;

    case SEND:
      if (connected)
      {
        currentStateMillis=millis();
        // send string to UPD port, use sendstr instead of replyPacket
    if (Udp.beginPacketMulticast(ipMulti, portMulti, WiFi.localIP()) == 1)
        {
          //Serial.println("after Udp.beginPacketMulticast ...");
      Udp.write(sendstr.c_str());
          //Serial.println("after Udp.write ...");
          Udp.endPacket();
          yield();
          //Serial.println("after Udp.endPacket ...");
    }
      }
      // get the time for sending
      time_between_measurements = millis() - startTime;
      sendstr += ",t_tot=";
      sendstr += String(time_between_measurements, DEC);
      Serial.print("After sending "); Serial.print(millis()-startTime, DEC); Serial.print(" ms, ");
      Serial.print(millis()-currentStateMillis, DEC); Serial.println(" ms.");
      Serial.println(sendstr);
      state=WAIT_NEXT;
    break;
   
    case WAIT_NEXT:
      if ((millis()-startTime)>=UPDATE_TIME) // if UPDATE_TIME has been reached, switch to START again
      {
        currentStateMillis=millis();
        state=START;
        Serial.print("After restart again "); Serial.print(millis()-startTime, DEC); Serial.print(" ms, ");
        Serial.print(millis()-currentStateMillis, DEC); Serial.println(" ms.");
      }
    break;
  } 
}
//- -----------------------------------------------------------------------------------------------------------------------

zugehörige Zeitmessung:
Vitotronic 1-wire demo
Connecting to PMWLAN02 .... connected ...
OTA initialized ...
UDP port at IP 192.168.188.28, UDP port 12345 opened
Locating devices ...
Found 3 device(s).
Parasite power is: OFF
Device 0 Address: 109E85B700080021
Device 1 Address: 10C175B5020800C5
Device 2 Address: 288B22A8000000C2
Before starting (START) 0 ms.
After request (START) 2 ms.
After conversion (WAIT_CONV) 751 ms, 0 ms.
After read temperature (READ) loop 0 763 ms, 12 ms.
After read temperature (READ) loop 1 778 ms, 13 ms.
After read temperature (READ) loop 2 791 ms, 13 ms.
After string collection (COLLECT) 792 ms, 1 ms.
After sending 793 ms, 1 ms.
OK VALUES THz 1 cnt=1,109E85B700080021=25.75,10C175B5020800C5=25.75,288B22A8000000C2=25.75,time_tot=792,t_tot=793
After restart again 5000 ms, 0 ms.

Kurzfassung des Problems:
Wie bekomme ich das Auslesen der Temperaturen
tempC[j]=sensors.getTempC(devices[j]);schneller als die gemessenen 13 ms? Oder anders gefragt: liegt das an dem (langsamen) 1-wire Bus?

Für Tipps wäre ich echt dankbar, mir gehen langsam die Ideen aus.

Danke + Gruß

Peter
1x FB7170 (29.04.88) 5.7 1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F)
1x RPi BV2LCDCSM 1.63 5.7 2xMAX HKT, 1xMAX RT, V200KW1
1xFB 7490 (113.06.05) 5.7 1xCUL V3 1.63 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 1xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU 1xRFXtrx 90 1xWT440H 1xCM160 3xTFA30.3150 5xFA21

Offline Tom Major

  • Full Member
  • ***
  • Beiträge: 386
    • TomMajor@github
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #1 am: 11 April 2019, 23:50:10 »
Zitat
Oder anders gefragt: liegt das an dem (langsamen) 1-wire Bus?

Denke schon das es daran liegt.
Du schickst zum Lesen ca. 20 Byte über den Bus und die Bit time slots sind im Bereich von 60us. Das allein macht schon ca. 10ms ohne Berücksichtigung weiterer overheads.
FHEM 5.x auf Raspberry Pi 3 | OWServer mit I2C/DS2482 | 1-Wire 6fach S0-Stromzähler ATtiny/DS2423 Emu. | Heizungs-Mon. mit Firmata (mighty-1284p) | Ölstand-Mon. mit Ultraschall, RFM69 und JeeLink
RaspberryMatic HM Zentrale | diverse HM Devices | AskSinPP Devices
Informativ Informativ x 1 Liste anzeigen

Offline pizmus

  • Developer
  • New Member
  • ****
  • Beiträge: 34
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #2 am: 15 April 2019, 12:18:58 »
Hallo PeMue,
falls Du keine Software-Lösung findest, könntest Du zusätzliche Hardware einsetzen um die CPU zu entlasten. Das könnte ein Raspberry Pi für die dedizierte Aufgabe sein, oder ein 1-wire Controller wie der von Esera. Es hängt natürlich von vielen Faktoren ab, was da für Dich die beste Lösung ist.
Viele Grüße,
pizmus

Offline Morgennebel

  • Hero Member
  • *****
  • Beiträge: 1350
  • Proud systemd-free zone
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #3 am: 15 April 2019, 12:36:47 »
Ich möchte auf einem ESP8266 1-wire Sensoren auslesen, ... parallel noch ein Serial Server läuft

Ein ESP8266 kostet 3-9 EUR pro Stück. Deine Arbeitszeit mehr. Kauf einfach noch einen :)

Ciao, -MN
Einziger Spender an FHEM e.V. mit Dauerauftrag seit >= 24 Monaten

FHEM: MacMini/ESXi, 2-3 FHEM Instanzen produktiv
In-Use: STELLMOTOR, VALVES, PWM-PWMR, Xiaomi, Allergy, Proplanta, UWZ, MQTT,  Homematic, Luftsensor.info, ESP8266, ESERA

Offline HCS

  • Developer
  • Hero Member
  • ****
  • Beiträge: 3007
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #4 am: 15 April 2019, 12:37:27 »
Oder evtl. auf den ESP32 ausweichen und es in einem eigenen Thread machen.

Offline mumpitzstuff

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1466
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #5 am: 15 April 2019, 14:53:22 »
Je nach Menge der Daten kommen da meines Wissens sehr schnell ein paar ms zusammen. One Wire ist kein high performance bus. Es gibt aber einen Overdrive Modus, mit dem man das noch beschleunigen könnte, ich glaube aber dein Master und auch deine Sensoren müssen das dann irgendwie unterstützen.

Offline PeMue

  • Developer
  • Hero Member
  • ****
  • Beiträge: 4776
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #6 am: 17 April 2019, 15:43:50 »
Hallo zusammen,

danke für Eure Hinweise.
falls Du keine Software-Lösung findest, könntest Du zusätzliche Hardware einsetzen um die CPU zu entlasten. Das könnte ein Raspberry Pi für die dedizierte Aufgabe sein, oder ein 1-wire Controller wie der von Esera.
Beim Optolink Adapter läuft nur der serialServer (mit 4800 Baud) und die 1-wire Messung. Scheinbar funktioniert es, selbst mit den 13 ms, ich werde berichten.

Ein ESP8266 kostet 3-9 EUR pro Stück. Deine Arbeitszeit mehr. Kauf einfach noch einen :)
Ja, wäre eine Möglichkeit. Aber wieder ein zusätzlicher Stromfresser und ein Gerät mehr. Also im Moment keine Alternative. Und: ich versuche auch meine (rudimentär vorhandene) Softwarekenntnisse erweitern.

Oder evtl. auf den ESP32 ausweichen und es in einem eigenen Thread machen.
In diesem Fall müsste ich auf Deine Expertise zurückgreifen  :).

Je nach Menge der Daten kommen da meines Wissens sehr schnell ein paar ms zusammen. One Wire ist kein high performance bus. Es gibt aber einen Overdrive Modus, mit dem man das noch beschleunigen könnte, ich glaube aber dein Master und auch deine Sensoren müssen das dann irgendwie unterstützen.
Das muss mit dem gehen, was die DS18x20 Sensoren hergeben, scheinbar funktioniert es ...

Gruß Peter
1x FB7170 (29.04.88) 5.7 1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F)
1x RPi BV2LCDCSM 1.63 5.7 2xMAX HKT, 1xMAX RT, V200KW1
1xFB 7490 (113.06.05) 5.7 1xCUL V3 1.63 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 1xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU 1xRFXtrx 90 1xWT440H 1xCM160 3xTFA30.3150 5xFA21

Offline Prof. Dr. Peter Henning

  • Developer
  • Hero Member
  • ****
  • Beiträge: 6633
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #7 am: 17 April 2019, 16:26:05 »
Das wird nicht schneller gehen, das Bustiming ist eben so langsam. Eventuell kann man noch mit dem Overdrive Mode arbeiten - aber eben gerade nicht bei den Temperatursensoren.

LG

pah

P.S.: "1-wire Controller wie der von Esera" - machen wir hier nicht etwas zuviel Werbung für ein bestimmtes Produkt, dessen zugehöriges Modul NICHT zum normalen FHEM-Umfang gehört?

Offline Morgennebel

  • Hero Member
  • *****
  • Beiträge: 1350
  • Proud systemd-free zone
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #8 am: 17 April 2019, 17:52:01 »
P.S.: "1-wire Controller wie der von Esera" - machen wir hier nicht etwas zuviel Werbung für ein bestimmtes Produkt, dessen zugehöriges Modul NICHT zum normalen FHEM-Umfang gehört?

Ich glaube jeder Modulautor ist stolz auf seine Arbeit und freut sich, wenn seine Module genutzt werden. Ich sehe ja auch viele Hinweise auf YAAH :-)

Ciao, -MN
Einziger Spender an FHEM e.V. mit Dauerauftrag seit >= 24 Monaten

FHEM: MacMini/ESXi, 2-3 FHEM Instanzen produktiv
In-Use: STELLMOTOR, VALVES, PWM-PWMR, Xiaomi, Allergy, Proplanta, UWZ, MQTT,  Homematic, Luftsensor.info, ESP8266, ESERA

Offline Prof. Dr. Peter Henning

  • Developer
  • Hero Member
  • ****
  • Beiträge: 6633
Antw:Codeoptimierung 1-wire Temperatursensoren
« Antwort #9 am: 17 April 2019, 19:37:38 »
Das kostet aber nichts ...

LG

pah

 

decade-submarginal