Bits einlesen - wie mache ich das am Besten?

Hallo,

ich benötige bitte Eure Unterstützung. Wir haben ja vor kurzem das Protokoll eines Billig-Funkthermometers weitestgehend entwirrt: http://arduino.cc/forum/index.php/topic,67545.0.html. Nun möchte ich die Bitfolge in den Arduino einlesen um damit einen schönen Temp/Feucht-Logger zu bauen. Die Bitfolge kann z.B. so aussehen:

also hier

111101100000 010010011000 000000101110 111

Regel ist:
High + kurz Low == 1
High + lang Low == 0

Vor der o.g. Bitreihe kommen noch diverse Einsen zum Einpegeln... Wie kann ich diese High/Low-Reihen am Besten einlesen? Ich habe schon G00gl€ durchsucht... Und habe nichts demantsprechendes gefunden. Kann jemand unterstützen?

Hi,
hast du noch einen Interrupt frei ? Dann schick ich dir am Sonntag mal ein kleines Script, das dir bei deinem Problem hilft.

Ich würde es aber auch so machen wie du es schon überdacht hast. Die Zeit zwischen den Impulsen messen.
Dabei würde ich auf jede Flanke reagieren, damit man auch die Low / High Zeiten getrennt bestimmen kann.

Wie schnell kommt die Bitfolge ? Wie hoch ist die Frequenz ?

Wo genau liegt Dein Problem? Der Anschluß des Arduinos? Das erfassen der Daten nachdem der Arduino das Signal schon bekommt? Oder das decodieren im Arduino? Du musst schon etwas genauer werden.

Davon abgesehen würde ich nach "Arduino" und "Manchester" suchen um z.B. sowas zu finden:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1199058664/30.

Hilft Dir das?

Nachwas: "Funkthermometer" und "Mikrocontroller Net" liefert folgenden Treffer:
http://www.mikrocontroller.net/topic/38129

@DE8MSH:

Nach sowas suche ich auch schon länger. Bit-Folgen ( seriell [ RS-232-Protokoll ? ] ) auslesen, und dann dekodieren.
Bei meinen Versuchen wird nur Sh*'t angezeigt.

@Udo Klein: Was meint du mit "Manchester" ?

MfG

@Gurkengräber: folg doch einfach dem Link den ich dazu angegeben habe.
Oder dem hier: Manchester-Code – Wikipedia.

Unabhängig davon ob das nun ein Manchestercode ist oder nicht, beim Decodieren von MC haben die Leute letztendlich die gleichen Probleme. Also würde ich mir so eine MC Lib vornehmen und abschreiben. Das meine ich damit.

hab da schon mal so was ähnliches geschrieben, damit hab ich das DCF77-Signal (Zeitsender) decodiert, hat ganz gut funktioniert

hier der Code, vielleicht hilfts dir ja weiter

int DCF77Pin = 12;
unsigned long time;
int DCFarrey[58];
int bitNummer;
int start;
int Minute;
int Stunde;


void setup(void)
{
  Serial.begin(9600);
  pinMode(DCF77Pin, INPUT);
}

void loop(void)
{
  time = pulseIn(DCF77Pin, LOW);
  if (time > 1500000)
    {
      start = 1;
      bitNummer = 0;
      //for (int i = 0; i <= 57; i++)
      //{
      //  Serial.print(DCFarrey[i]);
      //}
      if (DCFarrey[29]==1){Stunde++;}
      if (DCFarrey[30]==1){Stunde = Stunde + 2;}
      if (DCFarrey[31]==1){Stunde = Stunde + 4;}
      if (DCFarrey[32]==1){Stunde = Stunde + 8;}
      if (DCFarrey[33]==1){Stunde = Stunde + 10;}
      if (DCFarrey[34]==1){Stunde = Stunde + 20;}
      if (DCFarrey[21]==1){Minute++;}
      if (DCFarrey[22]==1){Minute = Minute + 2;}
      if (DCFarrey[23]==1){Minute = Minute + 4;}
      if (DCFarrey[24]==1){Minute = Minute + 8;}
      if (DCFarrey[25]==1){Minute = Minute + 10;}
      if (DCFarrey[26]==1){Minute = Minute + 20;}
      if (DCFarrey[27]==1){Minute = Minute + 40;}
      Serial.print(Stunde);
      Serial.print(":");
      Serial.print(Minute);
      Serial.println();
    }
  if (start == 1)
    {
        if (time > 850000 && time < 1500000){DCFarrey[bitNummer] = 0; bitNummer++;}
        if (time > 750000 && time < 850000){DCFarrey[bitNummer] = 1; bitNummer++;}
        if (start == 1 && bitNummer == 57)
        {
          start = 0;
          Minute = 0;
          Stunde = 0;
        }
    }
}

