Luftfeuchtigkeits- und Temperatursensor funktioniert anscheinend nur sporadisch



  • Hallo, also vielleicht kann mir jemand helfen oder hat eine Idee zum Debuggen...

    Ich hab einen ganz einfachen Luftfeuchtigkeits- und Temperatur-Sensor an die GPIOs eines Raspberry Pi angeschlossen. Der Sensor kostet in der Produktion wahrscheinlich nur 0,01 bis 2,00 Euro. Ich weiß weder, um was für einen Sensor es sich handelt, noch hab ich die Dokumentation oder Treiber dafür. Ich muss alles "blind" machen.

    #include <iostream>
    #include <string>
    #include <wiringPi.h>
    #include <chrono>
    #include <thread>
    
    using namespace std;
    
    bool initFinish = FALSE;
    
    class Temp
    {
    public:
        const int LOW_VAL = 0;
        const int HIG_VAL = 1;
        const int pin1;
        int raw[6 * 8];
        int h, c1, c2, sum;
        float humi, temp;
        Temp(const int pin1) : pin1(pin1)
        {
            if (!initFinish)
            {
                initFinish = TRUE;
                wiringPiSetup();
            }
        }
        bool isValidTemp() const
        {
            return sum != 0 && sum == (h + c1 + c2);
        }
        bool readTemp()
        {
            for (size_t i = 0; i < 10; i++)
            {
                readRaw();
                readNumber(&h, 0, 8);
                readNumber(&c1, 16, 24);
                readNumber(&c2, 24, 32);
                readNumber(&sum, 32, 40);
                if (isValidTemp())
                {
                    humi = h;
                    temp = (c1 * 10 + c2) / 10.0;
                    return TRUE;
                }
                delay(2000);
            }
            return FALSE;
        }
        void readNumber(int *x, int a, int b)
        {
            *x = 0;
            for (size_t i = a; i < b; i++)
            {
                *x |= (raw[i] << (7 - (i - a)));
            }
            cout << *x << endl;
        }
        void readRaw()
        {
            pinMode(pin1, OUTPUT);
            digitalWrite(pin1, LOW_VAL);
            delay(20);
            digitalWrite(pin1, HIG_VAL);
            delayMicroseconds(30);
            pinMode(pin1, INPUT);
            readWhile(LOW_VAL, 80);
            readWhile(HIG_VAL, 80);
            for (size_t i = 0; i < 6 * 8; i++)
            {
                int tc = readWhile(LOW_VAL, 50);
                int c = readWhile(HIG_VAL, 80);
                // cout << c << endl;
                if (c > 47)
                {
                    raw[i] = 1;
                }
                else
                {
                    raw[i] = 0;
                }
            }
            cout << "Raw: ";
            for (int i : raw)
            {
                cout << i;
            }
            cout << endl;
        }
        int readWhile(int val, int micros)
        {
            int c = 0;
            do
            {
                if (c == micros)
                {
                    break;
                }
                delayMicroseconds(1);
                c++;
            } while (digitalRead(pin1) == val);
            return c;
        }
    };
    
    ostream &operator<<(ostream &str, Temp const &t)
    {
        string raw = "";
        for (int i : t.raw)
        {
            raw += to_string(i);
        }
        str << "Temperatur: " << t.temp
            << " Luftfeuchtigkeit: " << t.humi
            << " valid: " << t.isValidTemp()
            << " raw: " << raw;
        return str;
    }
    
    Temp temp(4);
    
    void sleepSeconds(int x)
    {
        this_thread::sleep_for(chrono::seconds(x));
    }
    
    int main(int argc, char const *argv[])
    {
        /* code */
        sleepSeconds(5);
        for (size_t i = 0; i < 10; i++)
        {
            cout << temp.readTemp() << endl;
            cout << temp << endl;
            sleepSeconds(2);
        }
        return 0;
    }
    

    Der Sensor liefert auch eine Prüfsumme zurück, ob die Messung gültig war (Zeile 30). Von 20 Messungen ist scheinbar 1 gültige dabei, diese ist dann allerdings sehr genau. Woran könnte das liegen und wie sollte man bei unbekannten "Bauteilen" im Allgemeinem vorgehen?

    Woher die > 47 in Zeile 75? Ich hab irgendwann festgestellt, dass, wenn Daten vorhanden sind, der Sensor 25 Mikrosekunden lang hoch sendet für 0 bzw. 70 Mikrosekunden lang hoch sendet für 1. (Mitte 47,5 Mikrosekunden)



  • @EinNutzer0 sagte in Luftfeuchtigkeits- und Temperatursensor funktioniert anscheinend nur sporadisch:

    wie sollte man bei unbekannten "Bauteilen" im Allgemeinem vorgehen?

    Zuallererst würde ich mich beschweren gehen, denn:

    × Je billiger ein Bauteil ist, desto eher treten Sondereffekte auf. Beispiele: Messungen werden ungenauer, Protokolle werden nicht sauber implementiert, Deep Sleep Modus wird simuliert, Watchdog mit Fütterungszeiten von 125ms, Übertragungsfehler, Modem mit Aufwachproblemen,... Habe alles schon erlebt.
    × Eine Entwicklung eines Treiber ohne Doku ist schon fast ein NoGo. Nutzt das Bauteil komplexere Protokolle (z.B. Bluetooth LE) so ist es fast nicht mehr vertretbar, da die Entwicklungszeit wesentlich höher wird als die Nutzungszeit. Denn...
    × Ohne Doku muss der Sensor bis in letzte Detail untersucht werden. Das wird aufwändig und kostenintensiv, da der Sensor eine Art von Kalibrierung durchlaufen muss. Der Sensor muss in kontrollierte Situationen gefahren und die Sensorausgaben geloggt werden. Es entsteht eine Art Tabelle Luftfeuchtigkeit, Temperatur, Sensorausgaben. Und dann versucht man einen Reim darauf zu machen.

    PS:
    Dein konkretes Problem hört sich fast nach einer zu niedrigen Versorgungsspannung an. Aber ohne Doku kann ich hier nur raten. Sei vorsichtig wenn du an der Spannung drehen willst.



  • Danke für die Antwort. Also, der Sensor sieht aus wie ein DHT11-Sensor: https://funduino.de/anleitung-dht11-dht22

    Die adafruit DHT sensor library funktioniert allerdings nicht, deshalb denke ich es handelt sich um einen anderen Sensor.

    Ich hab es mit 3.3V und mit 5V und mit einem 10KOhm Wiederstand zwischen Spannung und Control ausprobiert...

    Edit: Ja, Du hast recht, Treiber ohne Doku zu entwickeln würde die Kosten aus dem Rahmen fallen, aber in meinem Falle mache ich das privat und aus Lernzwecken...



  • Ich bin schon einen Schritt weiter. Jetzt ist es oft so, dass die erste Messung anscheinend ungültig ist, aber die nachfolgende Messung richtig ist.

    Ich will euch nicht zuspammen, aber ich zeig euch jetzt einmal die Ausgabe einer anscheinend ungültigen und einer gültigen Messung:

        void readRaw()
        {
            pinMode(pin1, OUTPUT);
            digitalWrite(pin1, LOW_VAL);
            delay(20);
            digitalWrite(pin1, HIG_VAL);
            delayMicroseconds(30);
            pinMode(pin1, INPUT);
            cout << readWhile(LOW_VAL, 60) << endl;
            cout << readWhile(HIG_VAL, 80) << endl;
            for (int i = 0; i < 6 * 8; i++)
            {
                int lv = readWhile(LOW_VAL, 80);
                int hv = readWhile(HIG_VAL, 80);
                cout << "l " << lv << " h " << hv << endl;
                if (i == 0 && lv < 10 && hv != 80)
                {
                    i--;
                    continue;
                }
                if (hv > 47)
                {
                    raw[i] = 1;
                }
                else
                {
                    raw[i] = 0;
                }
            }
            cout << "Raw: ";
            for (int i : raw)
            {
                cout << i;
            }
            cout << endl;
        }
        int readWhile(int val, int micros)
        {
            int c = 0;
            while (digitalRead(pin1) == val)
            {
                delayMicroseconds(1);
                c++;
                if (c == micros)
                {
                    break;
                }
            }
            return c;
        }
    
    // ungültig:
    60
    25
    l 27 h 23
    l 18 h 70
    l 25 h 25
    l 25 h 69
    l 27 h 24
    l 26 h 24
    l 27 h 24
    l 27 h 24
    l 27 h 24
    l 27 h 24
    l 26 h 24
    l 26 h 25
    l 27 h 24
    l 26 h 25
    l 26 h 25
    l 26 h 26
    l 26 h 23
    l 27 h 25
    l 26 h 24
    l 27 h 71
    l 27 h 24
    l 27 h 70
    l 27 h 70
    l 27 h 25
    l 27 h 24
    l 27 h 23
    l 10 h 21
    l 23 h 24
    l 12 h 70
    l 26 h 23
    l 27 h 24
    l 27 h 71
    l 27 h 23
    l 27 h 69
    l 27 h 71
    l 26 h 25
    l 0 h 34
    l 0 h 44
    l 10 h 69
    l 27 h 70
    l 27 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    Raw: 010100000000000000010110000010010110001111111111
    80
    22
    9
    99
    // gültig:
    60
    17
    l 25 h 22
    l 16 h 67
    l 25 h 23
    l 26 h 71
    l 26 h 23
    l 25 h 22
    l 27 h 21
    l 29 h 23
    l 28 h 22
    l 30 h 22
    l 29 h 22
    l 29 h 22
    l 24 h 1
    l 20 h 23
    l 11 h 23
    l 26 h 24
    l 27 h 24
    l 27 h 24
    l 27 h 24
    l 27 h 71
    l 27 h 24
    l 26 h 71
    l 27 h 70
    l 27 h 25
    l 24 h 24
    l 29 h 23
    l 31 h 24
    l 27 h 24
    l 26 h 70
    l 27 h 23
    l 26 h 24
    l 27 h 25
    l 27 h 24
    l 27 h 69
    l 27 h 70
    l 27 h 24
    l 27 h 69
    l 27 h 71
    l 26 h 71
    l 27 h 24
    l 26 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    l 0 h 80
    Raw: 010100000000000000010110000010000110111011111111
    80
    22
    8
    110
    1
    Temperatur: 22.8 Luftfeuchtigkeit: 80 valid: 1 raw: 010100000000000000010110000010000110111011111111
    


  • @EinNutzer0

    Mal eine Frage. Handelt es sich bei deinem Sensor im diesen hier?

    DHT11

    Wenn ja, würde ich das PDF mehrmals durchlesen.



  • @Quiche-Lorraine Jein. Er ist zwar auch blau, wie in der Abbildung auf Seite 3 gezeigt, hat aber nur 3 anstatt 4 Anschlüsse...



  • Ok, der 4. Pin wird nicht benutzt und ist deshalb nicht vorhanden. Das ist die richtige PDF.

    Ich weiß nicht warum, aber genau jeder 2. Aufruf von readRaw() funktioniert jetzt:

        void readRaw()
        {
            pinMode(pin1, OUTPUT);
            digitalWrite(pin1, LOW_VAL);
            delay(20);
            digitalWrite(pin1, HIG_VAL);
            delayMicroseconds(30);
            pinMode(pin1, INPUT);
            if (digitalRead(pin1) == HIG_VAL)
            {
                cout << readWhile(HIG_VAL, 80) << endl;
                cout << readWhile(LOW_VAL, 80) << endl;
            }
            else
            {
                cout << readWhile(LOW_VAL, 80) << endl;
                cout << readWhile(HIG_VAL, 80) << endl;
            }
    
            for (int i = 0; i < 6 * 8; i++)
            {
                int lv = readWhile(LOW_VAL, 80);
                int hv = readWhile(HIG_VAL, 80);
                cout << "l " << lv << " h " << hv << endl;
                if (i == 0 && lv < 10 && hv != 80)
                {
                    i--;
                    continue;
                }
                if (hv > 47)
                {
                    raw[i] = 1;
                }
                else
                {
                    raw[i] = 0;
                }
            }
            cout << "Raw: ";
            for (int i : raw)
            {
                cout << i;
            }
            cout << endl;
        }
    


  • @EinNutzer0
    Wie sehen deine Rohdaten aus, wenn du eine richtige und fehlerhafte Messung bekommst?

    Interpretiert deine readWhile() Funktion ein PWM Signal? Sie sieht nämlich empfindlich gegenüber Synchronisations- bzw. Timingfehler aus.

    Das dürfte man an dem Rohdaten sehen, wenn Richtig -
    Falsch konstant ist.

    Ich glaube man kann die PVM Interpretation auch über die CPU machen. Muss aber mal schauen ob und wie das funktioniert...

    Welche CPU nutzt du?



  • @Quiche-Lorraine sagte in Luftfeuchtigkeits- und Temperatursensor funktioniert anscheinend nur sporadisch:

    Interpretiert deine readWhile() Funktion ein PWM Signal? Sie sieht nämlich empfindlich gegenüber Synchronisations- bzw. Timingfehler aus.

    Danke für den Tipp!

    Hab es hinbekommen, jetzt funktioniert nahezu jede Messung:

    class Temp
    {
    public:
        const int LOW_VAL = 0;
        const int HIG_VAL = 1;
        const int pin1;
        int raw[6 * 8];
        int h, c1, c2, sum;
        float humi, temp;
        Temp(const int pin1) : pin1(pin1)
        {
            if (!initFinish)
            {
                initFinish = TRUE;
                wiringPiSetup();
            }
        }
        bool isValidTemp() const
        {
            return sum != 0 && sum == (h + c1 + c2);
        }
        bool readTemp()
        {
            for (size_t i = 0; i < 10; i++)
            {
                readRaw();
                readNumber(&h, 0, 8);
                readNumber(&c1, 16, 24);
                readNumber(&c2, 24, 32);
                readNumber(&sum, 32, 40);
                if (isValidTemp())
                {
                    humi = h;
                    temp = (c1 * 10 + c2) / 10.0;
                    return TRUE;
                }
                delay(3000);
            }
            return FALSE;
        }
        void readNumber(int *x, int a, int b)
        {
            *x = 0;
            for (size_t i = a; i < b; i++)
            {
                *x |= (raw[i] << (7 - (i - a)));
            }
        }
        void readRaw()
        {
            pinMode(pin1, OUTPUT);
            delay(1);
            digitalWrite(pin1, LOW_VAL);
            delay(20);
            digitalWrite(pin1, HIG_VAL);
            // delayMicroseconds(30);
            delayMicroseconds(20);
            pinMode(pin1, INPUT);
            int len0 = 200;
            int a[len0] = {};
            readPulses(a, len0);
            cout << "Raw: ";
            for (int i : a)
            {
                cout << i << ", ";
            }
            cout << endl;
            int start = 0;
            int len1 = 0;
            for (size_t i = 0; i < len0;)
            {
                int j = i;
                while (a[j] >= 50 && a[j] < 60)
                {
                    j += 2;
                }
                int len2 = (j - i);
                if (len2 > len1)
                {
                    start = i;
                    len1 = len2;
                }
                i = j + 2;
            }
            for (size_t i = 1; i < len0;)
            {
                int j = i;
                while (a[j] >= 50 && a[j] < 60)
                {
                    j += 2;
                }
                int len2 = (j - i);
                if (len2 > len1)
                {
                    start = i;
                    len1 = len2;
                }
                i = j + 2;
            }
            cout << start << " , " << len1 << endl;
            for (size_t i = start + 1, j = 0; i < start + len1 && j < 6 * 8; i += 2, j++)
            {
                if (a[i] > 47)
                {
                    raw[j] = 1;
                }
                else
                {
                    raw[j] = 0;
                }
            }
        }
        int readWhile(int val, int micros)
        {
            int c = 0;
            while (digitalRead(pin1) == val)
            {
                delayMicroseconds(1);
                c++;
                if (c == micros)
                {
                    break;
                }
            }
            return c;
        }
        void readPulses(int *a, int len)
        {
            for (int i = 0; i < len; i++)
            {
                if (i % 2 == 0)
                    a[i] = readWhile(LOW_VAL, 100);
                else
                    a[i] = readWhile(HIG_VAL, 100);
            }
        }
    };
    
    ostream &operator<<(ostream &str, Temp const &t)
    {
        string raw = "";
        for (int i : t.raw)
        {
            raw += to_string(i);
        }
        str << "Temperatur: " << t.temp
            << " Luftfeuchtigkeit: " << t.humi
            << " valid: " << t.isValidTemp()
            << " raw: " << raw;
        return str;
    }
    
    Temp temp(4);
    

    Raw: 69, 86, 54, 24, 54, 69, 54, 23, 54, 24, 54, 69, 54, 71, 53, 70, 53, 71, 54, 24, 54, 24, 54, 24, 54, 24, 54, 23, 53, 24, 54, 24, 53, 25, 53, 24, 54, 23, 53, 23, 54, 69, 54, 23, 53, 70, 53, 71, 53, 71, 53, 24, 54, 24, 54, 23, 54, 24, 53, 24, 53, 70, 53, 24, 54, 24, 53, 24, 54, 70, 53, 70, 53, 24, 54, 70, 53, 25, 52, 70, 52, 24, 54, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100,
    2 , 82
    1
    Temperatur: 23.4 Luftfeuchtigkeit: 79 valid: 1 raw: 010011110000000000010111000001000110101010000000

    (Bitte nicht wundern, ich sitze nicht in einer Aufgusssauna, die Luftfeuchtigkeit des Sensors ist etwas ungenau 😉 )


Log in to reply