Das Hygrometer

Mainboard Unterseite Mainboard Unterseite

Dieses Hygrometer ist zusätzlich auch noch ein Hygrostat, d.h. es besitzt neben der Anzeige für die aktuelle relative Luftfeuchte auch noch einen Schaltausgang (P-FET mit open Drain). Die Messwerte werden mit Hilfe eines ESP8266-Controllers über WLAN und php-Scripte in eine MySQL Datenbank gespeichert. Der ESP8266-Controller ist hier auf einem ESP12F (kompatibel mit ESP12E) Modul untergebracht. Dieses Modul enthält den 32Bit Controller mit 80MHz!!! und eine integrierte WLAN-Hardware. Zusätzlich ist ein 4MByte großer Flash-Speicher im Modul enthalten. Mit dem Arduino-SDE und dem entsprechendem Plugin kommt man schnell zu vorzeigbaren Ergebnissen. Dazu kommt ein unglaublich geringer Preis für dieses Modul. Die Firmware für den ESP8266 wurde nicht von mir geschrieben, sondern stammt aus einem anderen Gemeinschaftsprojekt. Bei dem Projekt waren lediglich die Hardware, die php-scripte, die MySQL Anbindung und die graphische Darstellung der Datenbankinhalte mein Part.
Hier (noch in html 4.01) ist ein Blick auf die Messwerte möglich.


Die Messwerte werden wiederum mittels php-Scripten aus der Datenbank extrahiert und über ein sehr schönes JavaScript-Tool graphisch aufgearbeitet. Das Tool heißt "HighCharts" und ist leicht über bekannte Suchmaschinen zu finden. Über das Beispielpack kommt man schnell hinter die Logik, wie die Messwerte bereitzustellen sind.


Schaltpläne

Netzteil

Der Schaltplan unten zeigt das Netzteil für den Controller, den Feuchtesensor AM2302 (auch bekannt unter DHT22) und die beiden Displays.
Schaltplan Netzteil


Encoder

