Blog der Heimetli Software AG

Signal von Temperatursensor auswerten

Mein erstes Arduino-Projekt!

Zuerst wollte ich es mit einem Raspberry machen, aber bekanntlich sind die relativ heikel wenn die Spannungsversorgung unerwartet unterbrochen wird. Und ich glaube nicht, dass man das Timing für den Decoder zuverlässig hinbringt, denn für solche Anforderungen sind der PI und sein Linux ganz einfach nicht gedacht.

Selbstverständlich wusste ich, dass es die Arduinos gibt, aber ich hatte mich nie gross darum gekümmert. Es stellte sich aber bald heraus, dass er für dieses Projekt genau richtig und relativ günstig zu haben war.

Also habe ich mir einen UNO beschafft, die IDE dazu installiert, und erste Versuche damit gemacht. Das ging überraschend glatt, und schon nach ein paar Stunden funktionierte der Decoder problemlos.

Der UNO erwies sich als gute Wahl, denn man kann ihn über den USB-Anschluss mit Strom versorgen. An diesem USB-Anschluss registriert er sich als serielle Schnittstelle, was ich gleich genutzt habe um die Messwerte in den PC zu bekommen.

Der Sensor

Weil ich schon einen Sensor habe der mit 433MHz sendet, habe ich den auch für dieses Projekt benutzt. In der Beschreibung des letzten Projektes sind alle Angaben zum Sensor zu finden.

Das Signal vom Sensor

Dank der ausgezeichneten Arbeit der Entwickler von rtl_433 blieb es mir erspart, das Protokoll selber zu enträtseln. Da ich vom vorangehenden Projekt wusste, dass es ein Prologue-Protokoll ist, fand ich sofort das passende File im Repository. Den Code habe ich zwar nicht gebraucht, aber die Beschreibung des Signals im Header-Kommentar.

Das Sensorsignal

Die Bits werden durch die Abstände zwischen den Pulsen codiert. Ein langer Abstand (ca. 4000µs) bedeutet eine 1, ein kurzer (ca. 2000µs) bedeutet 0. Als Startsignal dient ein längeres Low-Signal (ca. 9000µs). Die Breite der Pulse ist ca. 500µs.

Genau genommen werden 36 Bit übermittelt, aber die letzten Bits sind bei meinem Sensor irrelevant, deshalb nehme ich nur die ersten 32.

Der Empfänger

Als Empfänger habe ich einen kleines, billiges Printchen von Velleman bei Conrad gekauft. Die führen es unter dem Titel "Empfängerplatine Velleman". Laut Produktbeschreibung hat das Modul eine Reichweite von bis zu 200m. In meiner verseuchten Umgebung kommt es wohl lange nicht so weit, aber es scheint deutlich empfindlicher zu sein als der DVB-Stick.

Wenn der Sensor nicht sendet, sieht man auf einem Oszilloskop die wildesten Ausschläge. Entweder kommt das aus meiner Umgebung, oder es ist das Rauschen des Moduls. Auf jeden Fall braucht es ein sehr scharfes Filter um das Sensorsignal sicher zu erkennen.

Das Sketch

Das Sketch sucht Low-Pegel von mindestens 8000µs Länge, und versucht die folgenden Pulse als Sensorsignal zu decodieren. Um die Störungen zu eliminieren werden die Abstände der Flanken exakt vermessen. Falls die Abstände nicht in genau definierten Bereichen liegen, wird die Erkennung abgebrochen und wieder nach einem Sync gesucht.

Sobald 32 gültige Bits erkannt wurden, schickt das Sketch sie als Hexzahl an den PC, und beginnt mit der Suche nach der nächsten Ausstrahlung.

Der Sensor ueberträgt jede Messung mehrfach, und unter guten Empfangsbedingungen bekommt der PC das auch mit. Da sich der Prozessor im PC sowieso hauptsächlich langweilt, kann er die redundanten Messwerte unterdrücken.

/************************************************************************************************/
/*                                                                                              */
/*                                                                           FILE: Decoder.ino  */
/*                                                                                              */
/*   Decoder for the temperature signal of the pearl sensor                                     */
/*   ======================================================                                     */
/*                                                                                              */
/*   V1.00     04-SEP-2016  Te                                                                  */
/*                                                                                              */
/************************************************************************************************/

#define ST_IDLE   0
#define ST_ACTIVE 1

unsigned long start    = 0 ;
unsigned long value    = 0 ;
int           previous = 0 ;
int           bits     = 0 ;
int           state    = ST_IDLE ;

// Set up the serial port and the input pin
void setup() {
  Serial.begin( 9600 ) ;
  pinMode( 2, INPUT ) ;
}

void loop() {
  // Read the input pin
  int current = digitalRead( 2 ) ;

  // Look for level changes
  if( current != previous )
  {
    // Compute the time since the last change
    unsigned long now = micros() ;
    unsigned long us  = now - start ;

    // Start of a pulse
    if( current == 1 )
    {
      // Check for the sync
      if( us > 8000UL )
      {
        // Start decoding
        value = 0 ;
        bits  = 0 ;
        state = ST_ACTIVE ;
      }
      else
      {
        if( state == ST_ACTIVE )
        {
          // Stop at 32 bits
          if( ++bits > 32 )
          {
            state = ST_IDLE ;
            delay( 10 ) ;

            // Send the value to the PC as a hex number
            Serial.println( value, HEX ) ;
          }
          else
          {
            // Prepare for the next bit
            value <<= 1 ;

            // Short interval, bit is 0
            if( (us >= 1600UL) && (us <= 2200UL) )
              /* Empty statement */ ;
            // Long interval, bit is 1
            else if( (us >= 3500UL) && (us <= 4200UL ) )
               value |= 1 ;
            else
              // Out of range, abort decoding
              state = ST_IDLE ;
          }
        }
      }
    }
    else
    {
      // Abort decoding if the pulse length is out of range
      if( (us < 450UL) || (us > 700UL) )
        state = ST_IDLE ;
    }

    start    = now ;
    previous = current ;
  }
}