Jomelo:
Hi,
hast du noch einen Interrupt frei ? Dann schick ich dir am Sonntag mal ein kleines Script, das dir bei deinem Problem hilft.

Ich würde es aber auch so machen wie du es schon überdacht hast. Die Zeit zwischen den Impulsen messen.
Dabei würde ich auf jede Flanke reagieren, damit man auch die Low / High Zeiten getrennt bestimmen kann.

Wie schnell kommt die Bitfolge ? Wie hoch ist die Frequenz ?

Ja, ich habe noch alles frei, da der Code noch nicht steht.

1 ist 23ms High + 9ms Low
0 ist 23ms High + 23ms LOW

Vor der 39igen Bitreihe mit der Temp. und Feucht. gibt es zum Einpegeln

65ms High
23ms Low
16 mal die 0
37ms Low

Hier mal eine gesammte Reihe für 20,2° und 23%:

Sehr spät, aber ich glaub ich habe ein kleines Beispiel.
Kompilieren geht. Inhaltlich weiß ich es nicht.

/* 
 * Die defines geben die Signallaufzeiten an, die Berechnung steht dahinter 
 */
#define _Signal_1         32  //ms (23 high + 9  low)
#define _Signal_0         46  //ms (23 high + 23 low)
#define _Signal_start_end 60  //ms (23 high + 37 low)
#define _Signal_length    40  //Laenge der nutz Daten
#define _Signal_ms_puffer 1   //Wie weit das Signal streuen darf
                              //z.B. _Signal_1 = 32ms
                              //33 >= 32 &&  31 <= 32

/* 
 * Folgende globale Variabeln werden benoetigt
 */
unsigned long signal_time;              // Zeit (ms) Speicher
unsigned char signal_cnt;               // Zaehlt die einzelnen Signale hoch
unsigned char signal_status;            // Status gibt Start- / Endsignal frei
unsigned char signal_error;             // Hiermit koennen gegebenfalls Fehler ausgewertet werden
unsigned char signal_enable;            // Einlesen aktivieren
boolean signal_array[_Signal_length];   // Signal Ergebnis

/* 
 * Mit dieser Funktion kann das ein lesen gestartet werden 
 * Fertig ist es, wenn  signal_cnt = 39 ist  oder aber wenn signal_enable wieder 0 wird
 */
void Get_Bit_Signal_Enable()
{
 signal_cnt     = 0;
 signal_status  = 0;
 signal_error   = 0;
 signal_enable  = 1; 
}

/* 
 * Interrupt Funktion, wird von 0->1 wechsel ausgelöst
 */
void Get_Bit_Signal()
{
  //interne Variable wird, als Berechnungshilfe verwendet
  unsigned int time = 0;
  
  // Abfrage ob eine neue Reihenfolge eingelesen werden soll
  if(signal_enable) {    
    time = millis() - signal_time;
    
    //ungueltige Signal abfangen (Zeit groeßer 70 ms)
    if(time > (_Signal_start_end + 10)) {     
      signal_time = millis();
    }    
    
    
    if(signal_status == 0) {
      //Warten das Start Signal gesendet wird
      if(time >= (_Signal_start_end-_Signal_ms_puffer) && time <= (_Signal_start_end+_Signal_ms_puffer)) {        
        signal_status = 1;
        time = millis();
      }
    } else if(signal_status == 1) { 
      //Start signal wurde gesendet ...
  
      //High Signal auslesen    
      if(time >= (_Signal_1-_Signal_ms_puffer) && time <= (_Signal_1+_Signal_ms_puffer)) {
        //Wert speichern
        signal_array[signal_cnt] = true;        
        //Fehler abfangen
        if(signal_cnt > (_Signal_length-1)) {
          signal_error = true;
        } else {
          signal_cnt++;
        }
        //Zeit zurueck setzen
        time = millis();
      }
      
      //Low Signal auslesen
      if(time >= (_Signal_0-_Signal_ms_puffer) && time <= (_Signal_0+_Signal_ms_puffer)) {
        //Wert speichern
        signal_array[signal_cnt] = false;
        //Fehler abfangen
        if(signal_cnt > (_Signal_length-1)) {
          signal_error = true;
        } else {
          signal_cnt++;
        }
        //Zeit zuruecksetzen
        time = millis();
      }
      
      //Warten auf End Signal
      if(time >= (_Signal_start_end-_Signal_ms_puffer) && time <= (_Signal_start_end+_Signal_ms_puffer)) {        
        signal_enable = 0;
        signal_status = 2;        
      }      
    } else {
     //Schlafen (nix machen)
    } 
  }
}