Der Encoder dient zur Menüsteuerung. folgende Einstellungen sind veränderbar:
  • die Schaltschwelle
  • die Hysterese
  • die Displayhelligkeit
  • Interval für die Datenübertragung zur Datenbank
  • Die Kondensatoren sollen zusammen mit den im Controller programmierten Pullups schon etwas entprellend wirken.
    Schaltplan Encoder


    ESP8266 Modul ESP12F (kompatibel mit ESP12E)

    Der Schaltplan unten zeigt die (annähernd) Minimalbeschaltung des ESP12F Moduls.
    Im Einschaltmoment müssen einige Pins bestimmte logische Pegel führen, damit der Controller in den "Run" Modus kommt.
    GPIO0 -> high (bei low würde der Controller sonst in den Flash-Programmiermodus wechseln)
    GPIO2 -> high (was bei low passieren würde ist nicht dokumentiert bzw. habe ich nichts dazu gefunden -> es sollte aber bereits ein schwacher Pullup vorhanden sein)
    GPIO15 -> low (bei high würde der Controller von der SD-Karte booten wollen(nicht angeschlossen))
    Das Netzteil im unteren Bereich des Bildes stellt die Betriebsspannung von 3,3V für das Modul bereit. Der Transistor T1 ermöglicht einen externen Reset des ESP-Moduls. Der Widerstand R6(hier 560Ohm) ist notwendig, wenn man die Deep-Sleep-Funktion nutzen möchte. Ohne diesen Widerstand "wacht" der ESP8266 nicht wieder auf. Der Spannungsteiler R2/R3 setzt den TX-Pegel des At-Mega-Controllers auf einen für den ESP8266 verträglichen Wert herab. Die 3,3V Pegel des ESP8266 werden vom Atmel ohne Probleme als "high" erkannt.
    Schaltplan ESP12F


    Controller und restliche Peripherie

    Der Controller ist ein AtMega168. Bei der Beschaltung der Betriebsspannung und es Quarzes gibt es keine Besonderheiten. Die Displays sind von Avago Technologies und nennen sich "HCMS-2902" (Ich finde diesen Retro Look einfach schön). Die Displays muss man sich als seriell beschreibbare Schieberegister mit graphischer Anzeige vorstellen. Jede Stelle (jeder Buchstabe) besteht aus 5 Bytes wobei das jeweils zuerst übertragene Bit nicht sichtbar ist(5x7 LEDs). Der Controller setzt im Prinzip, ganz änlich wie im Dot-Matrix Projekt, die einzelnen Zeichen zusammen. Unten im Bild ist der AM2302 (DHT22) zu sehen, aufgrund der kürze der Leitungen wurde der externe Pullupwiderstand auf 10kOhm erhöht. Für die Ansteuerung des P-FETs ist ein Hilfstransistor (T2) erforderlich. Ohne ihn ließe sich der FET nicht abschalten. Der Widerstand R11 koppelt gegen und begrenzt in Kombination mit R10 so die maximal mögliche Gate-Source Spannung.
    Controller und Peripherie


    Bilder vom Aufbau

    Platine von vorn Platine von hinten
    Gehäuse Gehäuse
    Gehäuse Gehäuse

    Firmware

    Bis auf die Assembler-Routine für den AM2302 stammt der Code von mir. Von wo genau, der AM2302 Code stammt, weiß ich nicht mehr, aber die Routine funktioniert tadellos. Den Zeichensatz für die LED-Displays habe ich aus einem Datenblatt des Herstellers übernommen (nur bei einem Buchstaben stimmte da etwas nicht). Das fehlende "°"-Zeichen habe ich einfach hinten drann gehängt.

    Quellcode: (Syntax highlighted mit
    G
    e
    S
    H
    i
    mit Anpassungen für BascomAVR von mir)
    '       **************************************
    '       *    Hygrometer mit AM2302/DHT22     *
    '       *            mit AtMega168           *
                     Const Softver = "1.1a"
    '       **************************************
     
    '  Beschaltung:
     
    '  PortB.0  (ICP) Encoder Taster gegen Masse
    '  PortB.1  Ausgang zu P-FET
    '  PortB.2  Eingang AM2302/DHT22
    '  PortB.3  ISP MOSI
    '  PortB.4  ISP MISO
    '  PortB.5  ISP SCK
    '  PortB.6  XTal
    '  PortB.7  XTal
     
    '  PortC.0  n.c.
    '  PortC.1  Display RS
    '  PortC.2  Display CLK
    '  PortC.3  Display CE
    '  PortC.4  Display RESET
    '  PortC.5  Display DI
    '  PortC.6  POR
     
    '  PortD.0  (RXD) zum TX des ESP8266
    '  PortD.1  (TXD) zum RX des ESP8266 (über Spannungsteiler)
    '  PortD.2  (INT0) EncoderA geben Masse
    '  PortD.3  (INT1) EncoderB geben Masse
    '  PortD.4  n.n
    '  PortD.5  n.c.
    '  PortD.6  n.c.
    '  PortD.7  zum ESP8266 Reset (über Transistor)
     
    '  AGND     GND
    '  AREF     über 100n an Masse
    '  AVCC     VCC
    '  ADC6     n.c.
    '  ADC7     n.c.
     
    '**** Compiler settings ****
       $regfile = "m168def.dat"
       $crystal = 14745600
       $baud = 115200
       $hwstack = 128
       $swstack = 64
       $framesize = 64
     
    '**** alias ****
       P_fet Alias Portb.1
       Esp_reset Alias Portd.7
     
       Hcms_re Alias Portc.4
       Hcms_ce Alias Portc.3
       Hcms_rs Alias Portc.1
     
       Akku_a Alias R0
       Akku_b Alias R1
       Akku_c Alias R2
       Akku_d Alias R3
       Vom_am Alias R4
       Signal Alias R16
       Impuls Alias R17
       Notaus Alias R18
       Dauer Alias R19
       Bitzahl Alias R20
       Zwischen Alias R21
     
    '**** Konstanten deklarieren ****
       Const _esp_reset_time = 11                               'Sekunden
     
       Const _timeout = _xtal / 200000
       Const _schwelle =((_xtal / - 370000))
       Const _parity_ok = 0
       Const _parity_err = 1
       Const _timeout_err = 2
       Const _am_filterlaenge = &B0000_1111
       Const _am_pos_flanke = &B0000_0001
       Const _am_neg_flanke = &B0000_1110
     
    '**** EERAM Variablen deklarieren ****
       Dim Ee_dummybyte As Eram Byte At &H00                    'EEpromDummybyte da das erste byte im EEProm bei einem Reset verfälscht werden könnte
     
       Dim Ee_schwelle As Eram Byte At &H01
       Dim Ee_hysterese As Eram Byte At &H02
       Dim Ee_helligkeit As Eram Byte At &H03
       Dim Ee_interval As Eram Byte At &H04
     
       Dim Ee_schwelle_bckp As Eram Byte At &H05
       Dim Ee_hysterese_bckp As Eram Byte At &H06
       Dim Ee_helligkeit_bckp As Eram Byte At &H07
       Dim Ee_interval_bckp As Eram Byte At &H08
     
       $eepromhex                                               'den Compiler anweisen den EEProminhalt im Intel-Hex-Format auszugeben
       $eeprom                                                  'die folgenden Daten werden im EEProm gespeichert
          Data 0
          Data 60 , 10 , 15 , 5
          Data 60 , 10 , 15 , 5
       $data
     
    '**** SRAM Variablen deklarieren ****
       Dim Am(5) As Byte
       Dim Am_parity As Byte At Am(1) Overlay
       Dim Am_temperatur As Integer At Am(2) Overlay
       Dim Am_feuchte As Integer At Am(4) Overlay
       Dim Am_err As Byte                                       '0=ok, 1=Parityfehler, 2=Timeout
       Dim Temp As String * 8
       Dim Relf As String * 8
       Dim Temp_ As String * 5
       Dim Relf_ As String * 5
     
       Dim Anzeige_string As String * 30
       Dim Anzeige_byte(30) As Byte At Anzeige_string Overlay
       Dim Delay_time As Byte
       Dim Hcms_helligkeit As Byte
       Dim Stelle As Byte
       Dim Spalte As Byte
       Dim Pointer As Word
       Dim Spaltenwert As Byte
     
       Dim Eeram_err As Byte
       Dim Schwelle As Byte
       Dim Hysterese As Byte
       Dim Helligkeit As Byte
       Dim Interval As Byte
     
       Dim Encoderwert As Byte
       Dim Encodermin As Byte
       Dim Encodermax As Byte
     
       Dim Menu As Byte
     
       Dim Sekunden As Word
       Dim Interval_sekunden As Word
       Dim Reset_interval_sekunden As Word
     
       Dim Temp_int As Integer
       Dim Temp_byte As Byte
     
       Dim N As Byte
     
    '**** DDR settings ****
       Ddrb = &B00000010                                        'PortB.1=Ausgang zu P-Fet, Rest Eingänge
       Ddrc = &B0111110                                         'PortC.1-C.5=Ausgänge für Display, Rest Eingänge
       Ddrd = &B10010010                                        'PortD.1=Ausgang(TXD), PortD.7=Ausgang(ESP8266 Reset)
     
    '**** Port settings ****
       Portb = &B00000001                                       'Pullup für Taster
       Portd = &B00001101                                       'Pullup für RXD, INT0, INT2
     
    '**** Timer Settings ****
       Tccr1a = &B00000011                                      'Fast PWM Mode 15
       Tccr1b = &B00011100                                      'Fast PWM Mode 15 (+ ICP1 auf fallende Flanke) noch ohne pre (später = 256)
       Ocr1a = 57599                                            'Wert für 1Hz ( (clk/(pre*f))-1 )
     
    '**** Interrupt settings ****
       Eicra = &B00000001                                       'INT0 auf steigende und fallende Flanke einstellen
       On Icp1 Isr_icp1
       On Int0 Isr_int0
       On Ovf1 Isr_ovf1
       Disable Interrupts
       Enable Icp1
       Enable Int0
       Enable Ovf1
     
    '**** SPI konfigurieren ****
       Config Spi = Soft , Din = Portc.0 , Dout = Portc.5 , Ss = None , Clock = Portc.2
       Spiinit
     
    '**** AM2302 konfigurieren ****
       Port_in_am Alias Pinb
       Port_out_am Alias Portb
       Pin_am Alias 2
     
     
    Init:
       Esp_reset = 1
       Hcms_re = 0
       Waitus 250
       Hcms_re = 1
     
       Hcms_helligkeit = 0
       Gosub Set_hcms_helligkeit
       Anzeige_string = "        "
       Gosub Update_hcms_fast
       Hcms_helligkeit = 15
       Gosub Set_hcms_helligkeit
     
       Delay_time = 100
     
       If Ee_dummybyte = 255 Then
          Do
             Anzeige_string = "*** Speicherfehler  *** "
             Gosub Update_hcms_slow
             Anzeige_string = "keine Daten        "
             Gosub Update_hcms_slow
             Waitms 500
          Loop
       Else
          Anzeige_string = "*** Check NVRAM ***        "
          Gosub Update_hcms_slow
       End If
     
       Eifr.0 = 1
       Tifr1.5 = 1
       Menu = 0
       N = 1
       Sekunden = 0
       Timer1 = 0
     
       Gosub Check_eeram
     
       If Eeram_err > 0 Then
          Do
             Anzeige_string = "*** Speicherfehler  *** "
             Gosub Update_hcms_slow
             Anzeige_string = Str(eeram_err) + " Zelle(n) "
             Gosub Update_hcms_slow
             Anzeige_string = " fehlerhaft        "
             Gosub Update_hcms_slow
             Waitms 500
          Loop
       Else
          Anzeige_string = "ok        "
          Gosub Update_hcms_slow
       End If
     
       Hcms_helligkeit = Helligkeit
       Gosub Set_hcms_helligkeit
     
       Anzeige_string = "Stefan's HWR-Hygrometer "
       Gosub Update_hcms_slow
       Anzeige_string = "Softwareversion " + Softver + "        "
       Gosub Update_hcms_slow
     
       Gosub Get_luftfeuchte
       If Am_err = 0 Then
          Anzeige_string = "Sensor ok        "
          Gosub Update_hcms_slow
       Else
          Do
             Anzeige_string = "*** Sensorfehler  *** "
             Gosub Update_hcms_slow
             If Am_err = 1 Then
                Anzeige_string = "Kommunikation AM2302        "
                Gosub Update_hcms_slow
             Else
                Anzeige_string = "Verbindung AM2302        "
                Gosub Update_hcms_slow
             End If
             Waitms 500
          Loop
       End If
     
     
    Main:
       Do
          Select Case Menu
             Case 0 :
                Tccr1b = &B01011100
                If Am_err = 0 Then
                   Select Case N
                      Case 1 :
                         Gosub Get_luftfeuchte
                         Anzeige_string = Relf
                         Gosub Update_hcms_slow
     
                      Case 2 To 10 :
                         Anzeige_string = Relf
                         Gosub Update_hcms_fast
     
                      Case 11:
                         Gosub Get_luftfeuchte
                         Anzeige_string = Temp
                         Gosub Update_hcms_slow
     
                      Case 12 To 20 :
                         Anzeige_string = Temp
                         Gosub Update_hcms_fast
     
     
                      Case Else :
                         Nop
                   End Select
                Else
                   Anzeige_string = "*** Sensorfehler  *** "
                   Gosub Update_hcms_slow
                   If Am_err = 1 Then
                      Anzeige_string = "Kommunikation AM2302        "
                      Gosub Update_hcms_slow
                   Else
                      Anzeige_string = "Verbindung AM2302        "
                      Gosub Update_hcms_slow
                   End If
                End If
     
             Case 1 :
                Anzeige_string = " Schaltschwelle        "
                Gosub Update_hcms_slow
     
             Case 11 :
                Anzeige_string = Str(schwelle)
                Anzeige_string = Format(anzeige_string , "        ")
                Anzeige_byte(1) = "S"
                Anzeige_byte(2) = "w"
                Anzeige_byte(3) = ":"
                Gosub Update_hcms_fast
     
             Case 2 :
                Anzeige_string = " Hysterese        "
                Gosub Update_hcms_slow
     
             Case 21 :
                Anzeige_string = Str(hysterese)
                Anzeige_string = Format(anzeige_string , "        ")
                Anzeige_byte(1) = "H"
                Anzeige_byte(2) = "y"
                Anzeige_byte(3) = ":"
                Gosub Update_hcms_fast
     
             Case 3 :
                Anzeige_string = " Helligkeit        "
                Gosub Update_hcms_slow
     
             Case 31 :
                Anzeige_string = Str(helligkeit)
                Anzeige_string = Format(anzeige_string , "        ")
                Anzeige_byte(1) = "H"
                Anzeige_byte(2) = "e"
                Anzeige_byte(3) = ":"
     
                Gosub Update_hcms_fast
     
             Case 4 :
                Anzeige_string = " Datenbankinterval        "
                Gosub Update_hcms_slow
     
             Case 41 :
                Anzeige_string = Str(interval)
                Anzeige_string = Format(anzeige_string , "        ")
                Anzeige_byte(1) = "D"
                Anzeige_byte(2) = "i"
                Anzeige_byte(3) = ":"
     
                Gosub Update_hcms_fast
     
             Case Else :
                nop
          End Select
     
          If Sekunden >= Reset_interval_sekunden Then           'ESP "aufwecken"
             Esp_reset = 0
             Reset_interval_sekunden = 65535                    'mehrmaliges Aufrufen verhindern
             Anzeige_string = "    "
             Gosub Update_hcms_slow
             Anzeige_string = "ESP Reset...        "
             Gosub Update_hcms_slow
          End If
     
          If Sekunden >= Interval_sekunden Then                 'Messwerte an Webseite senden
             If Am_err = 0 Then
    '*********************************************************************************************
    '*                                                                                           *
    '*    Hier steht in meinem "echten" Programm die Routine zur Übertragung in die Datenbank    *
    '*    Dazu wird ein Befehl mit der URL zu einer php-Datei verwendet                          *
    '*    Diese URL möchte ich aus nachvollziebahren Gründen nicht veröffentlichen ;-)           *
    '*                                                                                           *
    '*********************************************************************************************
             End If
             Reset_interval_sekunden = Interval_sekunden - _esp_reset_time
             Sekunden = 0
             Anzeige_string = "    "
             Gosub Update_hcms_slow
             Anzeige_string = "Upload...        "
             Gosub Update_hcms_slow
             Esp_reset = 1
          End If
     
          Temp_int = Am_feuchte / 10
          Temp_byte = Schwelle - Hysterese
     
          If Temp_int >= Schwelle Then
             P_fet = 1
          Elseif Temp_int < Temp_byte Then
             P_fet = 0
          End If
     
          If N < 21 Then
             Incr N
          Else
             N = 1
          End If
          Wait 1
       Loop
       End
     
    Check_eeram:
       Disable Interrupts
       Eeram_err = 0
     
       Schwelle = Ee_schwelle
       Hysterese = Ee_hysterese
       Helligkeit = Ee_helligkeit
       Interval = Ee_interval
     
       If Schwelle <> Ee_schwelle_bckp Then
          Schwelle = Ee_schwelle_bckp
          Ee_schwelle = Schwelle
          Incr Eeram_err
       End If
     
       If Hysterese <> Ee_hysterese_bckp Then
          Hysterese = Ee_hysterese_bckp
          Ee_hysterese = Hysterese
          Incr Eeram_err
       End If
     
       If Helligkeit <> Ee_helligkeit_bckp Then
          Helligkeit = Ee_helligkeit_bckp
          Ee_helligkeit = Helligkeit
          Incr Eeram_err
       End If
     
       If Interval <> Ee_interval_bckp Then
          Interval = Ee_interval_bckp
          Ee_interval = Interval
          Incr Eeram_err
       End If
     
       Interval_sekunden = Interval * 60                        'Das Interval(min) in Sekunden umrechnen
       Reset_interval_sekunden = Interval_sekunden - _esp_reset_time
     
       Tifr1.5 = 1
       Eifr.0 = 1
       N = 1
       Sekunden = 0
       Timer1 = 0
       Enable Interrupts
    Return
     
     
    Get_luftfeuchte:
       Config Port_out_am.pin_am = Output
       Reset Port_out_am.pin_am
       Waitus 1000
       Config Port_out_am.pin_am = Input
       Waitus 3
       $asm
    Am2302:
       ldi   Signal, &B1111_1111                                'zuerst wird eine 1 anstehen, vorbesetzen
       clr   Bitzahl                                            'Bitzaehler auf 0
       ldi   Notaus, _Timeout                                   'Timer Notausstieg aufziehen
    Am2302_10:
       in    Zwischen, port_in_am                               'Signal vom AM2302 einlesen
       lsl   Signal                                             '... und nach links schieben
       sbrc  Zwischen, Pin_am
       inc   Signal                                             'aktueller Pegel nach D0
       andi  Signal, _am_filterlaenge                           'Filterlänge gegen Spikes einstellen
       cpi   Signal, _am_pos_flanke                             'Positive Flanke, mit Entprellung
       brne  Am2302_20
       LDi   Impuls, 1                                          'Einsen-Zähler "Dauer" einschalten
       ldi   Dauer, _Schwelle                                   '"Dauer" mit der _Schwelle laden
       ldi   Notaus, _Timeout                                   'Timer Notausstieg aufziehen
       rjmp  Am2302_30
    Am2302_20:
       cpi   Signal, _am_neg_flanke                             'Negative Flanke, mit Entprellung
       brne  Am2302_30                                          'Jetzt ist minimal 45µsec Zeit zum rechnen
       inc   Bitzahl                                            'Bit zu Ende, Bitzähler  erhöhen
       LDi   Impuls, 0                                          'Einsen-Zähler "Dauer" ausschalten
       ldi   Notaus, _Timeout                                   'Timer Notausstieg aufziehen
       Lds   Zwischen, {am(1)}                                  'Parity
       lsl   Zwischen
       sbrs  Dauer, 7                                           'Negativ = 0 , Positiv = 1
       inc   Zwischen
       sts   {am(1)}, Zwischen
       Lds   Zwischen, {am(2)}                                  'Temperatur low
       rol   Zwischen
       sts   {am(2)}, Zwischen
       Lds   Zwischen, {am(3)}                                  'Temperatur high
       rol   Zwischen
       sts   {am(3)}, Zwischen
       Lds   Zwischen, {am(4)}                                  'Feuchte low
       rol   Zwischen
       sts   {am(4)}, Zwischen
       Lds   Zwischen, {am(5)}                                  'Feuchte high
       rol   Zwischen
       sts   {am(5)}, Zwischen
    Am2302_30:
       sbrc  Impuls, 0                                          'Solange eine 1 anliegt
       Inc   Dauer                                              ' ...den Bitzähler erhöhen
       cpi   Bitzahl, 42                                        'Alle Bits eingelesen ?
       breq  AM2302_40
       dec   Notaus                                             'Timer Notausstieg runterzählen
       breq  AM2302_50                                          'Zeitdauer-Überlauf prüfen
       rjmp  Am2302_10                                          'Noch nicht alle Bits da, also weitermachen
    Am2302_40:
       Lds   Vom_am, {am(1)}                                    'Parity vom AM2302
       Lds   Akku_a, {am(2)}                                    'Temperatur low
       Lds   Akku_b, {am(3)}                                    'Temperatur high
       Lds   Akku_c, {am(4)}                                    'Feuchte low
       Lds   Akku_d, {am(5)}                                    'Feuchte high
       add   Akku_a, Akku_b
       add   Akku_a, Akku_c
       add   Akku_a, Akku_d
       Ldi   Zwischen, _parity_ok
       cp    Akku_a, Vom_am                                     'Parityprüfung
       Breq  Am2302_99
       Ldi   Zwischen, _parity_err
       rjmp  Am2302_99
    Am2302_50:
       Ldi   Zwischen, _timeout_err
    Am2302_99:
       sts   {AM_err}, Zwischen                                 'Fehlerkennung eintragen
       $end Asm
       If Am_temperatur < 0 Then
          Am_temperatur.15 = 0
          Am_temperatur = Am_temperatur * -1
       End If
       Temp_ = Str(am_temperatur)
       Temp_ = Format(temp_ , "0.0")
       Temp = Format(temp_ , "      ")
       Temp = Temp + Chr(128) + "C"
     
       Relf_ = Str(am_feuchte)
       Relf_ = Format(relf_ , "0.0")
       Relf = Format(relf_ , "     ")
       Relf = Relf + "%rF"
    Return
     
     
    Set_hcms_helligkeit:
       Hcms_helligkeit.6 = 1                                    'Sleepmode aus
       Hcms_rs = 1
       Waitus 1
       Hcms_ce = 0
       Waitus 1
       Spiout Hcms_helligkeit , 1
       Spiout Hcms_helligkeit , 1                               '2mal weil 2 Displays und serielle Stuerbyteübertragung
       Waitus 1
       Hcms_ce = 1
    Return
     
     
    Update_hcms_fast:
       Hcms_rs = 0
       Waitus 1
       Hcms_ce = 0
       Waitus 1
       For Stelle = 1 To Len(anzeige_string)
          For Spalte = 0 To 4                                   'jeder Buchstabe besteht aus 5 Spalten (0-4)
             Pointer = Anzeige_byte(stelle) * 5                 'Pointer einstellen
             Pointer = Pointer + Spalte                         'Pointer einstellen
             Spaltenwert = Lookup(pointer , Font)               'Daten aus dem Alphabet holen und entsprechende LEDs einschalten
             Spiout Spaltenwert , 1
             Waitus 1
          Next Spalte                                           'nächste Spalte
       Next Stelle
       Hcms_ce = 1
    Return
     
     
    Update_hcms_slow:
       Hcms_rs = 0
       Waitus 1
       For Stelle = 1 To Len(anzeige_string)
          Hcms_ce = 0
          Waitus 1
          For Spalte = 0 To 4                                   'jeder Buchstabe besteht aus 5 Spalten (0-4)
             Pointer = Anzeige_byte(stelle) * 5                 'Pointer einstellen
             Pointer = Pointer + Spalte                         'Pointer einstellen
             Spaltenwert = Lookup(pointer , Font)               'Daten aus dem Alphabet holen und entsprechende LEDs einschalten
             Spiout Spaltenwert , 1
          Next Spalte                                           'nächste Spalte
          Hcms_ce = 1
          Waitms Delay_time
       Next Stelle
    Return
     
     
    Isr_icp1:                                                   'Taster
       Select Case Menu
          Case 1 :
             Tccr1b = &B01011000
             Sekunden = 0
             Timer1 = 0
             Menu = 11
     
          Case 11 :
             Menu = 0
             Ee_schwelle_bckp = Schwelle
             Gosub Check_eeram
             Anzeige_string = "        "
             Gosub Update_hcms_fast
             Anzeige_string = "Schaltschwelle gespeichert "
             Gosub Update_hcms_slow
             N = 1
     
          Case 2 :
             Tccr1b = &B01011000
             Sekunden = 0
             Timer1 = 0
             Menu = 21
     
          Case 21 :
             Menu = 0
             Ee_hysterese_bckp = Hysterese
             Gosub Check_eeram
             Anzeige_string = "        "
             Gosub Update_hcms_fast
             Anzeige_string = "Hysterese gespeichert "
             Gosub Update_hcms_slow
             N = 1
     
          Case 3 :
             Tccr1b = &B01011000
             Sekunden = 0
             Timer1 = 0
             Menu = 31
     
          Case 31 :
             Menu = 0
             Ee_helligkeit_bckp = Helligkeit
             Gosub Check_eeram
             Anzeige_string = "        "
             Gosub Update_hcms_fast
             Anzeige_string = "Helligkeit gespeichert "
             Gosub Update_hcms_slow
             N = 1
     
          Case 4 :
             Tccr1b = &B01011000
             Sekunden = 0
             Timer1 = 0
             Menu = 41
     
          Case 41 :
             Menu = 0
             Ee_interval_bckp = Interval
             Gosub Check_eeram
             Anzeige_string = "        "
             Gosub Update_hcms_fast
             Anzeige_string = "Interval gespeichert "
             Gosub Update_hcms_slow
             N = 1
       End Select
    Return
     
     
    Isr_int0:                                                   'Encoder
       Select Case Menu
          Case 0 To 4 :
             Encoderwert = Menu
             Encodermin = 0
             Encodermax = 4
     
          Case 11 :
             Encoderwert = Schwelle
             Encodermin = Hysterese + 5
             If Encodermin < 20 Then
                Encodermin = 20
             End If
             Encodermax = 90
     
          Case 21 :
             Encoderwert = Hysterese
             Encodermin = 5
             Encodermax = Schwelle - 5
             If Encodermax > 30 Then
                Encodermax = 30
             End If
     
          Case 31 :
             Encoderwert = Helligkeit
             Encodermin = 5
             Encodermax = 15
     
          Case 41 :
             Encoderwert = Interval
             Encodermin = 1
             Encodermax = 30
       End Select
     
       If Pind.2 = 0 Then
          If Pind.3 = 1 Then
             If Encoderwert < Encodermax Then
                Incr Encoderwert
             Else
                Encoderwert = Encodermin
             End If
          Else
             If Encoderwert > Encodermin Then
                Decr Encoderwert
             Else
                Encoderwert = Encodermax
             End If
          End If
       Else
          If Pind.3 = 0 Then
             If Encoderwert < Encodermax Then
                Incr Encoderwert
             Else
                Encoderwert = Encodermin
             End If
          Else
             If Encoderwert > Encodermin Then
                Decr Encoderwert
             Else
                Encoderwert = Encodermax
             End If
          End If
       End If
     
       Select Case Menu
          Case 0 To 4 :
             Menu = Encoderwert
          Case 11 :
             Schwelle = Encoderwert
             Anzeige_string = Str(schwelle)
             Anzeige_string = Format(anzeige_string , "        ")
             Anzeige_byte(1) = "S"
             Anzeige_byte(2) = "w"
             Anzeige_byte(3) = ":"
             Gosub Update_hcms_fast
          Case 21 :
             Hysterese = Encoderwert
             Anzeige_string = Str(hysterese)
             Anzeige_string = Format(anzeige_string , "        ")
             Anzeige_byte(1) = "H"
             Anzeige_byte(2) = "y"
             Anzeige_byte(3) = ":"
             Gosub Update_hcms_fast
          Case 31 :
             Helligkeit = Encoderwert
             Hcms_helligkeit = Helligkeit
             Gosub Set_hcms_helligkeit
             Anzeige_string = Str(helligkeit)
             Anzeige_string = Format(anzeige_string , "        ")
             Anzeige_byte(1) = "H"
             Anzeige_byte(2) = "e"
             Anzeige_byte(3) = ":"
             Gosub Update_hcms_fast
          Case 41 :
             Interval = Encoderwert
             Anzeige_string = Str(interval)
             Anzeige_string = Format(anzeige_string , "        ")
             Anzeige_byte(1) = "D"
             Anzeige_byte(2) = "i"
             Anzeige_byte(3) = ":"
             Gosub Update_hcms_fast
       End Select
    Return
     
     
    Isr_ovf1:
       Incr Sekunden
    Return
     
     
    Font:
    Data &H08 , &H1C , &H3E , &H7F , &H00
    Data &H30 , &H45 , &H48 , &H40 , &H30
    Data &H45 , &H29 , &H11 , &H29 , &H45
    Data &H7D , &H09 , &H11 , &H21 , &H7D
    Data &H7D , &H09 , &H05 , &H05 , &H79
    Data &H38 , &H44 , &H44 , &H38 , &H44
    Data &H7E , &H01 , &H29 , &H2E , &H10
    Data &H30 , &H4A , &H4D , &H49 , &H30
    Data &H60 , &H50 , &H48 , &H50 , &H60
    Data &H1E , &H04 , &H04 , &H38 , &H40
    Data &H3E , &H49 , &H49 , &H49 , &H3E
    Data &H62 , &H14 , &H08 , &H10 , &H60
    Data &H40 , &H3C , &H20 , &H20 , &H1C
    Data &H08 , &H7C , &H04 , &H7C , &H02
    Data &H38 , &H44 , &H44 , &H3C , &H04
    Data &H41 , &H63 , &H55 , &H49 , &H41
    Data &H10 , &H08 , &H78 , &H08 , &H04
    Data &H18 , &H24 , &H7E , &H24 , &H18
    Data &H5E , &H61 , &H01 , &H61 , &H5E
    Data &H78 , &H14 , &H15 , &H14 , &H78
    Data &H38 , &H44 , &H45 , &H3C , &H40
    Data &H78 , &H15 , &H14 , &H15 , &H78
    Data &H38 , &H45 , &H44 , &H3D , &H40
    Data &H3C , &H43 , &H42 , &H43 , &H3C
    Data &H38 , &H45 , &H44 , &H45 , &H38
    Data &H3C , &H41 , &H40 , &H41 , &H3C
    Data &H38 , &H42 , &H40 , &H42 , &H38
    Data &H08 , &H08 , &H2A , &H1C , &H08
    Data &H20 , &H7E , &H02 , &H02 , &H02
    Data &H12 , &H19 , &H15 , &H12 , &H00
    Data &H48 , &H7E , &H49 , &H41 , &H42
    Data &H01 , &H12 , &H7C , &H12 , &H01
    Data &H00 , &H00 , &H00 , &H00 , &H00
    Data &H00 , &H5F , &H00 , &H00 , &H00
    Data &H00 , &H03 , &H00 , &H03 , &H00
    Data &H14 , &H7F , &H14 , &H7F , &H14
    Data &H24 , &H2A , &H7F , &H2A , &H12
    Data &H23 , &H13 , &H08 , &H64 , &H62
    Data &H36 , &H49 , &H56 , &H20 , &H50
    Data &H00 , &H0B , &H07 , &H00 , &H00
    Data &H00 , &H00 , &H3E , &H41 , &H00
    Data &H00 , &H41 , &H3E , &H00 , &H00
    Data &H08 , &H2A , &H1C , &H2A , &H08
    Data &H08 , &H08 , &H3E , &H08 , &H08
    Data &H00 , &H58 , &H38 , &H00 , &H00
    Data &H08 , &H08 , &H08 , &H08 , &H08
    Data &H00 , &H30 , &H30 , &H00 , &H00
    Data &H20 , &H10 , &H08 , &H04 , &H02
    Data &H3E , &H51 , &H49 , &H45 , &H3E
    Data &H00 , &H42 , &H7F , &H40 , &H00
    Data &H62 , &H51 , &H49 , &H49 , &H46
    Data &H22 , &H41 , &H49 , &H49 , &H36
    Data &H18 , &H14 , &H12 , &H7F , &H10
    Data &H27 , &H45 , &H45 , &H45 , &H39
    Data &H3C , &H4A , &H49 , &H49 , &H30
    Data &H01 , &H71 , &H09 , &H05 , &H03
    Data &H36 , &H49 , &H49 , &H49 , &H36
    Data &H06 , &H49 , &H49 , &H29 , &H1E
    Data &H00 , &H36 , &H36 , &H00 , &H00
    Data &H00 , &H5B , &H3B , &H00 , &H00
    Data &H00 , &H08 , &H14 , &H22 , &H41
    Data &H14 , &H14 , &H14 , &H14 , &H14
    Data &H41 , &H22 , &H14 , &H08 , &H00
    Data &H02 , &H01 , &H51 , &H09 , &H06
    Data &H3E , &H41 , &H5D , &H55 , &H1E
    Data &H7E , &H09 , &H09 , &H09 , &H7E
    Data &H7E , &H49 , &H49 , &H49 , &H36
    Data &H3E , &H41 , &H41 , &H41 , &H22
    Data &H7F , &H41 , &H41 , &H41 , &H3E
    Data &H7F , &H49 , &H49 , &H49 , &H41
    Data &H7F , &H09 , &H09 , &H09 , &H01
    Data &H3E , &H41 , &H41 , &H51 , &H32
    Data &H7F , &H08 , &H08 , &H08 , &H7F
    Data &H00 , &H41 , &H7F , &H41 , &H00
    Data &H20 , &H40 , &H40 , &H40 , &H3F
    Data &H7F , &H08 , &H14 , &H22 , &H41
    Data &H7F , &H40 , &H40 , &H40 , &H40
    Data &H7F , &H02 , &H0C , &H02 , &H7F
    Data &H7F , &H04 , &H08 , &H10 , &H7F
    Data &H3E , &H41 , &H41 , &H41 , &H3E
    Data &H7F , &H09 , &H09 , &H09 , &H06
    Data &H3E , &H41 , &H51 , &H21 , &H5E
    Data &H7F , &H09 , &H19 , &H29 , &H46
    Data &H26 , &H49 , &H49 , &H49 , &H32
    Data &H01 , &H01 , &H7F , &H01 , &H01
    Data &H3F , &H40 , &H40 , &H40 , &H3F
    Data &H07 , &H18 , &H60 , &H18 , &H07
    Data &H7F , &H20 , &H18 , &H20 , &H7F
    Data &H63 , &H14 , &H08 , &H14 , &H63
    Data &H03 , &H04 , &H78 , &H04 , &H03
    Data &H61 , &H51 , &H49 , &H45 , &H43
    Data &H00 , &H00 , &H7F , &H41 , &H41
    Data &H02 , &H04 , &H08 , &H10 , &H20
    Data &H41 , &H41 , &H7F , &H00 , &H00
    Data &H04 , &H02 , &H7F , &H02 , &H04
    Data &H40 , &H40 , &H40 , &H40 , &H40
    Data &H00 , &H07 , &H0B , &H00 , &H00
    Data &H38 , &H44 , &H44 , &H3C , &H40
    Data &H7F , &H48 , &H44 , &H44 , &H38
    Data &H38 , &H44 , &H44 , &H44 , &H44
    Data &H38 , &H44 , &H44 , &H48 , &H7F
    Data &H38 , &H54 , &H54 , &H54 , &H08
    Data &H08 , &H7E , &H09 , &H02 , &H00
    Data &H08 , &H14 , &H54 , &H54 , &H3C
    Data &H7F , &H08 , &H04 , &H04 , &H78
    Data &H00 , &H44 , &H7D , &H40 , &H00
    Data &H20 , &H40 , &H44 , &H3D , &H00
    Data &H00 , &H7F , &H10 , &H28 , &H44
    Data &H00 , &H41 , &H7F , &H40 , &H00
    Data &H78 , &H04 , &H18 , &H04 , &H78
    Data &H7C , &H08 , &H04 , &H04 , &H78
    Data &H38 , &H44 , &H44 , &H44 , &H38
    Data &H7C , &H14 , &H24 , &H24 , &H18
    Data &H18 , &H24 , &H14 , &H7C , &H40
    Data &H00 , &H7C , &H08 , &H04 , &H04
    Data &H48 , &H54 , &H54 , &H54 , &H20
    Data &H04 , &H3E , &H44 , &H20 , &H00
    Data &H3C , &H40 , &H40 , &H20 , &H7C
    Data &H1C , &H20 , &H40 , &H20 , &H1C
    Data &H3C , &H40 , &H30 , &H40 , &H3C
    Data &H44 , &H28 , &H10 , &H28 , &H44
    Data &H04 , &H48 , &H30 , &H08 , &H04
    Data &H44 , &H64 , &H54 , &H4C , &H44
    Data &H00 , &H08 , &H36 , &H41 , &H00
    Data &H00 , &H00 , &H77 , &H00 , &H00
    Data &H00 , &H41 , &H36 , &H08 , &H00
    Data &H08 , &H04 , &H08 , &H10 , &H08
    Data &H2A , &H55 , &H2A , &H55 , &H2A
    Data 6 , 9 , 9 , 6 , 0                                      '128 = ° Grad