Feuchte 00111101 = 16 (also 16%)
Hab ich nicht verstanden, ( meinst du 61 % ?)
sonst aber : Toll !!!
Feuchte 00111101 = 16 (also 16%)
Hab ich nicht verstanden, ( meinst du 61 % ?)
sonst aber : Toll !!!
michael_x:
Feuchte 00111101 = 16 (also 16%)
Hab ich nicht verstanden, ( meinst du 61 % ?)
sonst aber : Toll !!!
Ja, danke - gut aufgepasst. Es muss natürlich 61 heißen.
Hallo,
jetzt haben wir negative Temperaturen und dadurch habe ich einen Fehler in der Ausgabe gemerkt.
Ich poste mal die entscheidenden Zeilen, die geändert werden müssen.
if (Sequenz& 0x0F00) { // negative Werte
Serial.print(int((Sequenz & 0xFFF)|0xF000));
}
else {
Serial.print(Sequenz & 0xFF); // Temp
}
Die Umwandlung in Integer hätte man sicher auch eleganter lösen können, aber ich wollte jetzt nicht zuviel ändern.
Die letzten 12 Bits des Datenstroms stehen für die Temperatur ... Bei negativen Temperaturen sind die ersten 4 Bits der Temperatur "1111".
Ich frage mich warum 4 bit für das Vorzeichen verschwendet werden sollten.
Bist du sicher, dass es nicht einfach eine vorzeichenbehaftete 12 bit - Zahl ist ?
Der Wertebereich wäre dann deutlich größer: statt +-25.6 wären -204.8 ... 204.7 °C übertragbar.
Das ist natürlich -besonders im negativen Bereich- schwer zu testen.
Aber, ich fürchte, dein Code zeigt noch einen Fehler im nächsten Sommer, oder wenn du einen Fön zum Testen über 25 °C nimmst.
int16_t temp = Sequenz & 0x0FFF ;
if (temp & 0x800) temp |= 0xF000; // negativ: Vorzeichenbit setzen
Serial.print (temp);
P.S. Erstaunlich, dass so viel Logik ( Skalierung ) schon im Aussenfühler-Sender steckt. Ist nirgends eine Celsius/Fahrenheit Umschaltung vorgesehen ?
michael_x:
Aber, ich fürchte, dein Code zeigt noch einen Fehler im nächsten Sommer, oder wenn du einen Fön zum Testen über 25 °C nimmst.
Einmal wurde der Code bereits vom Thread-Starter selbst korrigiert, eine weitere Ungereimtheit bei sommerlichen Temperaturen von michael_x aufgedeckt.
Soviel also zum Thema "mal ganz einfach".
Wie lauten doch noch die ersten drei Murphy-Gesetze:
Happy decoding!
BTW: Lidl hat diese Woche ein "AURIOL Funk-Wetterstationsset" als Sonderposten für 49,95 mit Außensensoren auch für Regenmenge und Windgeschwindigkeit. Die Funksensoren scheinen auch auf 433 MHz zu laufen. Leider ohne Datenspeicher, ohne PC-Auswertemöglichkeit und erst Recht ohne Internetanschluss. Ich überlege, ob ich mir eine solche Wetterstation holen und mir selbst zu Weihnachten schenken soll, um mit einem Arduino, einem Ethernet-Shield und einem China-433MHz-Receiver die Decodierung und Umrüstung zur "PC-Wetterstation mit Internetanschluss" probieren soll.
Hallo michael_x
du hast vollkommen Recht. Die Temperatur ist eine vorzeichenbehaftete 12Bit Zahl, irgendwie war ich wohl irritiert wegen der 12 Bit.
Dein Code Schnipsel ist perfekt.
Inzwischen habe ich weitere Erkenntnisse sammeln können, ich fasse mal alles zusammen.
Beispiel für die 36 Bit:
01100010 10010000 00100011 000011011101
Bit 1 9 17 25 36
Bit 1-8 ist Sensor-Kennung, die sich zufällig bei jedem Batteriewechsel ändert
Bit 9 Low Bat Kennzeichnung
Bit 12 auf der Rückseite des Sensors wurde der TX Button gedrückt, damit registriert die Basisstation diesen Sensor als neuen Sensor. Bit ist für eine Sendung=28x36 Bit gesetzt
Bit 17-24 Feuchte
Bit 25-36 Temperatur als vorzeichenbehaftete 12Bit Zahl
Der Sensor hat die Möglichkeit der Umschaltung von °C nach Fahrenheit. Das verändert aber nur die Anzeige auf dem Display des Sensors, die Datenübertragung ist immer in °C
Im nachfolgenden Programm habe ich den Test der Sensorkennung entfernt und die Ausgabe ein wenig besser formatiert. Bei der Darstellung in Binärform werden die führenden Nullen natürlich nicht mit ausgegeben. So sieht dann die Ausgabe aus:
*
*
*
SeqC 1 100110010000000 100011 11011011 219 35
SeqC 2 100110010000000 100011 11011011 219 35
SeqC 3 100110010000000 100011 11011011 219 35
SeqC 4 100110010000000 100011 11011011 219 35
SeqC 5 100110010000000 100011 11011011 219 35
SeqC 6 100110010000000 100011 11011011 219 35
SeqC 7 100110010000000 100011 11011011 219 35
SeqC 8 100110010000000 100011 11011011 219 35
SeqC 9 100110010000000 100011 11011011 219 35
SeqC 10 100110010000000 100011 11011011 219 35
SeqC 11 100110010000000 100011 11011011 219 35
SeqC 12 100110010000000 100011 11011011 219 35
SeqC 13 100110010000000 100011 11011011 219 35
SeqC 14 100110010000000 100011 11011011 219 35
SeqC 15 100110010000000 100011 11011011 219 35
SeqC 16 100110010000000 100011 11011011 219 35
SeqC 17 100110010000000 100011 11011011 219 35
SeqC 18 100110010000000 100011 11011011 219 35
SeqC 19 100110010000000 100011 11011011 219 35
SeqC 20 100110010000000 100011 11011011 219 35
SeqC 21 100110010000000 100011 11011011 219 35
SeqC 22 100110010000000 100011 11011011 219 35
SeqC 23 100110010000000 100011 11011011 219 35
SeqC 24 100110010000000 100011 11011011 219 35
SeqC 25 100110010000000 100011 11011011 219 35
SeqC 26 100110010000000 100011 11011011 219 35
SeqC 27 100110010000000 100011 11011011 219 35
SeqC 28 100110010000000 100011 11011011 219 35
*
SeqC 1 1110110110010 10010000 11000000 192 144
*
*
In diesem Beispiel wurden die 28 Datensätze alle richtig erkannt. Danach wurde einmal ein Datensatz gefunden, der sich nicht wiederholte und damit vom Programm als fehlerhaft verworfen wird. In den meisten Fällen werden 26-28 aufeinander folgende Datensätze erkannt. Vielleicht wird das schlechter, wenn die Entfernung zum Sensor größer wird.
Hier nochmal der veränderte Code
#define PINA 2
#define INTERRUPT 0 // that is, pin 2
volatile unsigned long EdgeTime; // zur Speicherung der Zeit
unsigned long LastEdgeTime=0;
unsigned long DiffEdgeTime=0;
unsigned long LastMillis;
unsigned int Counter;
unsigned long OldSequenz;
long Sequenz, Temp;
unsigned int BitCount, ByteCount, SeqCounter, Kennung;
volatile boolean BitSet;
// Interrupt Service Routine for a falling edge
void isr ()
{
if (!BitSet) {
EdgeTime=micros();
BitSet=true;
}
} // end of isr
void setup ()
{
attachInterrupt (INTERRUPT, isr, FALLING); // interrupt 0 is pin 2
Serial.begin(115200);
}
void loop ()
{
while(millis()-LastMillis < 5000) { // jede 5 Sekunden Status
if (BitSet) {
DiffEdgeTime = EdgeTime-LastEdgeTime;
if (DiffEdgeTime > 800) { // alles kleiner ist Fehler
if (DiffEdgeTime>8000 && DiffEdgeTime<8500) { // Synchronisationpuls
Counter=0;
Sequenz=0;
}
else if (DiffEdgeTime>1800 && DiffEdgeTime<2300) {
Sequenz <<= 1;
Sequenz |= 1; // eine 1 von rechts rein
Counter++;
}
else if (DiffEdgeTime>900 && DiffEdgeTime<1300) {
Sequenz <<= 1; // eine 0 von rechts rein
Counter++;
}
/* if (Counter==8 && Sequenz!= B11000101) { // Sensor Kennung
Counter=0;
Sequenz=0;
}*/
if (Counter==16) Kennung=Sequenz; // SensorKennung
if (Counter==36) {
if (OldSequenz==Sequenz) {
SeqCounter++; // Anzahl gleicher Sequenzen in Folge
}
else {
SeqCounter=1;
}
OldSequenz=Sequenz;
Serial.print("SeqC ");
Serial.print(SeqCounter);
Serial.print(" ");
Serial.print(Kennung,BIN);
Serial.print(" ");
Serial.print((Sequenz&0xFF000)>>12,BIN);
Serial.print(" ");
Serial.print((Sequenz&0x00FFF),BIN);
Serial.print(" ");
Temp = Sequenz & 0x0FFF;
if (Sequenz & 0x0800) { // negative Werte
Temp |= 0xF000; // Vorzeichen zur Ausgabe setzen für 16Bit INT
}
Serial.print(Temp);
Serial.print(" ");
Sequenz >>= 12;
Serial.println(Sequenz & 0xFF); // Feuchte
Counter=0;
Sequenz=0;
}
}
LastEdgeTime=EdgeTime;
BitSet=false;
}
}
LastMillis=millis();
Serial.println("*");
}
Dieses Programm ist ja gedacht zum Debuggen. Der nächste Schritt wird jetzt sein, Temperatur und Feuchte auf LCD anzuzeigen oder auf eine SD Karte zu loggen.
Leider scheint dieser Sensor nicht mehr erhältlich zu sein. Ich häng mal ein Foto an.
Nachtrag: Ich hab gerade mal den Sensor in den Gefrierschrank gelegt. Wenn man Glück hat kommen 4 Datensätze in Folge ohne Fehler an.
jurs:
Soviel also zum Thema "mal ganz einfach".
Wie lauten doch noch die ersten drei Murphy-Gesetze:
- Nichts ist so einfach wie es scheint.
- Alles dauert länger als Du denkst.
- Wenn irgendwas schiefgehen kann, wird es auch schiefgehen.
Na ja, im Vergleich zu anderen Dokodierversuchen, wo hier im Forum gemeinsam lange orakelt wurde, war das doch wirklich einfach.
Und ohne Murphy ist alles hur halb so lustig.
Bin mal gespannt, ob sich die Lidl Station dekodieren lässt.
Gruss
Danke Murphy!
Statt
long Sequenz, Temp;
muss es richtig heissen
long Sequenz;
int Temp;
Wenn schon, tut auch nichts zur Sache, aber schöner wäre:
[b]unsigned [/b] long Sequenz;
Übrigens, ich finde, dank deines sehr guten Ansatzes, war die Dekodierung wirklich "mal ganz einfach".
Glückwunsch ernie-bernie
Hallo,
das sind ja recht gute Anregungen. Ich hab heute erstmal mit dem Audacity das Bild der Aldi Außensensoren aufgenommen.
Das ist ja ein Problem, was noch ungelöst bei mir rumliegt. Die Sensoren senden dreimal hintereinander gleiche Datenpakete,
da müssten die letzten beiden mit sicherheit dekodierbar sein. Falls ich Erfolge habe, melde ich mich, wenn nicht, auch.
Gruss Kalli
Kalli:
das sind ja recht gute Anregungen. Ich hab heute erstmal mit dem Audacity das Bild der Aldi Außensensoren aufgenommen.
Das ist ja ein Problem, was noch ungelöst bei mir rumliegt. Die Sensoren senden dreimal hintereinander gleiche Datenpakete,
da müssten die letzten beiden mit sicherheit dekodierbar sein.
Ja, sicherlich. Mit entsprechend Gehirnschmalz dürfte es machbar sein, wenn man die Bits erstmal auslesen kann.
"Kryptographisch verschlüsselt" sind die Bits in den Funkdaten wohl nicht, sondern nur "codiert".
Ich habe mich auch noch mal etwas näher informiert, und zumindest die ganz einfachen 433-MHz-Module der billigsten Funk-Thermometer und Funk-Wetterstationen scheinen alle nach demselben Grundschema mit ASK/OOK (Amplitudenmoduliertes Signal mit ON/OFF-Tastung) zu arbeiten. Und dabei immer dasselbe Sendeschema zu haben, dass zu LOW Pulsen verschiedener Länge am Empfänger führt. Es gibt quasi Bits mit drei verschiedenen Längen:
Und das nicht nur beim Tchibo-Funkthermometer, sondern bei fast allen billigen 433-MHz Funkthermometern und Funkwetterstationen.
Bei einem Controller-Takt von 16 MHz und einer Datenbitrate von höchstens 10 KBit/s frage ich mich, ob man sich die Auswertung von Sendeimpulsen am Oszilloskop oder per Soundkartenaufnahme nicht sparen kann, wenn man einfach einen Arduino-Sketch schreibt, zur Analyse und Vorab-Auswertung, der einem einfach Daten ausgibt wie:
Wenn man von so einer Vorauswertung per Arduino-Sketch dann schon ohne viel Aufwand die richtigen Längen für Startbit, 0-Bit, 1-Bit und die Anzahl der Bits in den Datenpaketen automatisch bekommen hat, kann man gleich mit einem speziellen Auswerteprogramm zur Auswertung der Bits weitermachen.
Solche ein bequemes Wettersensor-Vorauswertungsprogramm gibt es wohl noch nicht, wenn zum Dekodieren üblicherweise mit Bildern vom Oszilloskop oder von einem Soundkarten-Aufnahmeprogramm angefangen wird, oder?
Hallo jurs,
wenn du mein Programm in diesem Beitrag auf die Biterkennung reduzierst, macht es genau das, was du beschrieben hast.
Worauf stützt du deine Darstellung, dass die Kodierung immer so läuft bei den billigen Stationen?
Ich finde den ersten Einstieg über die Soundkarte gar nicht so schlecht, da weiß man zumindest schon mal, was man zu erwarten hat.
Die Zeiten kann man dann sehr einfach über ein Programm messen, dass eigentlich für IR Fernbedienungen gedacht ist. Arduino Playground - InfraredReceivers. Einfach statt des IR-Empfänger einen 433 MHz Empfänger anschließen.
Wenn man die Zeiten dann in mein Programm nimmt, ist man schon fast am Ziel. Jetzt muss man nur noch die Bits zuordnen.
@Kalli: stell doch mal einen Screenshot von deiner Audacity Messung an deinem Sensor hier rein.
erni-berni:
Worauf stützt du deine Darstellung, dass die Kodierung immer so läuft bei den billigen Stationen?
Immer wohl nicht.
Aber ganz, ganz oft.
Ich habe hier im Haus nun schon drei 433MHz-Funksensoren rausgekramt, die alle nach demselben Schema senden:
Allerdings gibt es Unterschiede zwischen den Sensoren:
Verschiedene Startbitlänge, verschiedene 1-Bit Länge, verschiedene 0-Bit Länge, und verschieden viele Bits in einem Datenpaket.
Und wenn man nur mit Try-and-Error herumprobiert, ist das eine mühsame Angelegenheit, die Startbitlänge, 1-Bit-Länge, 0-Bit-Länge und Anzahl der Datenbits im Paket herauszubekommen. Dafür hätte ich gerne einen Sketch, der das automatisch ermittelt und rauswirft, was so an Funk herumschwirrt.
erni-berni:
wenn du mein Programm in diesem Beitrag auf die Biterkennung reduzierst, macht es genau das, was du beschrieben hast.
Nicht so ganz, Deinem Programm muß ich ja wenigstens ungefähr die Startbitlänge, 0-Bit Länge und 1-Bit Länge vorgeben, sonst wird das mit der Biterkennung nichts. Das sind ja Werte, in denen sich die Sensoren gerade unterscheiden. Und die Timings der Bits würde ich gerne direkt, ohne Umweg über Soundkarte oder Oszilloskop ermitteln, nur mit dem Arduino.
erni-berni:
Ich finde den ersten Einstieg über die Soundkarte gar nicht so schlecht, da weiß man zumindest schon mal, was man zu erwarten hat.
Tja, da muss man dann wohl zu Anfang mit loslegen, wenn man seinen Sensor mit "bekannten" Timingwerten anderer Sensoren (Tchibo und Co.) nicht im Datenstrom identifizieren kann. Diese billigen 433-MHz Empfänger empfangen ja immer irgend etwas, selbst wenn sie nichts empfangen. In den Empfangspausen drehen die intern immer die Empfangsempfindlichkeit so weit auf, bis sie Rauschen empfangen - und dann ist das Rauschen auf dem Datenausgang. Und man selbst steht vor dem Problem zu erkennen: Was ist Rauschen - was sind die Nutzdaten eines Funk-Sensors?
Ich habe das oben erwähnte Programm mal für den Zweck der Messung der Implulse angepasst.
// Das ursprüngliche Programm stammte von
/*
* Author..... Walter Anderson
* E-mail..... wandrson@walteranderson.us
*
* Source: http://playground.arduino.cc/Code/InfraredReceivers
*/
#include <avr/interrupt.h>
#include <avr/io.h>
#define TIMER_RESET TCNT1 = 0
#define SAMPLE_SIZE 128
int IRpin = 2;
unsigned int TimerValue[SAMPLE_SIZE];
char direction[SAMPLE_SIZE];
byte change_count;
long time;
void setup() {
Serial.begin(115200);
Serial.println("Analyze IR Remote");
TCCR1A = 0x00; // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled
// ICNC1=0 => Capture Noise Canceler disabled -- ICES1=0 => Input Capture Edge Select (not used) -- CTC1=0 => Clear Timer/Counter 1 on Compare/Match
// CS12=0 CS11=1 CS10=1 => Set prescaler to clock/64
TCCR1B = 0x03; // 16MHz clock with prescaler means TCNT1 increments every 4uS
// ICIE1=0 => Timer/Counter 1, Input Capture Interrupt Enable -- OCIE1A=0 => Output Compare A Match Interrupt Enable -- OCIE1B=0 => Output Compare B Match Interrupt Enable
// TOIE1=0 => Timer 1 Overflow Interrupt Enable
TIMSK1 = 0x00;
pinMode(IRpin, INPUT);
}
void loop()
{
Serial.println("Waiting...");
change_count = 0;
while(digitalRead(IRpin) == LOW) {}
TIMER_RESET;
TimerValue[change_count] = TCNT1;
direction[change_count++] = '1';
while (change_count < SAMPLE_SIZE) {
if (direction[change_count-1] == '0') {
while(digitalRead(IRpin) == LOW) {}
TimerValue[change_count] = TCNT1;
direction[change_count++] = '1';
TIMER_RESET;
} else {
while(digitalRead(IRpin) == HIGH) {}
TimerValue[change_count] = TCNT1;
direction[change_count++] = '0';
TIMER_RESET;
}
}
Serial.println("Bit stream detected!");
change_count = 1;
time = (long) TimerValue[change_count] * 4;
while (change_count < SAMPLE_SIZE) {
time = (long) TimerValue[change_count] * 4;
Serial.print(time);
Serial.print("\t");
Serial.println(direction[change_count-1]);
change_count++;
}
Serial.println("Bit stream end!");
delay(2000);
}
Wenn man Glück hat und einen gültigen Datenstrom einfangen kann, sieht das ganz gut aus. Allerdings kommt wie bereits schon gesagt auch viel Müll an. Hier mal ein gutes Beispiel.
Analyze IR Remote
Waiting...
Bit stream detected!
28 1
189448 0
12 1
240792 0
4 1
176688 0
12 1
122560 0
164 1
8112 0
152 1
1060 0
148 1
1060 0
148 1
2084 0
152 1
1052 0
156 1
1060 0
148 1
2084 0
152 1
1064 0
144 1
1064 0
148 1
1060 0
148 1
1068 0
136 1
1064 0
152 1
1056 0
156 1
1064 0
136 1
1064 0
140 1
1068 0
136 1
1072 0
144 1
1064 0
148 1
2096 0
144 1
1064 0
140 1
1068 0
144 1
2088 0
144 1
2088 0
152 1
1060 0
140 1
1072 0
140 1
2096 0
140 1
2108 0
136 1
2088 0
148 1
1060 0
148 1
2096 0
140 1
2096 0
140 1
2092 0
148 1
2092 0
144 1
2096 0
148 1
2092 0
148 1
2092 0
144 1
1072 0
136 1
8120 0
144 1
1064 0
140 1
1076 0
136 1
2088 0
148 1
1068 0
136 1
1060 0
148 1
2088 0
144 1
1064 0
140 1
1072 0
148 1
1064 0
148 1
1064 0
140 1
1068 0
128 1
1068 0
140 1
1064 0
148 1
1064 0
144 1
1072 0
136 1
1068 0
136 1
1084 0
132 1
2100 0
128 1
1068 0
140 1
1068 0
136 1
2108 0
132 1
In Excel oder LibreOffice Calc kann man dann die Häufigkeit des Vorkommens ermitteln und daraus die Entscheidungsschwellen für die Erkennung ableiten.
Die HIGH Pegel zwischen den Datenbits sind zwischen 136 und 148us
der Synchronisierungsimpuls ist 8120us
die "0" Datenbits entsprechen 1064us
die "1" Bits entsprechen 2090us (alles ca. Werte)
erni-berni:
Wenn man Glück hat und einen gültigen Datenstrom einfangen kann, sieht das ganz gut aus. Allerdings kommt wie bereits schon gesagt auch viel Müll an.
Ich glaube, ich möchte zur Vorab-Analyse von Wettersensoren lieber etwas, das mir die gültigen Datenströme automatisch einfängt und dabei nur möglichst wenig Datenmüll ausgibt.
Im besten Fall sollen nur die Wettersensoren selbst, eventuell Fragmente von den Wettersensoren aus der Nachbarschaft, die nur bruchstückhaft empfangen werden weil sie eigentlich außer Reichweite sind, und nur ganz wenig Datenmüll empfangen werden.
Und es soll rein mit Arduino funktionieren, ohne Umweg über Soundkarte oder externe Programme.
Mal schauen, was ich mir dazu selbst programmieren kann.
jurs:
Mal schauen, was ich mir dazu selbst programmieren kann.
Super, ich bin sehr gespannt!
erni-berni:
Die HIGH Pegel zwischen den Datenbits sind zwischen 136 und 148us
der Synchronisierungsimpuls ist 8120us
die "0" Datenbits entsprechen 1064us
die "1" Bits entsprechen 2090us (alles ca. Werte)
So, ich habe nun nochmal etwas an den Datentelegrammen verschiedener 433 MHz Sensoren geforscht und mein Vorauswertungsprogramm für Datenpakete zeigt erste Zuckungen.
Meine Sensoren liefern allesamt längere Impulse als Dein Tchibo-Sensor, die Werte liegen mehr bei:
HIGH Pegel zwischen den Bits: 475 us
Startbit/Sync bei ca. 9000 us
die "0" Datenbits entsprechen 2000us
die "1" Bits entsprechen 4000us
Die High-Pegel von "Datenmüll" scheinen sehr oft bei weniger als 50 us zu liegen.
Ich glaube, da werde ich mir mal ein paar plausible Grenzwerte setzen, z.B.:
HIGH Pegel zwischen den Bits: mindestens 50 us oder länger
Startbit mindestens 5000 us oder länger
"0" Datenbits mindestens 500 us oder länger
"1" Bits länger als "0" Bits
Anzahl der Datenbits: 20 oder mehr
Und dann versuchen, was dann noch übrig bleibt an Bits einigermaßen vernünftig aus dem Äther zu fischen und als "Vorauswertung" auszugeben.
Merkwürdigerweise scheine ich verschiedene Sensoren zu haben, die ziemlich ähnliche aber trotzdem verschiedene Protokolle aussenden (identische Bit-Längen und 36-Bit Datenpakete), und trotzdem weiß die zum Sensor gehörende Basisstation, welche 36 Bits zu ihr gehören und zeigt korrekt an. Das müssen die Basisstationen dann wohl anhand von "Stationsnummern" und "Prüfsummen" unterscheiden können, welche Daten für sie bestimmt sind - und welche nicht.
Nachtrag: Ich werde es auch gleich noch kompatibel zur Erkennung von Funktelegrammen machen, die von Fernbedienungen für Funksteckdosen ausgesendet werden. Die Bitfolgen für die Steuerung von Funksteckdosen sind meisten wesentlich kürzer als die von Wettersensoren. Hier getestet mehr bei 20 Bit (Funksteckdose) statt 36 Bit (Funk-Thermometer). Außerdem ist das Startbit für die Funksteckdosen unheimlich lang: 80000 us. Das ist länger als es in einen Integer hineinpasst, da werde ich mir noch etwas einfallen lassen. Und den Sketch dann mal posten.
So ein Mist, jetzt wollte ich meinen Funkanalyes-Sketch für 433MHz-Funkgerätschaften wie handelsübliche Funk-Thermometer und Funk-Steckdosen posten, schreibe noch sehr ausführlichen Text dazu, Anwendung, Funktionsweise, Hintergründe, und dann meldet das Forum beim Posten des vollständig ausgearbeiteten Beitrags einen Fehler: Kompletter Beitrag weg!
Jetzt poste ich einfach nur mal den Code des Sketches.
/*
Sketch zur Vorab-Analyse unbekannter 433-MHZ-Wettersensoren
und Fernbedienungen von 433MHz-Funksteckdosen
Inspiriert durch Beiträge im Arduino-Forum:
http://arduino.cc/forum/index.php/topic,119739.0.html
http://arduino.cc/forum/index.php/topic,136836.0.html
Hardware:
1. Arduino-Board mit 433 MHz Regenerativempfänger für ASK/OOK,
angeschlossen an einem interruptfähigen Pin.
2. Funksensor entweder eines 433 MHz Funkthermometers
oder Funk-Wetterstation oder Steckdosen-Funkfernbedienung
Analysiert werden können Sensoren mit folgendem Funkprotokoll:
- extra langes Startbit (extra langer LOW Pulse am Receiver)
- langes 1-Datenbit (langer LOW Pulse am Receiver)
- kurzes 0-Datenbit (kurzer LOW Pulse am Receiver)
- sehr kurze Trenn-Impulse zwischen den Datenbits (sehr kurze HIGH-Impulse am Receiver)
- 20 bis 50 Datenbits pro Datenpaket
Diese Art Funkprotokoll trifft auf die meisten billigen 433 MHZ
Funkthermometer, Funk-Wetterstationen und Funk-Steckdosen zu.
Ausgabe ueber den seriellen Monitor
Je erkanntem Datenpaket am Receiver wird ausgegeben:
- Länge des Startbits (Mikrosekunden LOW) und des nachfolgenden HIGH-Impulses
- Anzahl der erkannten Datenbits im Datenpaket
- Länge aller erkannten Datenbits (Mikrosekunden LOW)
- Länge der zwischen den Datenbits erkannten Pausen (Mikrosekunden HIGH)
- die als 0/1-Bitstrom decodierten Datenbits des Datenpakets
Nur Vorab-Analyse des Timings im Funkprotokoll!
In einem weiteren Schritt muss dann die Bedeutung der Bits
und die Umsetzung in Messwerte erst noch detalliert decodiert werden,
dieser Sketch erkennt nur das Timing und die Groesse der Datenpakete!
*/
// connect data pin of rx433 module to a pin that can handle hardware interrupts
// with an Arduino UNO this is digital I/O pin 2 or 3 only
#define RX433DATAPIN 2
// hardware interrupt connected to the pin
// with Arduino UNO interrupt-0 belongs to pin-2, interrupt-1 to pin-3
#define RX433INTERRUPT 0
// Set speed of serial in Arduino IDE to the following value
#define SERIALSPEED 115200
// Now make some suggestions about pulse lengths that may be detected
// minimum duration (microseconds) of the start pulse
#define MINSTARTPULSE 4500
// minimum duration (microseconds) of a short bit pulse
#define MINBITPULSE 450
// minimum duration (microseconds) of a HIGH pulse between valid bits
#define MINHITIME 50
// variance between pulses that should have the same duration
#define PULSEVARIANCE 250
// minimum count of data bit pulses following the start pulse
#define MINPULSECOUNT 20
// maximum count of data bit pulses following the start pulse
#define MAXPULSECOUNT 50
// buffer sizes for buffering pulses in the interrupt handler
#define PBSIZE 216
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Start!");
pinMode(RX433DATAPIN, INPUT);
attachInterrupt(RX433INTERRUPT, rx433Handler, CHANGE);
}
volatile unsigned int pulsbuf[PBSIZE]; // ring buffer storing LOW pulse lengths
volatile unsigned int hibuf[PBSIZE]; // ring buffer storing HIGH pulse lengths
unsigned int validpulsbuf[MAXPULSECOUNT]; // linear buffer storing valid LOW pulses
unsigned int validhibuf[MAXPULSECOUNT]; // linear buffer storing valid HIGH pulses
volatile byte pbread,pbwrite; // read and write index into ring buffer
void rx433Handler()
{
static long rx433LineUp, rx433LineDown;
long LowVal, HighVal;
int rx433State = digitalRead(RX433DATAPIN); // current pin state
if (rx433State) // pin is now HIGH
{
rx433LineUp=micros(); // line went HIGH after being LOW at this time
LowVal=rx433LineUp - rx433LineDown; // calculate the LOW pulse time
if (LowVal>MINBITPULSE)
{ // store pulse in ring buffer only if duration is longer than MINBITPULSE
// To be able to store startpulses of more than Maxint duration, we dont't store the actual time,
// but we store MINSTARTPULSE+LowVal/10, be sure to calculate back showing the startpulse length!
if (LowVal>MINSTARTPULSE) LowVal=MINSTARTPULSE+LowVal/10; // we will store this as unsigned int, so do range checking
pulsbuf[pbwrite]=LowVal; // store the LOW pulse length
pbwrite++; // advance write pointer in ringbuffer
if (pbwrite>=PBSIZE) pbwrite=0; // ring buffer is at its end
}
}
else
{
rx433LineDown=micros(); // line went LOW after being HIGH
HighVal=rx433LineDown - rx433LineUp; // calculate the HIGH pulse time
if (HighVal>31999) HighVal=31999; // we will store this as unsigned int
hibuf[pbwrite]=HighVal; // store the HIGH pulse length
}
}
boolean counting;
byte i,counter;
int startBitDurationL,startBitDurationH,shortBitDuration,longBitDuration;
void showBuffer()
// this function will show the results on the serial monitor
// output will be shown if more bits than MINPULSECOUNT have been collected
{
long sum;
int avg;
sum=0;
if (counter>=MINPULSECOUNT)
{ // only show buffer contents if it has enough bits in it
Serial.println();
Serial.print("Start Bit L: "); Serial.print((startBitDurationL-MINSTARTPULSE)*10L);
Serial.print(" H: ");Serial.println(startBitDurationH);
Serial.print("Data Bits: ");Serial.println(counter);
Serial.print("L: ");
for (i=0;i<counter;i++)
{
Serial.print(validpulsbuf[i]);Serial.print(" ");
sum+=validpulsbuf[i];
}
Serial.println();
Serial.print("H: ");
for (i=0;i<counter;i++)
{
Serial.print(validhibuf[i]);Serial.print(" ");
}
Serial.println();
avg=sum/counter; // calculate the average pulse length
// then assume that 0-bits are shorter than avg, 1-bits are longer than avg
for (i=0;i<counter;i++)
{
if (validpulsbuf[i]<avg) Serial.print('0'); else Serial.print('1');
}
Serial.println();
}
counting=false;
counter=0;
}
void loop()
{
long lowtime, hitime;
if (pbread!=pbwrite) // check for data in ring buffer
{
lowtime=pulsbuf[pbread]; // read data from ring buffer
hitime=hibuf[pbread];
cli(); // Interrupts off while changing the read pointer for the ringbuffer
pbread++;
if (pbread>=PBSIZE) pbread=0;
sei(); // Interrupts on again
if (lowtime>MINSTARTPULSE) // we found a valid startbit!
{
if (counting) showBuffer(); // new buffer starts while old is still counting, show it first
startBitDurationL=lowtime;
startBitDurationH=hitime;
counting=true; // then start collecting bits
counter=0; // no data bits yet
}
else if (counting && (counter==0)) // we now see the first data bit
{ // this may be a 0-bit or a 1-bit, so make some assumption about max/min lengths of data bits that will follow
shortBitDuration=lowtime/2;
if (shortBitDuration<MINBITPULSE+PULSEVARIANCE)
shortBitDuration=MINBITPULSE;
else
shortBitDuration-=PULSEVARIANCE;
longBitDuration=lowtime*2+PULSEVARIANCE;
validpulsbuf[counter]=lowtime;
validhibuf[counter]=hitime;
counter++;
}
else if (counting&&(lowtime>shortBitDuration)&&(lowtime<longBitDuration))
{
validpulsbuf[counter]=lowtime;
validhibuf[counter]=hitime;
counter++;
if ((counter==MAXPULSECOUNT) || (hitime<MINHITIME))
{
showBuffer();
}
}
else // Low Pulse is too short
{
if (counting) showBuffer();
counting=false;
counter=0;
}
}
}
Ich habe jetzt keine Lust mehr, da nochmal zwanzig Minuten lang was zu schreiben und dann frisst das Forum den Text auf.
Wer Fragen hat, kann ja fragen.
Feedback erwünscht!
Hallo jurs,
super ! Musste ich natürlich direkt mit meinem Sensor ausprobieren. Hier die ersten Datensequenzen, wie sie auf dem seriellen Monitor ausgegeben werden. Hat auf Anhieb geklappt.
Start!
Start Bit L: 8030 H: 208
Data Bits: 36
L: 1012 1012 2008 2016 2024 2016 1012 2016 1004 1012 1008 1016 1004 1012 1000 1012 1000 2028 996 1016 2020 1008 2016 2020 1008 1012 1012 1004 1020 2012 1012 996 1020 2016 2012 2016
H: 188 180 188 184 184 180 184 184 180 184 184 184 184 180 184 184 184 188 184 180 184 188 184 176 184 180 184 180 180 184 184 184 184 184 180 184
001111010000000001001011000001000111
Start Bit L: 8070 H: 184
Data Bits: 36
L: 1012 996 2016 2028 2012 2028 1020 2016 1020 1020 1020 1020 1016 1020 1016 1012 1008 2024 1012 1012 2036 1020 2016 2012 1020 996 1012 1012 1008 2016 1012 1012 1004 2020 2016 2028
H: 180 184 184 184 180 184 168 172 192 172 168 172 172 172 176 180 184 180 176 180 172 172 172 184 184 184 184 184 184 176 184 184 184 180 180 184
001111010000000001001011000001000111
Start Bit L: 8060 H: 180
Data Bits: 36
L: 1012 1008 2012 2020 2020 2020 1012 2024 1012 1016 1012 1008 1024 1004 1012 1016 1004 2024 1012 1016 2024 1008 2028 2016 1004 1012 1016 1000 1020 2012 1000 1012 1016 2012 2012 2012
H: 184 184 188 184 180 180 184 180 176 176 180 180 172 180 180 180 184 180 176 180 180 184 172 184 184 184 180 180 180 184 184 184 184 188 184 188
001111010000000001001011000001000111
000001000111 Temperatur 7.1
01001011 Feuchte 75%
Die Daten meiner Fernbedienung für Funksteckdosen werden allerdings nicht dekodiert - die Anzeige bleibt leer.
erni-berni:
Die Daten meiner Fernbedienung für Funksteckdosen werden allerdings nicht dekodiert - die Anzeige bleibt leer.
Um Funksteckdosen auszulesen und anzustreuern nutze ich immer RCSwitch (GitHub - sui77/rc-switch: Arduino lib to operate 433/315Mhz devices like power outlet sockets.)
Da kommt dann sowas raus http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
Klappt bis jetzt immer!