void setup()
{  
  // Pin x nicht 0 einfach mal nachschauen
  // Interrupt von  0 -> 1 = rising
  attachInterrupt(0, Get_Bit_Signal, RISING);
  
  // wichtig fuer das Beispiel weiter unten
  Serial.begin(9600);
  
}


void loop()
{
  //Beispiel
  //Da mit Interrupts gearbeitet wird muss in der Loop eigenlich nichts mehr drin stehen
  
  //Hier mal ein kleines Beispiel wie man das realisieren könnte, das immer etwas gemacht 
  //wird, wenn ein komplettes Signal eingegangen ist
  if(signal_enable == 0) {
    Get_Bit_Signal_Enable();
    
    // Abfrage ob ein Signal fertig ausgelesen wurde
    if(signal_status == 2) {
     // Mach irgendwas mit dem Signal
     Serial.println("Signal empfangen:");
     
     //Signal Ausgeben in der Console
     for(int i=0; i<_Signal_length; i++) {
       Serial.print(signal_array[i]);
     }
     Serial.println("\n");
    }          
  }   
}

Hi.

wow, danke Dir für das Script! Ich werde das umgehend testen... :slight_smile:

Moin,

die Startsequenz scheint erkannt zu werden... Zumindest ist es so, dass wenn das Signal am Thermometer ankommt auch ein Bitstream ankommt:

...sorry für die schlechte Qualität...

Allerdings wird der Strom noch nicht ganz korrekt erkannt... Fuchse an dem noch herum...

Hier das provisorische RX-Setup:

Was stimmt denn mit dem Strom nicht? Meinst du allgemein die Spannungsversorgung?

Hi,

ich meine den Bit Strom. D.h. es wrid noch nicht genau erkannt wann 0 und wann 1 ist. Kann an meinen Messungen liegen. die ich mit Audacity ausgelesen habe. Ich habe leider kein Oszilloskop...

Der Pegel sollte stimmen, da der o.g. RX TTL ausschüttet...

Probier mal aus, ob du die Streuung etwas erhöhen kannst. z.B. auf

#define _Signal_ms_puffer 5

Wird überhaupt was eingelesen oder ist alles 0 oder alles 1 ?

[edit]
Du könntest auch noch versuchen den signal_error auszuwerten:

Hier mal den neuen Code für die Loopschleife

void loop()
{
  //Beispiel
  //Da mit Interrupts gearbeitet wird muss in der Loop eigenlich nichts mehr drin stehen
  
  //Hier mal ein kleines Beispiel wie man das realisieren könnte, das immer etwas gemacht 
  //wird, wenn ein komplettes Signal eingegangen ist
  if(signal_enable == 0) {
    Get_Bit_Signal_Enable();
    
    // Abfrage ob ein Signal fertig ausgelesen wurde
    if(signal_status == 2) {
     // Mach irgendwas mit dem Signal
     Serial.println("Signal empfangen:");
     Serial.println("Signal details:\n==================");
     Serial.print("Länge: ");
     Serial.println(signal_cnt);
     Serial.print("Error: ");
     Serial.println(signal_error);  
     
     //Signal Ausgeben in der Console
     for(int i=0; i<_Signal_length; i++) {
       if(signal_array[i] == 0 || signal_array[i] == 1) {
         Serial.print(signal_array[i]);
       } else {
         Serial.print("e");
       }
     }
     Serial.println("\n");
    }          
  }   
}

Was wird genau ausgegeben in der Console, kann ja auch sein das ich einen Fehler drin habe.
[/edit]

Hi,

es kommt nicht dazu, dass die 39 Bit aufgefüllt werden. Ich habe schon vonn

