Anleitung zum Selbstbau eines Außensensors
Das nachfolgende Arduino Programm simuliert einen Außensensor für eine Wetterstation Lidl H10515 / DCF.
Getestet mit Arduino Nano und ATmega328PU standalone.
Ich bin auch nur ein Laie, meine Variante ist möglicherweise nicht optimal, funktioniert aber bestens.
Mein Sketch kann ganz unten herunter geladen werden.
Für etwaige Fragen stehe ich je nach Möglichkeit zur Verfügung.
ich gebe aber keinerlei Support und verkaufe keine fertigen Außensensoren.
Nachbau auf eigene Gefahr und Kosten.
Allgemein:
Letztendlich empfehle ich den ATmega328PU, da dieser ohne Power-LED und USB daher kommt und somit um einiges stromsparender als ein Arduino ist.
Der standalone ATmega benötigt einen Taktgeber; der Sketch funktioniert nur mit 16 MHz, da das beim original Arduino (Uno) auch so ist.
Der ATmega kann auch 20 MHz, nur geht der Sketch bei einem UNO von 16 MHZ aus. Alles was mit Zeiten zu tun hat funktioniert dann nicht korrekt, bzw. ist zu schnell. Theoretisch könnte auch ein interner Takt verwendet werden, aber in diesem Fall und bei Verwendung eines 20 MHz Quarzes sind Anpassungen in den Fuses nötig. Damit habe ich mich nicht befasst, da ich eine andere Lösung, auch vom Programmieren her, einfacher finde.
Ein Arduino lässt sich direkt programmieren.
Für den ATmega328PU benötigen wir eine Programmiermöglichkeit, das kann ein Arduino als Programmer sein. Zum Programmieren von Bootloader und Sketch gibt es genügend Anleitungen im WWW.
Ich empfehle aber den Arduino Uno in der DIL-Variante und zusätzlich einen Nullkraftsockel zu verwenden, um den ATmel-Prozessor im UNO-Board zu programmieren.
Das Problem ist hier aber immer noch der Bootloader, für den würde immer noch ein 2. Arduino benötigt.
->-> Daher sollte nützlicher Weise der ATmega den Arduino UNO-Bootloader schon drauf haben. <-<-
Ich tausche den Chip aus, programmiere das Arduino UNO Board ganz normal als Arduino Uno und entnehme wieder den Chip.
Das ist einfach praktischer. Ein UNO-Clone kostet nur so um die 6-8€.
Wer auch einen Nullkraftsockel in das Breadboard stecken will sollte sich noch einen Satz stapelbare Buchsenleisten / Stiftleisten für Arduino UNO besorgen.
Der Nullkraftsockel hält im Breadboard nicht, mit aufgesteckten stapelbaren Buchsenleisten steht der Sockel zwar höher, steckt aber schön fest.
Ein Betrieb wäre mit 2x AAA/R3 Batterien möglich, da die Betriebsspannung mindestens 2,8V sein muss.
Ich verwende 3x AA/R6 4CAF50 Industrial Batterien, das hat den Vorteil, das selbst leere Batterien mit nur noch 1V ausreichen.
Ich habe etwas experimentiert und gemessen und bin ausgehend von einer Sendeintervall von ca. alle 5 Minuten / 300 Sekunden beim Stromverbrauch auf folgende Werte gekommen:
Pro Durchlauf:
(4 Sekunden Senden mit ca. 25mA (mit Display und Taste))
4 Sekunden Senden mit ca. 13mA (turnusmäßiges Senden)
296 Sekunden Ruhe mit ca. 0,16mA (nahezu durchgehend Sleepmodus)
Pro Stunde (12 Durchläufe):
48 Sekunden Senden mit ca. 13mA -> (Senden)
0,01333h mit 0,013A = 0,0001733Ah
3552 Sekunden Ruhe mit ca. 0,16mA -> (Sleepmodus)
0,98666h mit 0,00016A = 0,00015787Ah
gesamt
pro Stunde = 0,0003312Ah = 0,33mAh
pro Tag = 0,0079488Ah = 7,95Ah
pro Jahr = 2,901312Ah = 2900Ah
Sprich: Wir kommen mit vernünftigen Batterien locker ein Jahr hin:
* Varta Industrial Pro LR06 / Mignon / AA Alkali Mangan mit 2900mAh -> ca. 365 Tage
* Duracell Procell PC1500 LR6 / Mignon / AA Alkali Mangan mit 3016mAh -> ca. 380 Tage
* Baumarkt Durchschnitt mit 2500 -2600 mAh -> 315 - 330 Tage
* Billigste Variante mit 2000 -2200 mAh -> 250 - 280 Tage
Materialliste:
- 1x Arduino Uno mit ATmega328PU (DIL-Variante)
- 2x Nullkraftsockel
- 1x Satz stapelbare Buchsenleisten / Stiftleisten für Arduino UNO
- 1x ATmega328PU (das U steht für die DIL-Variante) mit Arduino Bootloader.
- 1x 16 MHz Quarz
- 2x 22nF Scheibenkondensator
- 1x Temperatursensor: DS18B20, den gibt es in eine Hülse eingegossen, mit Anschlusskabel, 3-Draht
- 1x Touch-Sensor, als TX-Taste, da dieser auch innerhalb / hinter dem Gehäuse funktioniert und relativ genügsam ist.
- 1x Display, 0,96 Zoll OLED, das wird nur beim Systemstart angeschaltet und wenn die TX-Taste betätigt wird, sonst zum Stromsparen immer aus.
- Etwas Acryl Glas, zum Einkleben in das Gehäuse für das Display
- Ein Gehäuse
- 1x 433 Mhz Sender
- 7 x 3-polige Jumper, Für Kanal, Softadresse und C/F-Umschaltung.
- 1x 4,7KOhm Widerstand für den Temperatursensor, vom Datenanschluss nach 5V
- 1x Batteriehalter
- 1x einstellbarer Widerstand 150 KOhm Als Spannungsteiler für den Messeingang der Batteriespannungsüberwachung
- 1x 10 KOhm für den Reset -Anschluss, zur Not auch direkt an 5V (Nachteil ist mir keiner bekannt)
- Loch-/Streifen-Rasterplatine
Optional:
- 1x LED-Lichtleiter für seitliche LED (45 Grad schräg am Lichteintritt), ca. 10 mm lang, die TX-Taste /der Touch-Sensor hat eine LED auf der Unterseite. Damit wir sehen, das das Berühren des Gehäuses (der Sensor sitzt ja dahinter) von Erfolg war.
Was wir weglassen können:
- Eine Power-LED wird nicht benötigt, wenn das Ding lebt steht eine Temperatur im Display, welches in meiner Variante aus Stromspargründen durch Tastendruck aktiviert wird.
- 1x Taster für Reset, man kann ja alternativ auch die Batterie entnehmen und wieder rein tun.
Hinweise:
Gehäuse:
Ich hab ein Handgehäuse mit Gürtelclip genommen, in den Clip kann schön ein entsprechendes Loch zum Aufhängen bohren und das Gehäuse bleibt heil. Das Gehäuse nicht zu klein wählen!! Der ATmega, der 433MHz Sender und die evtl. DIP-Schalter benötigen echt Platz, ich habe einige Bauteile (Display, TX-Taste) daher auf die Leiterseite gelötet.
Touchsensor:
Es ist wichtig unbedigt ein ganz klein wenig luft zum Gehäuse zu lassen und möglichst keinen Draht oder Kein Kabel direkt an dem Touchsensor vorbei zu führen, das kann zu komischen Fehlern führen, wie das er so tut als wäre er dauerhaft betätigt.
433 MHz Sender:
Ein billiges China, eBay, Amazon... -Teil reicht (die billigen Empfänger sind totaler Schrott, die Sender gehen).
Die Antenne sollte mindestens die passende Spiralantenne oder besser noch ein gerader 17,3 cm langer Draht sein. Sofern der Antennendraht gebogen wird darf dieser auch länger sein; wir sind dann sowieso weit weg von den optimalen Bedingungen. Bei mir ist der Draht gebogen und läuft fast 1x komplett im gesamten inneren Gehäuse herum. Der Sender bekommt nur Spannung, wenn er benötigt wird. Wer Probleme hat: ein PC in der Nähe stört extrem das 433 MHz Signal, dann mal den PC ausknipsen.
3-polige Jumper:
Für Kanal, Softadresse und C/F-Umschaltung
Mehrpolige Jumper haben gegenüber DIP-Schalter den Vorteil, das wir Digitaleingänge ohne Pulldown-Widerstände beschalten können. Letztere beeinflussen nämlich den Ruhestrom unseres Arduino-Systems negativ. Das habe ich ausprobiert / gemessen! Alternativ die gleiche Anzahl Dipschalter, dann sind aber die Pulldowns nötig, bzw. geht auch eine Fest- / Hardverdrahtung.
Einstellbarer Widerstand 150KOhm:
Als Spannungsteiler für den Messeingang der Batteriespannungsüberwachung, Mittelabgriff an Messanschluss
Möglichst 150 KOhm!! Nicht mehr und auch nicht weniger.
Wenn er kleiner ist fließt zu viel Ruhestrom; wir betreiben den Sender mit Batterien, bei einem Netzteil ist das egal, dann sind 50-100 KOhm das Richtige.
Wenn er größer ist stimmen die gemessenen Spannungen nicht mehr bei sich leerenden Batterien, da durch den ATmega auch noch Strom fließt und das den Spannungsteiler negativ beeinflusst.
-> (interne) Referenzspannung 1,1V -> Spannungsteiler bei vollen Batterien auf die 1,1V der Referenzspannung einstellen.
Im Sketch ist die tatsächliche gemessene Spannung der vollen Batterien anzugeben .Ich verwende 3x 1,5V Industrial Batterien, die haben, wenn sie absolut neu sind, 4,8V.
Bei mir passen alternative Widerstände, die ich die noch da hatte, ganz gut bei 4,8V, es ergibt sich zufällig fast genau die Referenzspannung von 1,1V.
1x 33 KOhm - an GND/0V und Messanschluss
1x 110 KOhm - an 5V und Messanschluss
Es folgt nun ein bisschen Theorie:
Manches ist teilweise zusätzlich im Code nochmal wiederholt bzw. genauer kommentiert, was oben schon teilweise stand.
Meine Ermittlung des Sendesignales, da eine brauchbare Bibliothek nicht gefunden wurde, alle Angaben sind in µs.
- Mit Hilfe mehrerer Sender ermittelt, Arduino mit 433 MHz Empfänger als Zeitmesser:
- langer Impuls = Startmarkierung = 8830
- mittlerer Impuls = "1" = 3950
- kurzer Impuls = "0" = 1990
- Pause zwischen den Impulsen = 450
- Mit Hilfe mehrerer Sender und mit Oszi ermittelte Werte:
- langer Impuls = Startmarkierung = 8820 - 8840
- mittlerer Impuls = "1" = 3960 - 3985
- kurzer Impuls = "0" = 1898 - 1925
- Pause zwischen den Impulsen = 500 - 550
- Mit Hilfe der Wetterstation ermittelte (akzeptierte) Werte, mit Arduino und 433 MHz Sender erzeugt:
- langer Impuls = Startmarkierung = 8300 - 10000
- mittlerer Impuls = "1" = 3600 - 5300
- kurzer Impuls = "0" = 1500 - 2900
- Pause zw. den Impulsen = 150 - 1050
Laut Oszi werden die Daten 8x hintereinander 1x als kompletter Satz gesendet, es sind auch immer eine Start- und eine End-Sequenz zu sehen.
Ich mache das etwas anders, da die originalen Sender nicht jedes Mal erkannt werden und es besser werden soll: 3x 8.
Das übermittelte Datenpaket eines Senders, welches wir auch erzeugen müssen:
Dieses besteht aus einer Start-Markierung gefolgt von 36 Bits.
Ein Beispiel der Daten (der 36 Bits):
101111110101111010001000100110010111 = 51370297751 = BF5E88997
Da wir teilweise mit Ganzzahlen rechnen, zum Senden aber binäre Daten benötigen, der Arduino / der ATmel 36 Bit am Stück nicht kann, teilen wir in unserem Sketch das Datenpaket später in 3 Stücke auf:
101111110101 111010001000 100110010111 BF5 E88 997
Das gesamte Datenpaket des Senders besteht aus 9 Nipple:
1011 1111 0101 1110 1000 1000 1001 1001 0111
Die jeweilige Bedeutung ist:
1011 Softadresse (1. Teil), sollte bei mehreren immer abweichen
1111 ebenfalls Softadresse (2. Teil): ..11, und / incl. Kanal: 11.., sollte bei mehreren immer abweichen
Kanal:
(00) am originalen Sender nicht möglich, wird auch von der Wetterstation nicht erkannt
01=1
10=2
11=3
0101 Batterie, steigend, fallend, TX-Taste gedrückt
0 = Batt. OK, 1 = leer
1 = fallend, sonst 0
1 = steigend, sonst 0
0 = normal gesendet, 1= TX-Taste gedrückt (Anmeldesignal??)
1110 1000 1000 = aktuelle Temperatur, muss aber noch "dekodiert" werden:
111010001000 = ist zu invertieren:
000100010111 = Hex: 117, Dez: = 286, das ist unserer Wert
- Werte >= 504 sind negativ (-)
- Werte < 504: Temp = 286/10 = 28,6 Grad Celsius
- Werte >= 504: Temp = (Wert - 4096) / 10 = "-??,? Grad Celsius"
1001 1001 = Hardwareadresse für Lidl
0111 Prüfsumme
Maximale Temperaturwerte der originalen Lidl Wetterstation:
- zwischen -20 und +70 Grad
- Über 70 = HH.H
---> Temperaturen über 204 Grad werden von der Wetterstation auch als negativ interpretiert, das liegt daran, wie der Temp.-Sensor Werte übermittelt
- Unter -20 = LL.L
Was sendet der Außensensor eigentlich für Werte??
In der Theorie Werte zw. 0 und 4096
Wert für + Temperatur: = Temp * 10
Wert für - Temperatur = 4096 + (Temp * 10); Da Temp hier negativ ist, wird Temp daher im Prinzip von 4096 "subtrahiert" dann jeweils noch bitweise invertiert und dann "gesendet"; siehe oben Datenpaket
Als Anmerkung:
Der originale Außensensor ändert seine Softkennung beim Batterien einlegen, das bedeutet, das danach der Sensor neu anzulernen ist.
Das ist mehr wie unpraktisch. Daher habe ich mehrere Eingänge zum dauerhaften Einstellen der Softkennung vorgesehen.
Die Eingänge werden ebenfalls beim Batterien einlegen eingelesen. Danach nicht mehr; erst wieder beim nächsten Batteriewechsel oder einem Reset.
Alle anderen verwendeten Eingänge, wie für den Kanal und Celsius/Fahrenheit können wie beim Original im Betrieb umgestellt werden.
Download des Sketches:
Schaltplan, Bilder:
Schaltplan Der ATmel bei der Arbeit (Senden). Strom im Schnitt so 16-22 mA, für ca. 5 Sekunden. Hierbei ist für den Stromverbrauch auch entscheidend, wie lange der Touchsensor betätigt wird. Ein kurzes Tippen langt. Hier sieht man auch schön den Nullkraftsockel. Im fertigen Sender habe ich aber einen Standardsockel verbaut, der ist kleiner. Die Spiralantenne habe ich im Fertiggerät durch einen mehrfach gebogenen Draht von etwa 25 cm ersetzt. Der ATmel im Sleepmodus. Strom im Schnitt so 160-170 µA, für knapp 5 Minuten. Danach 1x mal kurz Senden und wieder Sleepmodus. Der fertige Außensensor, ich habe 2 davon. Der Touchsensor ist unter dem Gehäuse rechts neben dem Display. Leider habe ich mich beim 1. Sender (Foto) mit dem Lichtleiter verbohrt und den links montieren müssen, daher leuchtet er etwas dunkel, im 2. Sender sitzt er rechts (knapp neben dem Touchsensor). Der Lichtleiter ist nicht zwingend nötig. Da der Sensor aber etwas Zeit zum Aufwecken benötigt (so etwa 1 Sekunde), ist es ganz hilfreich, wenn man sieht, dass das Antippen registriert wurde und gleich etwas passiert. Unten das schwarze Teil ist der Temperatursensor; ich habe die billige Variante (Bauform TO-92) ohne Metallhülse und Anschlusskabel verwendet. |
Code hier einsehen:
/* Dieses Programm simuliert einen Außensensor für eine Wetterstation Lidl H10515 / DCF getestet mit Arduino Nano und ATmega328PU standalone Ich bin auch nur ein Laie, meine Variante ist möglicherweise nicht optimal, funktioniert aber bestens. Allgemein: Letztendlich empfehle ich den ATmega328PU, da dieser ohne Power-LED und USB daher kommt und somit um einiges stromsparender als ein Arduino ist. Der standalone ATmega benötigt einen Taktgeber; der Sketch funktioniert nur mit 16 MHz, da das beim original Arduino (Uno) auch so ist. Der ATmega kann auch 20 MHz, nur geht der Sketch bei einem UNO von 16 MHZ aus. Alles was mit Zeiten zu tun hat funktioniert dann nicht korrekt, bzw. ist zu schnell. Theoretisch könnte auch ein interner Takt verwendet werden, aber in diesem Fall und bei Verwendung eines 20 MHz Quarzes sind Anpassungen in den Fuses nötig. Damit habe ich mich nicht befasst, da ich eine andere Lösung, auch vom Programmieren her, einfacher finde. Ein Arduino lässt sich direkt programmieren. Für den ATmega328PU benötigen wir eine Programmiermöglichkeit, das kann ein Arduino als Programmer sein. Zum Programmieren von Bootloader und Sketch gibt es genügend Anleitungen im WWW. Ich Empfehle aber den Arduino Uno in der DIL-Variante und zusätzlich einen Nullkraftsockel zu verwenden um den ATmel-Prozessor im UNO-Board zu programmieren. Das Problem ist hier aber immer noch der Bootloader, für den würde immer noch ein 2. Arduino benötigt. ->-> Daher sollte nützlicher Weise der ATmega den Arduino UNO-Bootloader schon drauf haben.<-<- Ich tausche den Chip aus, programmiere das Arduino UNO Board ganz normal als Arduino Uno und entnehme wieder den Chip. Das ist einfach praktischer. Ein UNO-Clone kostet nur so um die 6-8€. Wer auch einen Nullkraftsockel in das Breadboard stecken will sollte sich noch einen Satz stapelbare Buchsenleisten / Stiftleisten für Arduino UNO besorgen. Der Nullkraftsockel hält im Breadboard nicht, mit aufgesteckten stapelbaren Buchsenleisten steht der Sockel zwar höher, steckt aber schön fest. Betrieb wäre mit 2x AAA/R3 Batterien möglich, da die Betriebsspannung mindestens 2,8V sein muss. Ich verwende 3x AA/R6 4CAF50 Industrial Batterien, das hat den Vorteil, das selbst leere Batterien mit nur noch 1V ausreichen. Materialliste: - 1x Arduino Uno mit ATmega328PU (DIL-Variante) - 2x Nullkraftsockel - 1x Satz stapelbare Buchsenleisten / Stiftleisten für Arduino UNO - 1x ATmega328PU (das U steht für die DIL-Variante) mit Arduino Bootloader. - 1x 16 MHz Quarz - 2x 22nF Scheibenkondensator - 1x Temperatursensor: DS18B20, den gibt es in eine Hülse eingegossen, mit Anschlusskabel, 3-Draht - 1x Touch-Sensor, als TX-Taste, da dieser auch innerhalb / hinter dem Gehäuse funktioniert und relativ genügsam ist. - 1x Display, 0,96 Zoll OLED, das wird nur beim Systemstart angeschaltet und wenn die TX-Taste betätigt wird, sonst zum Stromsparen immer aus. - Etwas Acryl Glas, zum Einkleben in das Gehäuse für das Display - Ein Gehäuse - 1x 433 Mhz Sender - 7 x 3-polige Jumper, Für Kanal, Softadresse und C/F-Umschaltung. - 1x 4,7 KOhm Widerstand für den Temperatursensor, vom Datenanschluss nach 5V - 1x Batteriehalter - 1x einstellbarer Widerstand 150KOhm Als Spannungsteiler für den Messeingang der Batteriespannungsüberwachung - 1x 10 KOhm für den Reset -Anschluss, zur Not auch direkt an 5V (Nachteil ist mir keiner bekannt) - Loch-/Streifen-Rasterplatine Optional: - 1x LED-Lichtleiter für seitliche LED (45 Grad schräg am Lichteintritt), ca. 10 mm lang, die TX-Taste /der Touch-Sensor hat eine LED auf der Unterseite. Damit wir sehen, das das Berühren des Gehäuses (der Sensor sitzt ja dahinter) von Erfolg war. Was wir weglassen können: - Eine Power-LED wird nicht benötigt, wenn das Ding lebt steht eine Temperatur im Display, welches in meiner Variante aus Stromspargründen durch Tastendruck aktiviert wird. - 1x Taster für Reset, man kann ja alternativ auch die Batterie entnehmen und wieder rein tun. Hinweise: Gehäuse: Ich hab ein Handgehäuse mit Gürtelclip genommen, in den Clip kann schön ein entsprechendes Loch zum Aufhängen bohren und das Gehäuse bleibt heil. Das Gehäuse nicht zu klein wählen!! Der ATmega, der 433MHz Sender und die evtl. DIP-Schalter benötigen echt Platz, ich habe einige Bauteile (Display, TX-Taste) daher auf die Leiterseite gelötet. 433 MHz Sender: Ein billiges China, eBay, Amazon... -Teil reicht (die billigen Empfänger sind totaler Schrott, die Sender gehen). Die Antenne sollte mindestens die passende Spiralantenne oder besser noch ein gerader 17,3 cm langer Draht sein. Sofern der Antennendraht gebogen wird darf dieser auch länger sein; wir sind dann sowieso weit weg von den optimalen Bedingungen. Bei mir ist der Draht gebogen und läuft fast 1x komplett im gesamten inneren Gehäuse herum. Der Sender bekommt nur Spannung, wenn er benötigt wird. Wer Probleme hat: ein PC in der Nähe stört extrem das 433 MHz Signal, dann mal den PC ausknipsen. 3-polige Jumper: Für Kanal, Softadresse und C/F-Umschaltung Mehrpolige Jumper haben gegenüber DIP-Schalter den Vorteil, das wir Digitaleingänge ohne Pulldown-Widerstände beschalten können. Letztere beeinflussen nämlich den Ruhestrom unseres Arduino-Systems negativ. Das habe ich ausprobiert / gemessen! Alternativ die gleiche Anzahl Dipschalter, dann sind aber die Pulldowns nötig, bzw. geht auch eine Fest- / Hardverdrahtung. Einstellbarer Widerstand 150KOhm: Als Spannungsteiler für den Messeingang der Batteriespannungsüberwachung, Mittelabgriff an Messanschluss Möglichst 150 KOhm!! Nicht mehr und auch nicht weniger. Wenn er kleiner ist fließt zu viel Ruhestrom; wir betreiben den Sender mit Batterien, bei einem Netzteil ist das egal, dann sind 50-100 KOhm das Richtige. Wenn er größer ist stimmen die gemessenen Spannungen nicht mehr bei sich leerenden Batterien, da durch den ATmega auch noch Strom fließt und das den Spannungsteiler negativ beeinflusst. -> (interne) Referenzspannung 1,1V -> Spannungsteiler bei vollen Batterien auf die 1,1V der Referenzspannung einstellen. Im Sketch ist die tatsächliche gemessene Spannung der vollen Batterien anzugeben .Ich verwende 3x 1,5V Industrial Batterien, die haben, wenn sie neu sind, 4,8V Bei mir passen alternative Widerstände, die ich die noch da hatte, ganz gut bei 4,8V, es ergibt sich zufällig fast genau die Referenzspannung von 1,1V. 1x 33 KOhm - an GND/0V und Messanschluss 1x 110 KOhm - an 5V und Messanschluss Es folgt nun ein bisschen Theorie: Manches ist teilweise zusätzlich im Code nochmal wiederholt bzw. genauer kommentiert, was oben schon teilweise stand. Meine Ermittlung des Sendesignales, da eine brauchbare Bibliothek nicht gefunden wurde, alle Angaben sind in µs. - Mit Hilfe mehrerer Sender ermittelt, Arduino mit 433 MHz Empfänger als Zeitmesser: langer Impuls = Startmarkierung = 8830 mittlerer Impuls = "1" = 3950 kurzer Impuls = "0" = 1990 Pause zwischen den Impulsen = 450 - mit Hilfe mehrerer Sender und mit Oszi ermittelte Werte: langer Impuls = Startmarkierung = 8820 - 8840 mittlerer Impuls = "1" = 3960 - 3985 kurzer Impuls = "0" = 1898 - 1925 Pause zwischen den Impulsen = 500 - 550 - mit Hilfe der Wetterstation ermittelte (akzeptierte) Werte, mit Arduino und 433 MHz Sender erzeugt: langer Impuls = Startmarkierung = 8300 - 10000 mittlerer Impuls = "1" = 3600 - 5300 kurzer Impuls = "0" = 1500 - 2900 Pause zw. den Impulsen = 150 - 1050 Laut Oszi werden die Daten 8x hintereinander 1x als kompletter Satz gesendet, es sind auch immer eine Start- und eine End-Sequenz zu sehen. Ich mache das etwas anders, da die originalen Sender nicht jedes Mal erkannt werden und es besser werden soll: 3x 8. Das übermittelte Datenpaket eines Senders, welches wir auch erzeugen müssen: Dieses besteht aus einer Start-Markierung gefolgt von 36 Bits. Ein Beispiel der Daten (der 36 Bits): 101111110101111010001000100110010111 = 51370297751 = BF5E88997 Da wir teilweise mit Ganzzahlen rechnen, zum Senden aber binäre Daten benötigen, der Arduino / der ATmel 36 Bit am Stück nicht kann, teilen wir in unserem Sketch das Datenpaket später in 3 Stücke auf: 101111110101 111010001000 100110010111 BF5 E88 997 Das gesamte Datenpaket des Senders besteht aus 9 Nipple: 1011 1111 0101 1110 1000 1000 1001 1001 0111 Die jeweilige Bedeutung ist: 1011 Softadresse (1. Teil), sollte bei mehreren immer abweichen 1111 ebenfalls Softadresse (2. Teil): ..11, und / incl. Kanal: 11.., sollte bei mehreren immer abweichen Kanal: (00) am originalen Sender nicht möglich, wird auch von der Wetterstation nicht erkannt 01=1 10=2 11=3 0101 Batterie, steigend, fallend, TX-Taste gedrückt 0 = Batt. OK, 1 = leer 1 = fallend, sonst 0 1 = steigend, sonst 0 0 = normal gesendet, 1= TX-Taste gedrückt (Anmeldesignal??) 1110 1000 1000 = aktuelle Temperatur, muss aber noch "dekodiert" werden: 111010001000 = ist zu invertieren: 000100010111 = Hex: 117, Dez: = 286, das ist unserer Wert - Werte >= 504 sind negativ (-) - Werte < 504: Temp = 286/10 = 28,6 Grad Celsius - Werte >= 504: Temp = (Wert - 4096) / 10 = "-??,? Grad Celsius" 1001 1001 = Hardwareadresse für Lidl 0111 Prüfsumme Maximale Temperaturwerte der originalen Lidl Wetterstation zwischen -20 und +70 Grad Über 70 = HH.H ---> Temperaturen über 204 Grad werden von der Wetterstation auch als negativ interpretiert, das liegt daran, wie der Temp.-Sensor Werte übermittelt Unter -20 = LL.L Was sendet der Außensensor eigentlich für Werte?? In der Theorie Werte zw. 0 und 4096 Wert für + Temperatur: = Temp * 10 Wert für - Temperatur = 4096 + (Temp * 10); Da Temp hier negativ ist, wird Temp daher im Prinzip von 4096 "subtrahiert" dann jeweils noch bitweise invertiert und dann "gesendet"; siehe oben Datenpaket Als Anmerkung: Der originale Außensensor ändert seine Softkennung beim Batterien einlegen, das bedeutet, das danach der Sensor neu anzulernen ist. Das ist mehr wie unpraktisch. Daher habe ich mehrere Eingänge zum dauerhaften Einstellen der Softkennung vorgesehen. Die Eingänge werden ebenfalls beim Batterien einlegen eingelesen. Danach nicht mehr; erst wieder beim nächsten Batteriewechsel oder einem Reset. Alle anderen verwendeten Eingange, wie für den Kanal und Celsius/Fahrenheit können wie beim Original im Betrieb umgestellt werden. Genug der Theorie, jetzt geht es los... */ //Für Energiesparmodus des Arduino, damit die Batterien nicht nach 3 Tagen alle sind, sondern etwa 1 Jahr halten. //Wir schicken den Arduino schlafen und lassen ihn nach spätestens 8 Sekunden vom Watchdog reaktivieren. #include "LowPower.h" //TX-Taste, diese muss in der Lage sein den Arduino aus dem Energiesparmodus aufzuwecken, //wir wollen ja nicht warten bis der Watchdog das tut. Daher hängen wir die Taste an einen Interrupt-Eingang. #define IntTX 2 //Pin 2 ist INT0 String TX_Taste = "0"; // Wenn TX-Button aktiv = 1 //Temp.Sensor DS18B20 #include "OneWire.h" #define TempPin 3 // Daten-Pin des Temperatursensors OneWire DS18B20(TempPin); byte address[8]; //Variablen für den Batteriezustand double Volt_bat; //ermittelte Batteriespannung String Batt_Low; //Batteriestatus an sich double Batt_Spann; //tatsächliche Versorgungsspannung //Symbole für das Display brauchen wir auch const unsigned char batt_OK [] PROGMEM = {0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const unsigned char batt_LOW [] PROGMEM = {0x3c, 0xc3, 0x81, 0x81, 0x81, 0xff, 0xff}; const unsigned char Temp_UP [] PROGMEM = {0x18, 0x24, 0xc3, 0x24, 0x24, 0x24, 0x3c}; const unsigned char Temp_Down [] PROGMEM = {0x3c, 0x24, 0x24, 0x24, 0xc3, 0x24, 0x18}; byte soft1_temp; // für SoftKennung1, berechnet nur bei Neustart, bei Bedarf als Zuffallzahl oder "DIP-Codierung" byte soft2_temp; // für SoftKennung2, berechnet nur bei Neustart, bei Bedarf als Zuffallzahl oder "3" float temp; // ermittelte aktuelle Temperatur float temp_alt = 999; // Temp. aus der vorangegangenen Messung für Trend byte temp_trend = 0; // Temperaturtrend ergibt sich aus mehreren Temp. Messungen //Es eignen sich nicht alle Eingänge als Digitaleinge, teilweise haben einige relativ hohe Ruheströme. //Alle verwendeten Eingänge sind zwingend auf ein definiertes Potential zu legen! Mindestens auf LOW!! //Diese verwende ich: #define C_F A0 // 1x 3-pol Jumper Celsius/Fahrenheit, low = Celsius, high = Farenheit #define Kanal1 5 // 2x 3-pol Jumper für Kanaleinstellung #define Kanal2 6 // 00 = 1; Kanal 1 damit Kanal 0 nicht vorkommt // 01 oder 10 = 2; nur ein DIP auf ON bzw. ein Eingang high, welcher ist egal // 11 = 3; String Kanal; // Kanal als String, wird für Datenpaket und Display benötigt #define Dip1 7 // 4x 3-pol Jumper für Softkennung1, die Softkennung2 legen wir einfach fest. #define Dip2 8 // alles LOW bzw. alles "0000" -> Zufallsadressierung wie beim Original-Außensender #define Dip3 9 // meine haben Softadresse 4 = 0010 #define Dip4 10 #define sendpin 11 // Daten-Pin des RF 433Mhz Senders #define Vpin 12 // abschaltbarer 5V-Pin des 433Mhz Senders, da dieser keinen Energiesparmodus hat //Letztendlich zu sendene Variablen // Da wir nicht jedes Byte einzeln im Code stehen lassen wollen senden wir mit der Schleife: sendserial byteweise. // Und, da der Arduino binär nur max. 12 Byte kann (bzw. max. FFF) wir aber 36 am Stück senden wollen, müssen wir die Daten in 3 Stücke aufteilen: int Data1 = 0; // = Softadresse incl. Kanal, Batt_Low, Steigend, Fallend, TX_Taste int Data2 = 0; // = Temp_Send int Data3 = 0; // = Hard_Sensor1 + Hard_Sensor2 + ChkSum // Data2 muss zuerst ermittelt werden, da wir die Temp. für den Temperaturtrend vorher wissen müssen //Sendeintervall in Sekunden int count = 0; //Zum Zeitzählen benötigt, hängt mit dem Aufwecken durch den Watchdog oder "TX-Taste" zusammen int timedelay = 300; //Sendeintervall in Sekunden, oder auch Verzögerung bis zum nächsten automatischen Senden //OLED (Display) #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); int Adresse = (0x78 >> 1); // Adresse (wie sie an Display steht um 1 Bit "geshiftet" = 0x3C; mein Display kann auch (0x7A >> 1) = 0x3D void setup() { Batt_Spann = 4.8; // in Volt, sollte halbwegs den Tatsachen entsprechen (in meinem Fall 3x R6/AA Industrial) analogReference(INTERNAL); // Referenzspannung zum Batterie-Überwachen, am Atmega328P 1,1V der entsprechende Pin darf NICHT belegt werden!! (z.B. mit 5V) // Wir benötigen eine stabile Referenz, sonst kommt Mist beim Batteriemessen raus // Das bedeutet auch, wir benötigen einen Spannungsteiler am entsprechenden Analogeingang, damit die gemessene Spannung nicht höher als die Referenz ist // Bei vollen Batterien sollte exakt die Referenzspannung am Spannungsteiler heraus kommen //meine Variante: "0V" - 33KOhm - "Messpunkt" - 110KOhm - "Betriebsspannung" // damit kommt bei vollen Batterien (4,8V) ein Wert am Messeingang an, der fast der Referenzspannung entspricht //Mit sinkender Spannung sinkt die Genauigkeit der Anzeige entsprechend der Ungenauigkeit der Widerstände des Spannungsteilers // da aber unter 3 Volt der Atmega eher unwillig ist, spielt eine etwaige Ungenauigkeit keine große Rolle // (Eine korrekte Formel für den Sketch ist mir nicht eingefallen...) Serial.begin(115200); // interesanterweise geht es nicht ohne, wenn ein echter Arduino und kein Atmega328 Stand alone verwendet wird, // da die Sende- und Empfangs-LEDs sonst leuchten und somit unnötig Strom fressen //Setup der Pins pinMode(C_F, INPUT); pinMode(IntTX, INPUT); pinMode(Kanal1, INPUT); pinMode(Kanal2, INPUT); pinMode(Dip1, INPUT); pinMode(Dip2, INPUT); pinMode(Dip3, INPUT); pinMode(Dip4, INPUT); pinMode(Vpin, OUTPUT); digitalWrite(Vpin, HIGH); //Nicht sofort nötige Ausgänge auf Input und Low setzen; zum Stromsparen digitalWrite(IntTX, LOW); digitalWrite(sendpin, LOW); pinMode(sendpin, INPUT); //OLED (Display) display.begin(SSD1306_SWITCHCAPVCC, Adresse); //"Hallo" sagen display.clearDisplay(); display.display();; delay(50); display.clearDisplay(); display.setTextColor(WHITE); display.invertDisplay(false); display.setTextSize(1); display.setCursor(0, 0); display.print("Systemstart:"); display.display(); // Den verwendeten Temperatursensor suchen und Ergebnis im Display anzeigen lookUpSensor(); // Der Orginalsender legt beim Start automatisch eine neue Softkennung an, das gefällt uns nicht. // Hier wird überprüft o evtl. DIP-Schalter btw. eine Festverdrahtung vorhanden und codiert sind, dann werden diese üernommen, anderenfalls dann Zufallskennung. //mit DIP-Switch für Softkennung if (digitalRead(Dip1) == HIGH || digitalRead(Dip2) == HIGH || digitalRead(Dip3) == HIGH || digitalRead(Dip4) == HIGH) { //mit DIP-Switch String soft, soft1, soft2, soft3, soft4; if (digitalRead(Dip1) == HIGH) {soft1 = "1";} else {soft1 = "0";} if (digitalRead(Dip2) == HIGH) { soft2 = "1";} else {soft2 = "0";} if (digitalRead(Dip3) == HIGH) {soft3 = "1";} else {soft3 = "0";} if (digitalRead(Dip4) == HIGH) {soft4 = "1";} else {soft4 = "0";} soft = soft1 + soft2 + soft3 + soft4; soft1_temp = StrToInt(soft, 4); //Eine echte Zahl daraus machen, ist bis jetzt String, der binär nur darstellt soft2_temp = 3; //Die 2. Softkennung legen wir nur fest } else { //ohne DIP-Switch, oder alle Eingänge = "LOW" = Verhalten wie am Original simulieren randomSeed(analogRead(0)); //startet Zufallsgenerator auf einen unbenutzten Eingang, (dieser "flattert", dadurch bekommen wir beinahe eine "echte" Zufallszahl) while (soft1_temp == 0) //Dauerschleife , solage die Zufallszahl 0 ist {soft1_temp = random(16);} //Zufallszahl zwischen 0 und 15 while (soft2_temp == 0) //Dauerschleife , solage die Zufallszahl 0 ist {soft2_temp = random (4);} //Zufallszahl zwischen 0 und 3 // das ergibt später binär (Softkennung 1 (XXXX) + Kanal (XX) + Softkenung 2 (XX)) eine // 8-stellige binäre Gesamt-Softkennung 0001 + 01 +01 == 00010101 (mindestens 00010101, da kein Teil 0 sein soll; bis max. 11111111) } //zu Beginn 1x senden, das mit "TX-Taste" //(Die Wetterstation benötigt kein Anmeldesignal, wir schicken es aber trotzdem, //da das der orginale Sender zumintest auch beim Drücken der TX-Taste macht) TX_Taste = "1"; Run_TX(); TX_Taste = "0"; //Wenn Pin 2 (INT 0) auf 5V geht(HIGH), sprich unsere TX-Taste betätigt wird, Interrupt-Routine aufrufen attachInterrupt(0, interruptRoutine, RISING); } void interruptRoutine() //Aufwecken des Arduino durch TX-Taste { if (TX_Taste == "0") //Falls Taste noch nicht gedrückt wurde, tut wir was... { TX_Taste = "1"; // Variable für Taste auf gedrückt setzten, um Mehrfachaufruf zu verhindern, brauchen wir auch für das Anschalten des Displays count = 0; // Zähler für die Verzögerung des automatischen Sendens der Temperatur auf 0 setzen Run_TX(); // Temp. senden anstoßen if (digitalRead(2) == LOW); // falls Taste nicht mehr gedrückt {TX_Taste = "0";} // Variable für Taste zurücksetzen } } void loop() { //Der Loop macht meistens fast nichts, außer den Arduino in den Sleepmode zu schicken. Da der Watchdog den Arduino nach max. 8 Sekunden reaktiviert, //wird geschaut, ob die Zeit bis zum nächsten automatischen Senden schon erreicht ist: wenn nein -> wieder Ruhemodus für 8 Sekunden; wenn ja: -> Senden. //Da wir zählen wie oft der Arduino aufgeweckt wurde, benötigen wir ein Verhältnis zur eingestellten Verzögerungszeit zwischen den automatischen Sendungen, //daher teilen wir die Verzögerungszeit genau duch die "Sleep-Zeit". un unserem Fall 8 Sekunden (wegen "SLEEP_8S" im "LowPower.powerDown"-Aufruf) while (count < (timedelay / 8)) // Verzögerung zwischen dem automatischen Senden abwarten { //StandBy, Aufwachen nach 8 Sekunden durch Watchdog; zum Schauen, ob die Verzögerungszeit um ist //wenn nicht Zähler um 1 erhohen count++; LowPower.powerDown(SLEEP_8S, ADC_ON, BOD_OFF); } //Wenn Zeit um ist: noInterrupts(); //Interrupts unterdrücken TX_Taste = "0"; //keine TX-Taste count = 0; //Zähler zurücksetzen Run_TX(); //Temp ermitteln und Senden interrupts(); //Interrupts wieder erlauben } void Run_TX() { //Unsere drei Teile der Daten zum Senden, wir erzeugen diese in den entsprechenden Unterroutinen Data2 = data_2(); // enthält Themperatur, muss zuerst berechnet werden, da wir die Temp. auch für den Trend in Data1 benötigen Data1 = data_1(); // enthält Soft-Kennung und Sensorstatus Data3 = data_3(); // enthält Hard-Kennung und Prüfsumme if (TX_Taste == "1") //falls Taste gedrückt wurde {anzeige();} // Display anknipsen
//Anknipsen der momentan inaktiven aber benötigten Ausgänge pinMode(sendpin, OUTPUT); pinMode(Vpin, OUTPUT); digitalWrite(Vpin, HIGH); //Die Daten werden 24x (3 Sequenzen, zu jeweils 8 Datesätzen) wiederholt gesendet (orginal ist es 1x8) for (int l = 0; l < 3; l++) // 3x wiederholt die gesamte Datensequenz { // Startsequenz digitalWrite(sendpin, HIGH); delayMicroseconds(100); digitalWrite(sendpin, LOW); delayMicroseconds(200); digitalWrite(sendpin, HIGH); delayMicroseconds(2000); for (int k = 0; k < 8; k++) // Die eigrentlichen Daten (8x wiederholt) { starter(); // Senden des Startimpulses sendserial(Data1, 11); // Aufruf einer Hilfsroutine zum Senden der eigentlichen Daten sendserial(Data2, 11); //geschickt werden kann alles, was irgendwie wie eine Zahl ausschaut sendserial(Data3, 11); //tatsächlich senden wir natürlich immer binär, insgesamt 12 bit (bit 0 - bit 11) } //Endsequenz digitalWrite(sendpin, LOW); delayMicroseconds(62500); digitalWrite(sendpin, HIGH); delayMicroseconds(200); } //alles ausknipsen display.clearDisplay(); display.display(); display.ssd1306_command(SSD1306_DISPLAYOFF); display.display(); digitalWrite(sendpin, LOW); digitalWrite(Vpin, LOW); pinMode(sendpin, INPUT); pinMode(Vpin, INPUT); } void anzeige() { display.ssd1306_command(SSD1306_DISPLAYON); display.clearDisplay(); display.setTextSize(2); display.setCursor(16, 0); if (digitalRead(C_F) == LOW) { if (temp >= 0) { display.print(" "); if (temp < 10) { display.print(" "); } } else { if (temp > -10) { display.print(" "); } } display.print(temp, 1); display.setTextSize(1); display.setCursor(79, -2); display.print("o"); display.setTextSize(2); display.setCursor(88, 0); display.print("C"); } else { temp = ((temp * 9 / 5) + 32); if (temp >= 0) { display.print(" "); if (temp < 10) { display.print(" "); } } else { if (temp > -10) { display.print(" "); } } display.print(temp, 1); display.setTextSize(1); display.setCursor(79, -2); display.print("o"); display.setTextSize(2); display.setCursor(88, 0); display.print("F"); } display.setTextSize(1); if (temp_trend == 2) { display.drawBitmap(108, 0, Temp_UP, 8, 7, WHITE); } if (temp_trend == 1) { display.drawBitmap(108, 7, Temp_Down, 8, 7, WHITE); } if (Batt_Low == "0") { display.drawBitmap(0, 24, batt_OK, 8, 7, WHITE); } else { display.drawBitmap( 0, 24, batt_LOW, 8, 7, WHITE); } display.setTextSize(1); display.setCursor(13, 24); display.print(Volt_bat, 1); display.print("V"); //Kanal display.setTextSize(1); display.setCursor(98, 25); display.print("Ch."); display.setCursor(118, 25); if (Kanal == "01") { display.print("1"); } if (Kanal == "10") { display.print("2"); } if (Kanal == "11") { display.print("3"); } display.display(); } void sendserial(long data, int bytecount) // Hilfroutine für das bitweise Senden der "Nullen" und "Einsen" { for (int j = bytecount; j >= 0; j--) { if (data & (1 << j)) { one(); // Senden eines "1" - Impulses } else { zero(); // Senden eines "0" - Impulses } } } // Impulsmodell der Datenpakete // beginn = 8800, Startmarkierung 8300 - 10000 // 1 = 4000, 3600 - 5300 // 0 = 2000; 1500 - 2900 // Pause = 500; Impulspause 150 - 1050 void starter () { digitalWrite(sendpin, LOW); delayMicroseconds(8000); digitalWrite(sendpin, HIGH); delayMicroseconds(500); } void one () //1 { digitalWrite(sendpin, LOW); delayMicroseconds(4000); digitalWrite(sendpin, HIGH); delayMicroseconds(500); } void zero () //0 { digitalWrite(sendpin, LOW); delayMicroseconds(2000); digitalWrite(sendpin, HIGH); delayMicroseconds(500); } int data_1() { String Soft_Sensor1; String Soft_Sensor2; // SoftKennung2, Softteil wird nur bei Neustart String Status; //Batt, steigend, fallend, TX-Button 4 Byte = Nipple3 //1.Nipple = Soft_Sensor1 als String Soft_Sensor1 = String(soft1_temp, BIN); // Nullen auffüllen int len_ss1 = Soft_Sensor1.length(); //Nullen Anfügen for (int j = len_ss1; j < 4; j++) { Soft_Sensor1 = "0" + Soft_Sensor1; } //2.Nipple = Soft_Sensor2 als String //1. Teil, der Kanal if (digitalRead(Kanal1) == LOW & digitalRead(Kanal2) == LOW) { Kanal = "01"; // 1 } if ((digitalRead(Kanal1) == HIGH & digitalRead(Kanal2) == LOW) || (digitalRead(Kanal1) == LOW & digitalRead(Kanal2) == HIGH)) { Kanal = "10"; // 2 } if (digitalRead(Kanal1) == HIGH & digitalRead(Kanal2) == HIGH) { Kanal = "11"; // 3 } //2. Teil, Soft-Kennung String soft2 = String(soft2_temp, BIN); // Nullen auffüllen soft2 = Strlen(soft2, 2); //Zusammenführen Soft_Sensor2 = Kanal + soft2; //3.Nipple = Status //3.1 Batterie int BattPin = A1; pinMode(BattPin, INPUT); // Pin zum Batterie messen String Steigend = "0"; // Wenn Temp. steigt = 1, 1 Byte String Fallend = "0"; // Wenn Temp. steigt = 1, 1 Byte double mess_bat = (analogRead(BattPin)) * 1.0; Volt_bat = (mess_bat / 1023.0) * Batt_Spann; if (Volt_bat < 3.9) { Batt_Low = "1"; } else { Batt_Low = "0"; } //3.2 Steigend, 3.3 Fallend // Es darf nur ein Steigend oder Fallend zutreffen, beides = "1" wird von der Wetterstation nicht akzeptiert if (temp_trend == 2) { Fallend = "0"; // Wenn Temp. steigt = 1 Steigend = "1"; // Wenn Temp. steigt = 1 } if (temp_trend == 1) { Fallend = "1"; // Wenn Temp. steigt = 1 Steigend = "0"; // Wenn Temp. steigt = 1 } if (temp_trend == 0) { Fallend = "0"; // Wenn Temp. steigt = 1 Steigend = "0"; // Wenn Temp. steigt = 1 } //3.3 TX_Taste //Wird am Anfang im LOOP abgefragt //Zusammenführen Status = Batt_Low + Fallend + Steigend + TX_Taste; String Data1_Temp = Soft_Sensor1 + Soft_Sensor2 + Status; //Eine echte Zahl daraus machen, is ja String der binär darstellt int Data1 = StrToInt(Data1_Temp, 12); return Data1; } int data_2() { int Temp_Send; // zurückgegebener Wert int temp_val; // * für weitere Verarbeitung Temp. *10) //4./5./6.Nipple = Temp_Send als integer, kann so Data2 zugewiesen werden // Sensor Abfrage //Temperatur auslesen und ausgeben temp = getTemperature(); //Trend Festlegen if (temp_alt == 999 || temp_alt == temp) { temp_trend = 0; } else { if (temp_alt < temp) { temp_trend = 2; } if (temp_alt > temp) { temp_trend = 1; } } temp_alt = temp; if (temp >= 0) //Wenn >= 0 Grad // if (temp >= 0) { temp_val = temp * 10; } else //Wenn < 0 Grad { temp_val = 4096 + (temp * 10); } //Daten zum Senden erzeugen // nach String, über BIN, damit "Nullen" angefügt werden können und wir eine feste Länge haben String temp_bin_str = String(temp_val, BIN); // Nullen auffüllen temp_bin_str = Strlen(temp_bin_str, 12); //Invertieren und gleich nach integer Temp_Send = Strrev (temp_bin_str, 1, 12); //anknipsen return Temp_Send; } int data_3() { // Checksumme (Nipple 9) aus allen anderen Nipples berechnen //Nipple 1-3 extrahiert aus Data1, invertiert //Nipple 4-6 extrahiert aus Data2, invertiert //Nipple 7 und 8 , sind sind für Lidl jeweils = 9 und damit binär = 1001 , müssen nicht invertiert werden // Data1 als binärer String mit Nullen aufgefüllt String data_1 = Strlen((String(Data1, 2)), 12); // Data1 als binärer String mit Nullen aufgefüllt String data_2 = Strlen((String(Data2, 2)), 12); String nip_7_8 = "1001"; // Für Datenpaket // Daten für Quersumme ermitteln byte nip1 = Strrev (String(data_1), 1, 4); byte nip2 = Strrev (String(data_1), 5, 8); byte nip3 = Strrev (String(data_1), 9, 12); byte nip4 = Strrev (String(data_2), 1, 4); byte nip5 = Strrev (String(data_2), 5, 8); byte nip6 = Strrev (String(data_2), 9, 12); byte nip7 = 9; byte nip8 = 9; //Quersumme int quer = (nip1 + nip2 + nip3 + nip4 + nip5 + nip6 + nip7 + nip8); //Prüffsumme int chk = (quer & 15) ^ 15; //Nipple 9 berechnen // Aus Quersumme als mit Nullen aufgefüllenter String String nip_s = Strlen((String(chk, 2)), 4); // invertieren und als Integer int nip_i = Strrev(nip_s, 1 , 4); // als mit Nullen aufgefüllenter binärer String String nip9 = Strlen((String(nip_i, 2)), 4); // data3 als String erzeugen String data3_Str = (nip_7_8 + nip_7_8 + nip9); // nach Integer konvertierendata3_Str int data3_Int = StrToInt(data3_Str, 12); return data3_Int; } int Strrev (String strg, int bytestart, int byteend) { //String invertieren, das tolle ist, es kommt gleih eine Zahl raus int Data = 0; for (int i = (bytestart - 1); i < (byteend); i++) { // Byteweise als integer in "Data" packen if (strg[i] == '1') { bitSet(Data, ((1 - bytestart) + i)); } } return Data; } String Strlen(String daten, int Length) { //Stringlänge korrigieren int len_daten = daten.length(); //Nullen Anfügen for (int j = len_daten; j < Length; j++) { daten = "0" + daten; } return daten; } int StrToInt(String daten, int Length) { //Eine echte Zahl daraus machen, is ja String der binär darstellt int Integer = 0; for (int i = (Length - 1); i > (-1); i--) { // Byteweise als integer in "Integer" =Ergebniss packen if (daten[i] == '1') { bitSet(Integer, ((Length - 1) - i)); } } return Integer; } void lookUpSensor() { // DS18x20-Sensoren suchen, Adresse ausgeben DS18B20.search(address); { bool detect = false; switch (address[0]) { case 0x10: detect = true; break; case 0x28: detect = true; break; case 0x22: detect = true; break; } detect = false; switch (address[0]) { case 0x28: detect = true; break; } // Anzeigen, wenn ein Temperatursensor gefunden wurde display.setCursor(0, 8); if (detect) { display.print("Sensor gefunden."); } else { display.print("Sensor-Fehler!"); } display.display(); } } float getTemperature() { // Temperaturwert des Sensors auslesen byte data[12]; int16_t raw; byte i; bool type_s; DS18B20.reset(); DS18B20.select(address); DS18B20.write(0x44, 1); // Start Messung, parasitaere Versorgung an delay(1000); // eventuell reichen auch 750 ms DS18B20.reset(); DS18B20.select(address); DS18B20.write(0xBE); // Read Scratchpad for ( i = 0; i < 9; i++) { data[i] = DS18B20.read(); } raw = (data[1] << 8) | data[0]; byte cfg = (data[4] & 0x60); // Aufloesung bestimmen, bei niedrigerer Aufloesung sind // die niederwertigen Bits undefiniert -> auf 0 setzen if (cfg == 0x00) raw = raw & ~7; // 9 Bit Aufloesung, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 Bit Aufloesung, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 Bit Aufloesung, 375.0 ms // Default ist 12 Bit Aufloesung, 750 ms Wandlungszeit return ((float)raw / 16.0); } |