Dies ist eine kostenlose Homepage erstellt mit hPage.com.




   

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:

Lidl_Aussensensor.zip


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);

}

Nach oben

Dies ist eine kostenlose Homepage erstellt mit hPage.com.