#define _Signal_ms_puffer 2

bis

#define _Signal_ms_puffer 10

alles gestestet. Bei "#define _Signal_ms_puffer 10" kommt nur 0,1,0,1,0,1,0,1,0... etc. heraus. Aber rein quantitativ auf keine 39... Ich dachte schon darüber nach einfal mal platt die Dauer der H/L Signale zu messen. Kann man das Script dahingehend umbauen?

P.S.: Die 0 und eins entstammen nicht dem Array sondern ich habe

8<
signal_array[signal_cnt] = true;
Serial.print("1,");

8
und
8<
signal_array[signal_cnt] = false;
Serial.print("0,");
8
zum Debug eingepflegt...

Bei _Signal_ms_puffer 10 ist es klar das kein gültiges Signal mehr raus kommt.
Das liegt daran das bei 10 die Signale ineinander übergehen zwischen Low und High durch die Zeiten (+-10 von 32 => 22-42, von 46 => 36-56)

Hier mal ein Script zum ausgeben, wobei es könnte sein das die Serial.print funktion im Interrupt das Script so dermaßen bremst, dass man das erst in einen Array schreiben muss und dann ausgibt.

unsigned long signal_time =0;


/* 
 * Interrupt Funktion, wird von 0->1 wechsel ausgelöst
 */
void Get_Bit_Signal()
{
  //interne Variable wird, als Berechnungshilfe verwendet
  unsigned int time = 0; 
    
  time = millis() - signal_time;
  signal_time = millis();
  Serial.println(time);  
}

void setup()
{
  // Pin x nicht 0 einfach mal nachschauen
  // Interrupt von  0 -> 1 = rising
  attachInterrupt(0, Get_Bit_Signal, CHANGE);
  
  // wichtig fuer das Beispiel weiter unten
  Serial.begin(9600);  
}

void loop()
{
}

Das klappte auch nicht so richtig mit dem Messen... Jetzt habe ich das hier kurz zusammengestrickt:

int pin = 2;
unsigned long duration;

void setup()
{
  pinMode(pin, INPUT);
    Serial.begin(9600);
    Serial.println("Give it to me...");
}

void loop()
{
  duration = pulseIn(pin, HIGH);
  if ((duration>600)&&(duration<1000)) Serial.print("1,");
  if ((duration>1200)&&(duration<4000)) Serial.print("0,");
}

Nun kommt das heraus für 21,3° und 69%:

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,1,1,1,

"Vorspiel" Vorzeihen? Temp Feucht Keine Ahnung
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1, 1,1,0,0,1,0,0,0,0,1,0,0, 1,0,0,1,0,1,1,0,0,0,0,0, 1,1,1,0,1,0,0,1,1,1,1,1,

Jetzt möchte ich versuchen Deine vorher herausgefundene Bit-Schieberei durchzuführen, sodass ich die Werte angezeigt bekomme... Drückt mir die Daumen :slight_smile:

So, habe mal kräftig mitgeloggt:

000000000000000000   1111   100010000100   011001100000   010011001111
000000000000000000   1111   100010000100   011001100000   010011001111

000000000000000000   1111   100010000100   011001100000   010011001111
000000000000000000   1111   100010000100   011001100000   010011001111

000000000000000000   1111   100010000100   011001100000   010011001111
000000000000000000   1111   100010000100   011001100000   010011001111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   011001100000   010011001111
000000000000000000   1111   100010000100   011001100000   010011001111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   101001100000   000000111111
000000000000000000   1111   100010000100   101001100000   000000111111

000000000000000000   1111   100010000100   001001100000   111101111111
000000000000000000   1111   100010000100   001001100000   111101111111

000000000000000000   1111   100010000100   001001100000   111101111111
000000000000000000   1111   100010000100   001001100000   111101111111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   101001100000   111101111111
000000000000000000   1111   000010000100   101001100000   111101111111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

000000000000000000   1111   000010000100   001001100000   011100011111
000000000000000000   1111   000010000100   001001100000   011100011111

Es werden offensichtlich alle Daten 2x gesendet. Ist mir bei der Audacity-Auswertung garnicht aufgefallen. Naja, jedenfalls nehme ich bei der letzten 12er Kombination Checksumme oder so an. Kam aber aufrgrund Nachdenkens nicht auf der Algho...