'##############################################################################
' StarLight_Slave.BAS                                          Stand 14.02.2011
' -------------------                                          (C) Markus Fulde
'
' Steuerprogramm für Slaveeinheit der StarLight Deckenbeleuchtungselektronik
'
' Das Steuerprogramm verfügt über die folgenden einzelnen Funktions- und
' Teilkomponenten:
'     - Mikrocontroller ATmega168 (inkl. ISP, RS232 und Reset)
'     - 20 MHz externer Clock
'     - RS485-Interface für Kommunikation mit Master
'     - Slave-Adresse über 4-Bit DIP-Schalter konfigurierbar
'     - Nulldurchgangserkennung mittels Optokoppler für Dimmer
'     - Dimmersteuerung mittels optoentkoppeltem IGBT
'     - 1-Wire Temperatursensor für Umgebungstemperatur
'     - Lichtsteuerung An/Aus über Solid-Sate-Relais
'     - Akustischer Signalgeber
'     - LED-Anzeigen für Funktionsanzeige
'
'     - Funktions- und Debug-Steuerung über RS232
'
'
' Das Slaveprogramm führt die vom Master empfangenen Kommandos aus und sendet
' entsprechende Antworten/Statubotschaften zum Master zurück.
' Ein Slave verfügt über keine eigene Intelligenz, ist in seiner primären
' Aufgabe ein Phasenabschnittsdimmer, überwacht aber seine Umgebungstemperatur
' und schaltet für sich selbst die Netzspannung an/aus.
'
'##############################################################################

'------------------------------------------------------------------------------
' Compilerinstruktionen und Compilerdirektiven
'------------------------------------------------------------------------------
$regfile = "m168def.dat"                                    ' Definitionsdatei für ATmega168 laden
$crystal = 20000000                                         ' Quarzfrequenz für 20 MHz festlegen
$hwstack = 128                                              ' HW-Stack auf 128 Bytes erweitern
$swstack = 64                                               ' SW-Stack auf 64 Bytes erweitern
$framesize = 80                                             ' Framesize auf 80 Byte festlegen

' $baud = 38400                                               ' Baudrate für RS232 auf 38400 Bauf festlegen
' Hinweis: Direktive nicht notwendig da Konfiguration über CONFIG

'------------------------------------------------------------------------------
' Allgemeine Zusatzinformatonen zu Programmbeginn
'------------------------------------------------------------------------------

' ASCII Table (Incomplete)
' Decimal  Hex    Binary       Value   Beschreibung
' -------  ---    --------     -----   ------------------
' 000      000    00000000     NUL     (Null char.)
' 008      008    00001000     BS      (Backspace)
' 009      009    00001001     HT      (Horizontal Tab)
' 010      00A    00001010     LF      (Line Feed)
' 012      00C    00001100     FF      (Form Feed)
' 013      00D    00001101     CR      (Carriage Return)
' 032      020    00100000     SPACE   (Leerzeichen)
' 048      030    00110000     0       (Beginn der Ziffern)
' 049      031    00110001     1       (..)
' 052      034    00110100     4       (..)
' 065      041    01000001     A       (Beginn der Zeichen)
' 066      042    01000010     B       (..)
' 067      043    01000011     C       (..)

' Hinweis: Im Datenblatt wird die zeit von 750 ms nur in Verbindung mit dem
' parasite power mode genannt. Test in der Praxis haben interessanter Weise
' jedoch ergeben, das auch mit normaler Spannungsversorgung beim DS18S20 Zeiten
' bis 700 ms erreicht werden. Wird zu zeitig ausgelesen liefert der Sensor den
' Fehlercode 10101010 welcher 170 DEZ = 85°C entspricht. Wird dieser Wert bei
' erstmaligem Convert T ausgelesen ist dies ein Zeichen dafür, dass der Sensor
' den Konvertierungsvorgang noch nicht abgeschlossen hat.

'------------------------------------------------------------------------------
' Definition von Ressourcen
'------------------------------------------------------------------------------

' ----- DIM: Dimmer -----
' Nulldurchgangserkennung
Nulldurchgang_pin Alias Pind.2                              ' GPIO für Nulldurchgangserkennung (für DDR oder Input)
Nulldurchgang Alias Portd.2                                 ' GPIO für Nulldurchgangserkennung (für Output oder PullUp)

' IGBT Steuerung
Igbt_pin Alias Pind.4                                       ' GPIO für IGBT-Steuerleitung (für DDR oder Input)
Igbt Alias Portd.4                                          ' GPIO für IGBT-Steuerleitung (für Output oder PullUp)

' Power Steuerung von Solid-State-Relais
Powerrelais_pin Alias Pinc.5                                ' GPIO für SSR-Steuerleitung (für DDR oder Input)
Powerrelais Alias Portc.5                                   ' GPIO für SSR-Steuerleitung (für Output oder PullUp)

' ----- LED's -----
' Übertemperatur-LED
Temp_led_pin Alias Pind.3                                   ' GPIO für Übertemperatur-LED (für DDR oder Input)
Temp_led Alias Portd.3                                      ' GPIO für Übertemperatur-LED (für Output oder PullUp)

Alive_pin Alias Pinc.4                                      ' GPIO für Alive-LED (für DDR oder Input)
Alive Alias Portc.4                                         ' GPIO für Alive-LED (für Output oder Pullup)

' ----- Steuerleitungen für RS485-Baustein -----

' DE = DataEnable für Senden
Rs485_de_pin Alias Pind.5                                   ' GPIO für DE (für DDR oder Input)
Rs485_de Alias Portd.5                                      ' GPIO für DE (für Output oder Pullup)

' RE = ReceiveEnable für Empfangen
Rs485_re_pin Alias Pind.6                                   ' GPIO für RE (für DDR oder Input)
Rs485_re Alias Portd.6                                      ' GPIO für RE (für Output oder Pullup)

' ----- Soundausgabe -----
' Piezo
Piezo_pin Alias Pind.7                                      ' GPIO für Soundausgabe (für DDR oder Input)
Piezo Alias Portd.7                                         ' GPIO für Soundausgabe (für Output oder PullUp)

' ----- DS1820: 1Wire-Interface DS18S20
1wire_port Alias Portb.2                                    ' 1Wire-Interface für Temperatursensor

' ----- Adressleitungen für Dipschalter -----

' Adr0
Adresse0_pin Alias Pinc.0                                   ' GPIO für Adr0 (für DDR oder Input)
Adresse0 Alias Portc.0                                      ' GPIO für Adr0 (für Output oder Pullup)

' Adr1
Adresse1_pin Alias Pinc.1                                   ' GPIO für Adr1 (für DDR oder Input)
Adresse1 Alias Portc.1                                      ' GPIO für Adr1 (für Output oder Pullup)

' Adr2
Adresse2_pin Alias Pinc.2                                   ' GPIO für Adr2 (für DDR oder Input)
Adresse2 Alias Portc.2                                      ' GPIO für Adr2 (für Output oder Pullup)

' Adr3
Adresse3_pin Alias Pinc.3                                   ' GPIO für Adr3 (für DDR oder Input)
Adresse3 Alias Portc.3                                      ' GPIO für Adr3 (für Output oder Pullup)

' Adressnibble
Adresse_port Alias Pinc                                     ' Port für die Adressschaltung

'------------------------------------------------------------------------------
' Definition von Konstaten
'------------------------------------------------------------------------------

' ----- Für Testumgebung bzw. Traceausgaben -----
Const Main_testmodus = 0                                    ' Flag für Testmodus Allgemeinsystem
Const System_testmodus = 0                                  ' Testmodus zum Abfackeln aller Funktionen vor Systemstart
Const Temp_testmodus = 0                                    ' Flag für Testmodus Temperaturüberwachung
Const Dimmer_testmodus = 0                                  ' Flag für Testmodus Dimmer
Const Timer_testmodus = 0                                   ' Flag für Testmodus Timer
Const Rs485_testmodus = 0                                   ' Flag für Testmodus RS485
Const Eeprom_testmodus = 0                                  ' Flag für Testmodus EEPROM
Const Empfangsueberwachung_testmodus = 0                    ' Flag für globale Empfangsüberwachung mit Timerout

' ----- Allgemeine Systemkonstanten -----
Const Led_aus = 0
Const Led_ein = 1

Const Licht_aus = 0
Const Licht_ein = 1

Const False = 0
Const True = 1

Const Pullup_aus = 0
Const Pullup_ein = 1

' Zeitvorgabe für Sekunden-Timer
Const Timervorgabe = 46005                                  ' Timer von 1 Sekunden (SekundenTick)

' Zeitvorgabe für Receive-Timeout-Überwachung
Const Receive_timeout = 2

' ----- System-Demo -----
Const Sweep_down = 0
Const Sweep_up = 1

Const Demo_sweep_time = 250                                 ' 250 ms

' ----- Systemcheck -----
Const Looptime = 100                                        ' Dauer der Schleifenzeit in ms für Check

' ----- Sound: Akustik-Wiedergabe -----
Const Sound_aus = 0
Const Sound_ein = 1
Const Sound_ein_delay = 100                                 ' Soundlänge in MS
Const Sound_pause_delay = 100                               ' Soundpause in MS

' ----- Relais: Hauptrelais-Steuerung -----
Const Relais_aus = 0
Const Relais_ein = 1

' ----- DIM: Systemkonstanten für das Dimmer-Modul -----
Const Dim_helligkeit_default = 0
Const Dim_helligkeitstabellenwerte = 32
Const Dim_helligkeit_min = 0
Const Dim_helligkeit_max = 32

Const Passiv = 0
Const Aktiv = 255

Const Igbt_aus = 0
Const Igbt_ein = 1

' ----- DS1820: Temperatursensor -----
Const Ds1820_skip_rom_command = &HCC                        ' Code für Skip ROM
Const Ds1820_convert_t_command = &H44                       ' Code für Convert T
Const Ds1820_scratchpad_command = &HBE                      ' Code für Read scratchpad

Const Ds1820_delay_time = 750                               ' 750ms Wartezeit

Const Ds1820_auswertung = 30                                ' Default Auswerteintervall in Sekunden
Const Ds1820_auswertung_start = 2                           ' Default Auswerteintervall in Sekunden

Const Uebertemperatur_default = 50                          ' Konstante für Übertemperatur

' ----- RS485: Systembus RS485 Interface -----

' Allgemeines
Const Nachrichtenlaenge = 10                                ' Länger der gesamtbotschaft in Bytes
Const Framelaenge = 5                                       ' Länger der Nutzdaten

Const Masteradresse = &H00                                  ' Master hat Adresse 0
Const Broadcastadresse = &HFF                               ' Adresse für alle uns alles (Broadcast)

Const Undefined = &HFF                                      ' Platzhalter

Const Rs485_send_enable = 1                                 ' DE ein
Const Rs485_send_disable = 0                                ' DE aus
Const Rs485_receive_enable = 0                              ' RE/ ein
Const Rs485_receive_disable = 1                             ' RE/ aus

' 1 Start + 8 Daten + 1 Stop = 10 Bits
' 10 Bytes pro Übertragung => 100 Bits bei 57600 Baud = 1,7361 ms => 2 ms
Const Wait_time = 2                                         ' Wartezeit in ms für RE

' Kommunikation Master -> Slave
Const Cmd_licht_schalten = &H01                             ' Steuerwort für Licht schalten
Const Cmd_dimmer_schalten = &H02                            ' Steuerwort für Dimmer steuern
Const Cmd_sound_schalten = &H03                             ' Steuerwort für Sound schalten
Const Cmd_licht_dimmer_schalten = &H04                      ' Steuerwort für Licht schalten und Dimmer steuern
Const Cmd_status_abfragen = &H05                            ' Steuerwort für Status abfragen
Const Cmd_uebertemperatur_setzen = &H06                     ' Steuerwort für Übertemperatur setzen
Const Cmd_demo_sweep = &H07                                 ' Steuerwort für Demo-Sweep-Modus

' Kommunikation Slave -> Master
Const Resp_ack = &HFF                                       ' Response Acknowledge                             '
Const Resp_uetemp = &H01                                    ' Response Übertemperatur
Const Resp_status = &H02                                    ' Response Status

' ----- Internes EEPROM -----

' Aktuelle EEPROM-Datenstruktur
Const Akt_internal_ee_version = &H02                        ' Aktuelle EEPROM-Datenstruktur intern

'------------------------------------------------------------------------------
' Definition von Variablen und Datentypen
'------------------------------------------------------------------------------

' Bemerkung:
' Die Betiebszustände des Dimmers können über die Variablen
'     - Free_running_flag
'     - Dim_helligkeitsstufe
' abgefragt werden.

' ----- Temporäre Hilfsvariablen -----
Dim Temp_byte_1 As Byte                                     ' Temporäre Byte Variable 1
Dim Temp_byte_2 As Byte                                     ' Temporäre Byte Variable 2
Dim Temp_byte_3 As Byte                                     ' Temporäre Byte Variable 3

Dim Temp_word_1 As Word                                     ' Temporäre Word Variable 1
Dim Temp_word_2 As Word                                     ' Temporäre Word Variable 2
Dim Temp_word_3 As Word                                     ' Temporäre Word Variable 3

Dim Temp_single_1 As Single                                 ' Temporäre Single Variable 1
Dim Temp_single_2 As Single                                 ' Temporäre Single Variable 2
Dim Temp_single_3 As Single                                 ' Temporäre Single Variable 3

' ----- Variable für SecTick Scheduler -----
Dim Timercounter As Word                                    ' Scheduler-Variable

' ----- Variablen für globale Receive Timeout Überwachung
Dim Receive_timeout_counter As Word                         ' Vaiable für Counter
Dim Receive_timeout_flag As Byte                            ' Flag für Counter-Überwachung

' ----- Variablen für Dimmer -----
Dim Igbt_schaltzeitpunkte(32) As Byte                       ' Array für Schaltzeitpunkt
Dim Dim_helligkeitsstufe As Byte                            ' Helligkeitsstufe
Dim Dim_index_counter As Byte                               ' Helligkeitsindex

Dim Free_running_flag As Byte                               ' Dimmerbetrieb

Dim Lichtflag As Byte                                       ' Flag of Licht eingeschaltet oder aus

' ----- DS1820: Temperatursensor -----
Dim Ds1820_device_count As Byte                             ' Variable für Anzahl aller Devices auf 1Wire
Dim Ds1820_rom_code(8) As Byte                              ' Variable für 64-Bit Lasered ROm Code
Dim Ds1820_error_flag As Byte                               ' Globale Variable für Fehlermeldungen
Dim Ds1820_scratchpad(9) As Byte                            ' Varible für Scratchpad
Dim Ds1820_messwert As Integer                              ' Globale Variable für Integer-Messert
Dim Ds1820_temperatur As Byte                               ' Gloable Temperatur zum Casten

Dim Ds1820_erfassungs_counter As Word                       ' Globaler Zähler für Windauswertung

Dim Flag_uebertemperatur As Byte                            ' Flag für Übertemperatur
Dim Uebertemperatur As Byte                                 ' Globale Variable für Übertemperatur

' ----- Variable für RS485 Slave-Adresse -----

' Algemeines
Dim Rs485_slaveadresse As Byte                              ' Slave-Adresse des Dimmers
Dim Rs485_broadcastflag As Byte                             ' Flag für broadcast-Botschaft

' RS485: Globale Sendestruktur
Dim Tx_zieladresse As Byte                                  ' Senden: Zieladresse
Dim Tx_quelladresse As Byte                                 ' Senden: Quelladresse
Dim Tx_framelength As Byte                                  ' Senden: Datenlänge
Dim Tx_kommando As Byte                                     ' Senden: Kommando
Dim Tx_licht As Byte                                        ' Senden: Datum Licht
Dim Tx_dimmstufe As Byte                                    ' Senden: Datum Dimmer
Dim Tx_temperatur As Byte                                   ' Senden: Temperatur
Dim Tx_sound As Byte                                        ' Senden: Datum Sound
Dim Tx_checksumme As Word                                   ' Senden: Cheksumme
Dim Tx_buffer(nachrichtenlaenge) As Byte At Tx_zieladresse Overlay       ' Overlay über Datenstruktur

Dim Tx_bufferindex As Byte                                  ' Sende-Zeiger
Dim Rs485_send_request As Byte                              ' Flag Sendeaufforderung

' RS485: Globale Empfangsstruktur
Dim Rx_zieladresse As Byte                                  ' Empfangen: Zieladresse
Dim Rx_quelladresse As Byte                                 ' Empfangen: Quelladresse
Dim Rx_framelength As Byte                                  ' Empfangen: Datenlänge
Dim Rx_kommando As Byte                                     ' Empfangen: Kommando
Dim Rx_licht As Byte                                        ' Empfangen: Datum Licht
Dim Rx_dimmstufe As Byte                                    ' Empfangen: Datum Dimmer
Dim Rx_temperatur As Byte                                   ' Empfangen: Temperatur
Dim Rx_sound As Byte                                        ' Empfangen: Datum Sound
Dim Rx_checksumme As Word                                   ' Empfangen: Checksumm
Dim Rx_buffer(nachrichtenlaenge) As Byte At Rx_zieladresse Overlay       ' Overlay über Datenstruktur

Dim Rx_bufferindex As Byte                                  ' Empfangs-Zeiger
Dim Rs485_data_received As Byte                             ' Flag Empfangsindikator

' ----- Variablen für Soundausgabe -----
Dim Soundflag As Byte                                       ' Flag für Soundausgabe

' ----- EEPROM Datenstrukturen und persistente Datenhaltung -----

' EE: EEPROM Datenstruktur internes EEPROM - Setting-Daten
Dim Ee_data_version_intern As Eram Byte At &H0000           ' Speicherstelle für Datenversion
Dim Ee_data_temperature As Eram Byte At &H0001              ' Speicherstelle für Temperaturschwelle

'------------------------------------------------------------------------------
' Konfiguration und Basiseinstellungen (Projekt und Testumgebung)
'------------------------------------------------------------------------------

' --------------------------------- CONFIG ------------------------------------

' ----- RS232 -----

' Hardware RS232 konfigurieren = interne RS232

' Serialport für RS485 Systeminterface
Config Com1 = 57600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Serialin = Buffered , Size = 254
Config Serialout = Buffered , Size = 254

' Serialport für RS485 Systeminterface
Open "com1:" For Binary As #1

' Software RS232 Kanal 2 und 3 konfigurieren = externe RS232
' Anschluss an Mega168 über PORTB.0 für RxD und PORTB.1 für TxD.

' Achtung: Tracesausgaben zum PC erfolgen über SW-RS232. Die HW-RS232 wird zur
' Kommunikation mit RS485-Bus verwendet

' Öffnen eines Transmit-Kanals (#2) für Ausgaben
Open "comb.1:38400,8,n,1" For Output As #2

' Öffnen eines Receive-Kanals (#3) für Eingaben
Open "comb.0:38400,8,n,1 " For Input As #3

' ----- Konfiguration 1-Wire-Interface -----
Config 1wire = 1wire_port                                   ' Konfiguration 1-Wire-Interface

' ----- Timer -----

' Konfiguration eines Timers für 1 Sekunden Timer-Tick (Scheduler und Alive)
Config Timer1 = Timer , Prescale = 1024                     ' Timer 1 verwenden
On Timer1 Sekunden_tick                                     ' Interrupt Routine
Timer1 = Timervorgabe
Enable Timer1                                               ' Interrupt für Sekunden-Tack

' ----- Konfiguration Dimmer -----

' DIM: Interrupt für Nulldurchgangserkennung konfigurieren
Gosub Dimmer_konfig

' INT0 so konfiguriert das Trigger bei steigender  Flanke
Config Int0 = Rising
' Springe zur Interrupt-Routine Dimmer_irq
On Int0 Dimmer_null_irq
Enable Int0                                                 ' Interrupt5 freigeben

' Konfiguration Timer2 für Abschaltzeitpunkt IGBT nach Vorgabe bzw. Nulldurchgang
Config Timer2 = Timer , Prescale = 1024
On Timer2 Dimmer_triac_irq
Enable Timer2

' ------------------------------- Port's und Pin's ----------------------------

' ----- LED-Konfigurationen -----
Config Alive_pin = Output
Config Temp_led_pin = Output

' ----- Sound-Konfiguration -----
Config Piezo_pin = Output

' ----- Hauptrelais -----
Config Powerrelais_pin = Output

' ----- RS485 -----

' Adressleitungen für Dipschalter
Config Adresse0_pin = Input                                 ' Adresspin als Eingang konfigurieren
Config Adresse1_pin = Input                                 ' Adresspin als Eingang konfigurieren
Config Adresse2_pin = Input                                 ' Adresspin als Eingang konfigurieren
Config Adresse3_pin = Input                                 ' Adresspin als Eingang konfigurieren

' RS485-Steuerleitungen konfigurieren
Config Rs485_de_pin = Output                                ' DataEnable
Config Rs485_re_pin = Output                                ' ReceiveEnable

' ------------------------------ Variablen und Werte --------------------------

' ----- LED-Konfigurationen -----
Alive = Led_aus                                             ' Alive-LED aus
Temp_led = Led_aus                                          ' Übertemperatur LED aus

' ----- Sound-Konfiguration -----
Piezo = Sound_aus                                           ' Sound aus auf Port ausgeben
Soundflag = Sound_aus                                       ' Soundflag auf Sound = AUS setzen

' ----- Hauptrelais -----
Powerrelais = Relais_aus                                    ' Powerrelais immer aus
Lichtflag = Licht_aus                                       ' Licht immer aus

' ----- Globale Variable für SecTick Scheduler -----
Timercounter = 0                                            ' Sekunden-Counter auf 0 initialisieren

' ----- Dimmervariablen initialisieren -----
Free_running_flag = Passiv                                  ' Free_Running aktivieren
Dim_helligkeitsstufe = Dim_helligkeit_default               ' Defaulthelligkeit setzen

' ----- DS18S20 -----
Ds1820_temperatur = 0                                       ' Zunächst Temperatur auf NULL setzen
Flag_uebertemperatur = False                                ' Flag zur Steuerung des Übertemperatur-Handlings

' ----- RS485 -----
' Adressleitungen für Dipschalter
Adresse0 = Pullup_ein                                       ' Interner PullUp ein
Adresse1 = Pullup_ein                                       ' Interner PullUp ein
Adresse2 = Pullup_ein                                       ' Interner PullUp ein
Adresse3 = Pullup_ein                                       ' Interner PullUp ein

' RS485-Steuerleitungen konfigurieren
Rs485_de = Rs485_send_disable                               ' Treiber default tristate
Rs485_re = Rs485_receive_enable                             ' Treiber immer mithörend

' Sende- und Empfangsstrukturen initialisieren
Rx_bufferindex = 1                                          ' Index auf 1
Tx_bufferindex = 1                                          ' Index auf 1
Rs485_broadcastflag = False                                 ' Adresstyp zurücksetzen

' Adresse berechnen
Rs485_slaveadresse = Adresse_port
Rs485_slaveadresse = Rs485_slaveadresse And &B00001111      ' Maske über LOW-Nibble

' ----- Globale Empfangs-Timeout-Überwachung -----
Receive_timeout_counter = 0                                 ' Counter auf NULL
Receive_timeout_flag = False                                ' Flag auf False

' ----- Variablen für Soundausgabe -----
Soundflag = False

'------------------------------------------------------------------------------
' Und los gehts, hier noch die Restarbeiten
'------------------------------------------------------------------------------

' ---------------------------------- Gosub's ----------------------------------

' ----- Initialisierung Dimmer -----

' DIM: Interrupt für Nulldurchgangserkennung konfigurieren
Gosub Dimmer_konfig

' ----- DS18S20: Konfiguration Temperatursensor -----
Gosub Ds1820_konfig                                         ' Konfiguration
Gosub Ds1820_start_measurement                              ' Erstmaliges Messen auslösen

' ----- Freigabe aller Interrupts ----
Enable Interrupts                                           ' Damit auch Empfang von Daten über Buffer

' ----- EEPROM -----
' Initialisierung des internen EEPROM aufrufen und ggf. Traces schreiben
Gosub Ee_init_internal_eeprom

'-- Timer2 sofort anhalten und erst über SW anstossen
Stop Timer2

' ---------------------------------- Systemtest -------------------------------

' Falls System_testmodus gesetzt ist wird kurzer System-Check durchlaufen.
' Alle relevanten Funktionen werden einmal angefahren und entsprechender Output
' auf der Trace-Schnittstelle wird erzeugt.
#if System_testmodus

   ' *** Adresseinstellung ***

   ' Ausgabe der errechneten Slave-Adresse
   Print #2 , "System_testmodus: Adresse " ; Rs485_slaveadresse ; " erkannt"

   ' *** LED's ***

   ' LED's blinken lassen
   For Temp_byte_1 = 1 To 3
      Temp_led = Led_ein
      Waitms Looptime                                       ' Wartezeit für Testschleifen
      Temp_led = Led_aus
      Waitms Looptime                                       ' Wartezeit für Testschleifen
   Next Temp_byte_1

   ' *** Sound ***

   ' Piezo piepsen lassen
   For Temp_byte_1 = 1 To 3
      Piezo = Sound_ein
      Waitms Looptime
      Piezo = Sound_aus
      Waitms Looptime
   Next Temp_byte_1

   ' *** Hauptrelais ***

   ' Hauptspannung einschalten -> LED für Nulldurchgangserkennung sollte leuchten
   Powerrelais = Relais_ein
   Lichtflag = Licht_ein

   ' 5 Sekunden warten bis Dimmer einsetzt
   Wait 5

   ' *** Dimmer ***

   ' Dimmer einschalten
   Gosub Dimmer_ein

   ' Dimmer langsam von 1 bis 32 hochfahren
   For Temp_byte_1 = 1 To 31 Step 1
      ' Dimmerhelligkeit setzen
      Dim_helligkeitsstufe = Temp_byte_1
      Waitms Looptime                                       ' Wartezeit für Testschleifen
   Next Temp_byte_1

   ' Dimmer langsam von 32 bis 1 abdimmen
   For Temp_byte_1 = 31 To 1 Step -1
      ' Dimmerhelligkeit setzen
      Dim_helligkeitsstufe = Temp_byte_1
      Waitms Looptime                                       ' Wartezeit für Testschleifen
   Next Temp_byte_1

   ' Grobe Schritte dafür lange an
   Dim_helligkeitsstufe = 10
   Wait 5
   Dim_helligkeitsstufe = 20
   Wait 5
   Dim_helligkeitsstufe = 30
   Wait 5

   ' Dimmer abschalten
   Gosub Dimmer_aus

   ' Dimmer korrekt initialisieren
   Dim_helligkeitsstufe = Dim_helligkeit_default

   ' Hauptspannung wieder abschalten
   Powerrelais = Relais_aus
   Lichtflag = Licht_aus

   ' *** Temperatursensor ***

   Print #2 , "Funktion: 1Wire-Konfiguration auslesen und ausgeben"
   Gosub Ds1820_konfig_detect

   Print #2 , "Funktion: DS18S20 Teperaturmessung"

   ' Warten bis Temperatur konvertiert
   Waitms Ds1820_delay_time

   Gosub Ds1820_measurement

   Print #2 , "Gemessene Temperatur : " ; Ds1820_temperatur
   Print #2 , ""                                            ' Leerzeile ausgeben

   ' *** RS485 Kommunikation ***

   ' Auf einen Test der RS485 Kommunikation wird verzichtet da er das Gesamtsystem
   ' durch unmotiviertes Senden von Bytes stören kann.

#endif                                                      ' Ende Systemtest

' ----- Scheduler noch korrekt setzen und los -----

' Daten für Temperaturüberwachung setzen
Ds1820_erfassungs_counter = Timercounter + Ds1820_auswertung_start

' #############################################################################
'
'                             Hauptprogramm ConvCtrl
'
' #############################################################################

' ----------------------------------------------
' ----- Hier ist die Programmhauptschleife -----
' ----------------------------------------------

' In Abhängigkeit der Konstante Traceausgabe schreiben
#if Main_testmodus
   Print #2 , "** OK, let's GO **"
#endif

Clear Serialin                                              ' Rx-Buffer löschen
Clear Serialout                                             ' Tx-Buffer löschen

Do

   ' RS485 Buffer auf Empfang prüfen
   Gosub Rs485_receive_check

   ' Wurde ein gültiges Kommando empfangen?
   If Rs485_data_received = True Then
      ' JA

      ' In Abhängigkeit der Konstante Traceausgabe schreiben
      #if Rs485_testmodus
         Print #2 , "Mainloop - Datenpaket empfangen"
      #endif

      ' Datenpaket prozessieren
      Gosub Slave_verarbeitung

   End If                                                   ' Empfangquittierung

   ' RS485 Sendeauftrag prüfen
   If Rs485_send_request = True Then
      ' JA, Senderequest vorhanden, Datenpaket senden

      ' In Abhängigkeit der Konstante Traceausgabe schreiben
      #if Rs485_testmodus
         Print #2 , "Mainloop - Daten sollen gesendet werden"
      #endif

      ' Daten senden
      Gosub Rs485_send

   End If                                                   ' Sendeauftrag

   ' ===== SW Timer Scheduler =====
   Gosub Scheduler

Loop                                                        ' Hauptschleife

'## End Hauptprogramm #########################################################

'******************************************************************************
' Interruptroutinen
'******************************************************************************

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (Timer1): Sekunden_tick
' Routine zur Auswertung des Timer Interrupts
'------------------------------------------------------------------------------
Sekunden_tick:

   ' ----- Programmcode -----

   Incr Timercounter                                        ' Timercounter erhöhen
   Timer1 = Timervorgabe                                    ' Timer neu laden

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Timer_testmodus
      Print #2 , Timercounter
   #endif

   ' Alive-LED toggeln lassen
   Toggle Alive

   ' Prüfen ob Übertemperatur vorliegt
   If Flag_uebertemperatur = True Then

      ' JA -> Übertemperatur -> dann piepsen und blinken
      Toggle Piezo
      Toggle Temp_led

   End If                                                   ' Übertemperatur

Return
'-- End Sekunden_tick  --------------------------------------------------------

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (INT5): Dimmer_null_irq
' Routine zur Nulldurchgangserkennung des Sinussignals
'------------------------------------------------------------------------------
Dimmer_null_irq:

   ' ----- Programmcode -----

   ' In dieser IRQ-Routine wird wegen Geschwindigkeit auf Ausgaben verzichtet
   If Free_running_flag = Aktiv Then

      ' IGBT einschalten
      Igbt = Igbt_ein

      ' Ablauftimer für Phasenabschnitt starten
      Start Timer2
      Timer2 = Igbt_schaltzeitpunkte(dim_helligkeitsstufe)

   End If                                                   ' Free_running_flag

Return
'-- End Dimmer_null_irq -------------------------------------------------------

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (Timer0): Dimmer_triac_irq
' Routine zum Zünden des TRIAC
'------------------------------------------------------------------------------
Dimmer_triac_irq:

   ' ----- Programmcode -----

   ' Ablauftimer für Phasenabschnitt stoppen
   Stop Timer2

   ' IGBT abschalten
   Igbt = Igbt_aus

Return
'-- End Dimmer_triac_irq ------------------------------------------------------

'******************************************************************************
' GOSubroutinen
'******************************************************************************

' ***********
' * EEPROM  *
' ***********

'------------------------------------------------------------------------------
' EE-Gosubroutine: Ee_init_internal_eeprom
' Subroutine überprüft die Datenkonsitenz aufgrund des verwendeten Versions-
' Index und führt ggf. eine Grundinitialisierung der Datenstrukturen durch.
'------------------------------------------------------------------------------
Ee_init_internal_eeprom:

   ' ----- Programmcode -----

   ' Wenn Konstante gesetzt Trace Output schreiben
   #if Eeprom_testmodus                                     ' Trace
      Print #2 , "Enter Ee_init_internal_eeprom"
   #endif                                                   ' Trace

   ' Zur Vollständigkeit hier nochmals die Datenstruktur der internen Daten
   ' EE: EEPROM Datenstruktur internes EEPROM - Setting-Daten
   ' Dim Ee_data_version_intern As Eram Byte At &H0000           ' Speicherstelle für Datenversion
   ' Dim Ee_data_temperature As Eram Byte At &H0001              ' Speicherstelle für Temperaturschwelle

   ' Aktuelle Datenversion des internen EEPROM lesen
   Temp_byte_1 = Ee_data_version_intern

   ' Ist die Datenversion korrekt
   If Temp_byte_1 <> Akt_internal_ee_version Then

      ' NEIN, aktuelle Daten neu speichern

      ' Wenn Konstante gesetzt Trace Output schreiben
      #if Eeprom_testmodus                                  ' Trace
         Print #2 , "Ee_init_internal_eeprom: Datenversion intern stimmt nicht"
         Print #2 , "Ee_init_internal_eeprom: Initialisiere internes EEPROM neu!"
      #endif                                                ' Trace

      ' Datenstruktur internes EEPROM entspricht nicht dem aktuellen Stand
      ' => Datenstruktur neu anlegen bzw. neue Defaultwerte setzen.
      Ee_data_version_intern = Akt_internal_ee_version
      Ee_data_temperature = Uebertemperatur_default
   End If                                                   ' Datenversion?

   ' Wenn Konstante gesetzt Trace Output schreiben
   #if Eeprom_testmodus                                     ' Trace

      Print #2 , "Ee_init_internal_eeprom: Setting-Daten internes EEPROM:"

      ' Wert 01
      Temp_byte_1 = Ee_data_version_intern
      Print #2 , "Version Datenstruktur       : " ; Hex(temp_byte_1)

      ' Wert 02
      Temp_byte_1 = Ee_data_temperature
      Print #2 , "Einstellung Uebertemperatur : " ; Hex(temp_byte_1)

   #endif                                                   ' Trace

   ' Übergabe der Daten in gloabel Arbeitsvariablen
   Uebertemperatur = Ee_data_temperature

Return
'-- End Ee_init_internal_eeprom -----------------------------------------------

' **********
' * Dimmer *
' **********

'------------------------------------------------------------------------------
' DIM - Gosub-Routine: Dimmer_konfig
' Subroutine zur Konfiguration des Dimemrs
'------------------------------------------------------------------------------
Dimmer_konfig:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Dimmer_testmodus
      Print #2 , "Enter Dimmer_konfig"
   #endif

   ' PortD.2 als Eingang mit aktivem PullUp konfigurieren
   Config Nulldurchgang_pin = Input
   Nulldurchgang = Pullup_ein

   ' PortD.4 als Ausgang definieren und IGBT abschalten
   Config Igbt_pin = Output
   Igbt = Igbt_aus

   ' Der Interrupt selbst kann nicht in der Gosub-Routine initialisiert werden
   ' sondern muss im Rumpf des Gesamtprogramms initialisiert werden.

   ' Dimmerhelligkeit auf Default einstellen
   Dim_helligkeitsstufe = Dim_helligkeit_default

   ' Triac Zündzeitpunkte aus Tabelle in Datenstruktur laden
   Restore Igbt_schalttabelle
   For Dim_index_counter = 1 To Dim_helligkeitstabellenwerte
      Read Igbt_schaltzeitpunkte(dim_index_counter)

      ' In Abhängigkeit der Konstante Traceausgabe schreiben
      #if Dimmer_testmodus
         Print #2 , "Dimmer_konfig: Zuendwert " ; Dim_index_counter ; " : " ; Igbt_schaltzeitpunkte(dim_index_counter)
      #endif

   Next Dim_index_counter

Return
'-- End Dimmer_konfig ---------------------------------------------------------

'------------------------------------------------------------------------------
' DIM - Gosub-Routine: Dimmer_an
' Subroutine zum Setzen von Parametern für freien Dimmerlauf, gesteuert über
' Nulldurchgangskennung - Dimmer einschalten
'------------------------------------------------------------------------------
Dimmer_ein:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Dimmer_testmodus
      Print #2 , "Enter Dimmer_an"
   #endif

   ' Free_runing wird eingeschaltet
   Free_running_flag = Aktiv

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Dimmer_testmodus
      Print #2 , "Dimmer_ein: Free Running ist aktiv"
   #endif

Return
'-- End Dimmer_an -------------------------------------------------------------

'------------------------------------------------------------------------------
' DIM - Gosub-Routine: Dimmer_aus
' Subroutine zum Setzen von Parametern für freien Dimmerlauf, gesteuert über
' Nulldurchgangskennung - Dimmer ausschalten
'------------------------------------------------------------------------------
Dimmer_aus:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Dimmer_testmodus
      Print #2 , "Enter Dimmer_aus"
   #endif

   ' Free_running wird ausgeschaltet
   Free_running_flag = Passiv

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Dimmer_testmodus
      Print #2 , "Dimmer_aus: Free Running ist passiv"
   #endif

Return
'-- End Dimmer_aus -------------------------------------------------------------

' ****************************
' * DS1820: Temperatursensor *
' ****************************

'------------------------------------------------------------------------------
' Ds1820 - Gosub-Routine: Ds1820_konfig
' Funktion konfiguriert den Ds1820 temperatursensor bzw. ermittelt für globale
' Variaben die relevanten Arbeitswerte
'------------------------------------------------------------------------------
Ds1820_konfig:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Temp_testmodus
      Print #2 , "Enter Ds1820_konfig"
   #endif

   ' Auslesen  der Anzahl aller am 1Wire-Bus vorhandenen Devices
   Ds1820_device_count = 1wirecount()

   ' Auslesen des 64-Bit breiten ROM Codes für gefundenes Device in Array
   Ds1820_rom_code(1) = 1wsearchfirst()

Return
'-- End Ds1820_konfig ---------------------------------------------------------

'------------------------------------------------------------------------------
' DS1820 - Gosub-Routine: Ds1820_start_measurement
' Funktion startet globale Temperaturmessung für alle Sensoren
'------------------------------------------------------------------------------
Ds1820_start_measurement:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Temp_testmodus
      Print #2 , "Enter Ds1820_start_measurement"
   #endif

   ' Gobales Fehlerflag zurücksetzen
   Ds1820_error_flag = 0

   1wreset                                                  ' 1Wire Master fährt RESET

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Temp_testmodus
      Ds1820_error_flag = Err                               ' Fehlerflag übergeben
      Print #2 , "Ds1820_start_measurement: Reset-ERR : " ; Ds1820_error_flag
   #endif

   ' Alle angeschlossenen DS18S20 zum Messen veranlassen
   1wwrite Ds1820_skip_rom_command                          ' Senden von Skip ROM command
   1wwrite Ds1820_convert_t_command                         ' Convert T

Return
'-- End Ds1820_start_measurement ----------------------------------------------

'------------------------------------------------------------------------------
' DS1820 - Gosub-Routine: Ds1820_measurement
' Funktion startet globale Temperaturmessung für alle Sensoren und macht
' Auswertung auf aktiven Sensor
'------------------------------------------------------------------------------
Ds1820_measurement:

   ' ----- Programmcode -----

   ' Achtung:
   ' Aus dieser Routine wurde die Funktion zum Starten der Messung entfernt.
   ' Zwischen Start und Auswertung benötigt der Chip eine Zeit von ca. 750 ms
   ' Diese Zeit wir bei normalem Systemstart durch den Scheduler eingehalten.
   ' Der erste Messwert der Temperatur nach Systemstart ist erst nach Scheduleraufruf
   ' ca. 5 Sekunden später vorhanden.

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Temp_testmodus
      Print #2 , "Enter Ds1820_measurement"
   #endif

   ' Measurement starten
   Gosub Ds1820_start_measurement

   ' Den Sensor auswählen
   1wverify Ds1820_rom_code(1)

   ' Kommando Scratch-Pad aus Sensor auslesen
   1wwrite Ds1820_scratchpad_command                        ' Senden des Lesekommandos

   ' Scratchpad aus Sensor auslesen
   Ds1820_scratchpad(1) = 1wread(9)

   ' CRC Überprüfung und Messert berechnen
   If Ds1820_scratchpad(9) = Crc8(ds1820_scratchpad(1) , 8) Then

      ' Messung war erfolgreich
      Ds1820_messwert = Makeint(ds1820_scratchpad(1) , Ds1820_scratchpad(2))

      ' In Abhängigkeit der Konstante Traceausgabe schreiben
      #if Temp_testmodus
         Print #2 , "Ds1820_measurement: CRC OK, Messwert plausibel"
         Print #2 , "Ds1820_measurement: Integerwert : " ; Ds1820_messwert
      #endif
   Else                                                     ' Messwert erfassen
      ' Es ist ein CRC Fehler aufgetreten

      ' In Abhängigkeit der Konstante Traceausgabe schreiben
      #if Temp_testmodus
         Print #2 , "Ds1820_measurement: CRC Fehler bei Messwert aufgetreten"
      #endif

      Ds1820_messwert = &HFFCE                              ' Temperaturwert auf -25°C als Fehlerkennzeichnung
   End If                                                   ' Fehlerbehandlung

   Temp_single_1 = Ds1820_messwert                          ' Temperatur auslesen und aufrunden
   Temp_single_1 = Temp_single_1 * 0.5

   Ds1820_temperatur = Temp_single_1                        ' Temperatur auf Byte casten

   #if Temp_testmodus
      Print #2 , "Ds1820_measurement: Temperaturwert : " ; Ds1820_temperatur ; " {248}C"
   #endif

Return
'-- End Ds1820_measurement ----------------------------------------------------

'------------------------------------------------------------------------------
' DS1820 - Gosub-Routine: Ds1820_konfig_detect
' Funktion liest alle relevanten und verfügbaren 1-Wire Konfigurationsinfor-
' mationen aus und gibt diese aus
'------------------------------------------------------------------------------
Ds1820_konfig_detect:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Temp_testmodus
      Print #2 , "Enter Ds1820_konfig_detect"
   #endif

   ' Ausgabe der Anzahl aller am 1Wire-Bus vorhandenen Devices
   Print #2 , "Ds1820_konfig_detect: Anzahl 1Wire-Devices: " ; Ds1820_device_count

   ' Überprüfen ob empfangener Code gemäß CRC korrekt
   Temp_byte_1 = Crc8(ds1820_rom_code(1) , 7 )
   If Ds1820_rom_code(8) = Temp_byte_1 Then

      Print #2 , "Ds1820_konfig_detect: CRC des empfangenen ROM-Codes OK"
      ' Empfangenen Bytes in Hex ausgeben
      Print #2 , "Ds1820_konfig_detect: ROM-Code : " ;

      For Temp_byte_2 = 8 To 1 Step -1
         Print #2 , Hex(ds1820_rom_code(temp_byte_2)) ; " " ;
      Next Temp_byte_2

      Print #2 , ""
   Else                                                     ' Konfiguration ausgeben
      Print #2 , "Ds1820_konfig_detect: CRC des empfangenen ROM-Codes FALSCH"
   End If                                                   ' Fehlerbehandlung

Return
'-- End Ds1820_konfig_detect --------------------------------------------------

' *******************
' * RS485 Systembus *
' *******************

'------------------------------------------------------------------------------
' Gosub-Routine: Rs485_receive_check
' Routine überprüft ob im Empfangsbuffer Zeichen vorliegen, liest diese und
' baut die Empfangsstruktur auf. Danach wird ein Flag gesetzt, dass eine
' Botschafft erfolgreich empfangen wurde.
' Das Empfangen neuer Botschaften ist über eine Sempahore verriegelt. Erst
' wenn die Empfangene Botschaft verarbeitet ist, wird der Empfang einer neuen
' Botschaft zugelassen.
'------------------------------------------------------------------------------
Rs485_receive_check:

   ' ----- Programmcode -----

   ' Prüfen ob noch ein Datenpaket auf Verarbeitung wartet
   If Rs485_data_received = False Then

      ' NEIN, es wartet kein Datenpaket mehr auf Verarbeitung,
      ' die neuen Daten können empfangen werden

      ' Prüfen ob eib Zeichen im Empfangsbuffer wartet
      If Ischarwaiting(#1) <> 0 Then

         ' JA, es wartet ein Zeichen

         ' Prüfen ob Zeichen erstes Zeichen ist, wenn JA dann Überwachung starten
         If Rx_bufferindex = 1 Then

            ' JA Rx_bufferindex ist 1, damit wurde noch kein Zeichen empfangen

            '  Nun Timer aufziehen für Überwachung des Empfangs und Flag setzen
            Receive_timeout_flag = True                     ' Timeout aktvieren
            Receive_timeout_counter = Timercounter + Receive_timeout

            ' ggf. Trace ausgeben
            #if Empfangsueberwachung_testmodus
               Print #2 , "Rs485_receive_check: Starte Receive-Ueberwachung"
            #endif
         End If                                             ' Erstes Zeichen empfangen

         ' Zeichen in RF-RX-Buffer einlesen
         Rx_buffer(rx_bufferindex) = Inkey(#1)

         Incr Rx_bufferindex

         ' Prüfen ob ausreichende Anzahl von Bytes empfangen
         If Rx_bufferindex > Nachrichtenlaenge Then

            ' Timerüberachung deaktivieren
            'Receive_timeout_flag = False

            'Alle Datenfelder komplett empfangen
            Rx_bufferindex = 1                              'Index zurücksetzen

            ' Prüfung ob Checksumme gültig
            Temp_word_1 = Crc16(rx_buffer(1) , 8)
            If Temp_word_1 = Rx_checksumme Then

               ' JA, Checksumme ist korrekt

               ' In Abhängigkeit der Konstante Traceausgabe schreiben
               #if Rs485_testmodus
                  Print #2 , "Rs485_receive_check: CRC korrekt!"
               #endif

               ' Prüfung ob empfangenes Datenpaket auch für "mich"
               If Rx_zieladresse = Rs485_slaveadresse Or Rx_zieladresse = Broadcastadresse Then

                  ' JA, ich bin gemeint

                  ' In Abhängigkeit der Konstante Traceausgabe schreiben
                  #if Rs485_testmodus
                     Print #2 , "Rs485_receive_check:"
                     Print #2 , "Rx_zieladresse  : " ; Hex(rx_zieladresse)
                     Print #2 , "Rx_quelladresse : " ; Hex(rx_quelladresse)
                     Print #2 , "Rx_framelength  : " ; Hex(rx_framelength)
                     Print #2 , "Rx_kommando     : " ; Hex(rx_kommando)
                     Print #2 , "Rx_licht        : " ; Hex(rx_licht)
                     Print #2 , "Rx_dimmstufe    : " ; Hex(rx_dimmstufe)
                     Print #2 , "Rx_temperatur   : " ; Hex(rx_temperatur)
                     Print #2 , "Rx_sound        : " ; Hex(rx_sound)
                     Print #2 , "Rx_checksumme   : " ; Hex(rx_checksumme)
                     Print #2 , " "
                  #endif

                  ' In Abhängigkeit der Konstante Traceausgabe schreiben
                  #if Rs485_testmodus
                     Print #2 , "Rs485_receive_check: Message für mich!"
                  #endif

                  ' prüfen ob Broadcast
                  If Rx_zieladresse = Broadcastadresse Then
                     #if Rs485_testmodus
                        Print #2 , "Rs485_receive_check: Broadcastmessage -> kein ACK"
                     #endif
                     Rs485_broadcastflag = True
                  Else                                      ' Broadcast
                     Rs485_broadcastflag = False
                     #if Rs485_testmodus
                        Print #2 , "Rs485_receive_check: Keine Broadcastmessage -> sende ACK"
                     #endif
                  End If                                    ' Prüfung auf Broadcast

                  ' In Abhängigkeit der Konstante Traceausgabe schreiben
                  #if Rs485_testmodus
                     Print #2 , "Rs485_receive_check: Rx " ; Hex(rx_zieladresse) ; " " ; Hex(rx_quelladresse) ; " " ; Hex(rx_framelength) ; " " ; Hex(rx_kommando) ; " " ; Hex(rx_licht) ; " " ; Hex(rx_dimmstufe) ; " " ; Hex(rx_temperatur) ; " " ; Hex(rx_sound) ; " " ; Hex(rx_checksumme)
                  #endif

                  ' Flag setzen dass Datenpaket empfangen wurde
                  Rs485_data_received = True

               Else                                         ' Datenpaket für mich

                  ' In Abhängigkeit der Konstante Traceausgabe schreiben
                  #if Rs485_testmodus
                     Print #2 , "Rs485_receive_check: CRC falsch!"
                     Print #2 , "Rs485_receive_check: Soll : " ; Hex(temp_word_1)
                     Print #2 , "Rs485_receive_check: Ist  : " ; Hex(rx_checksumme)
                  #endif

                  ' Eingangsbuffer und Ausgangsbuffer löschen
                  Clear Serialin
                  Clear Serialout

               End If                                       ' Ich war nicht gemeint
            End If                                          ' Checksummenprüfung
         End If                                             ' Botschaft vollständig
      End If                                                ' Wartet ein Zeichen?
   End If                                                   ' Verarbeitungssemaphore

Return
'-- End Rs485_receive_check ---------------------------------------------------

'------------------------------------------------------------------------------
' Gosub-Routine: Rs485_send
' Die Routine sendet die in der Sendestruktur stehenden Daten über RS485
'------------------------------------------------------------------------------
Rs485_send:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Rs485_testmodus
      Print #2 , "Enter Rs485_send"
   #endif

   ' Checksumme setzen
   Tx_checksumme = Crc16(tx_buffer(1) , 8)

   ' Bytes übertragen
   Rs485_de = Rs485_send_enable                             ' Treiber auf Leitung schalten
   Printbin #1 , Tx_buffer(1)

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Rs485_testmodus
      Print #2 , "Rs485_send: Tx: " ;
      For Temp_byte_1 = 1 To Nachrichtenlaenge
         Print #2 , Hex(tx_buffer(temp_byte_1)) ; " " ;
      Next Temp_byte_1
      Print #2 , " *"
   #endif

   Waitms Wait_time                                         ' warten bis Datenübertragung beendet
   Rs485_de = Rs485_send_disable                            ' Treiber von Leitung nehmen

   ' Semaphore für das Senden zurücksetzen und erneutes Senden zulassen
   Rs485_send_request = False
Return
'-- End Rs485_send -----------------------------------------------------------

'------------------------------------------------------------------------------
' Gosub-Routine: Rs485_ack_send
' Die Routine sendet ein Acknowledge als Quittierung
'------------------------------------------------------------------------------
Rs485_ack_send:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Rs485_testmodus
      Print #2 , "Enter Rs485_ack_send"
   #endif

   ' Status zurück liefern
   ' Sende-Datenstruktur laden
   Tx_zieladresse = Masteradresse
   Tx_quelladresse = Rs485_slaveadresse
   Tx_framelength = Framelaenge
   Tx_kommando = Resp_ack
   Tx_licht = Free_running_flag
   Tx_dimmstufe = Dim_helligkeitsstufe
   Tx_temperatur = Ds1820_temperatur
   Tx_sound = Soundflag

   #if Rs485_testmodus
      Print #2 , "Rs485_ack_send:"
      Print #2 , "Tx_zieladresse  : " ; Hex(tx_zieladresse)
      Print #2 , "Tx_quelladresse : " ; Hex(tx_quelladresse)
      Print #2 , "Tx_framelength  : " ; Hex(tx_framelength)
      Print #2 , "Tx_kommando     : " ; Hex(tx_kommando)
      Print #2 , "Tx_licht        : " ; Hex(tx_licht)
      Print #2 , "Tx_dimmstufe    : " ; Hex(tx_dimmstufe)
      Print #2 , "Tx_temperatur   : " ; Hex(tx_temperatur)
      Print #2 , "Tx_sound        : " ; Hex(tx_sound)
   #endif

   ' Sendeanforderung setzen
   Rs485_send_request = True

Return
'-- End Rs485_ack_send --------------------------------------------------------

' *********
' * Sound *
' *********

'------------------------------------------------------------------------------
' Sound - Gosub-Routine: Sound_one_beep
' Routine gibt einen einzelnen Beep aus
'------------------------------------------------------------------------------
Sound_one_beep:

   ' ----- Programmcode -----

   ' 1x Peep ausgeben. Peepdauer wird über Konstante gesteuert
   Piezo = Sound_ein
   Waitms Sound_ein_delay
   Piezo = Sound_aus

Return
'-- End Sound_one_beep --------------------------------------------------------

'------------------------------------------------------------------------------
' Sound - Gosub-Routine: Sound_double_beep
' Routine gibt einen zwei Beep's aus
'------------------------------------------------------------------------------
Sound_double_beep:

   ' ----- Programmcode -----

   ' 2x Peep ausgeben. Peepdauer wird über Konstante gesteuert
   Piezo = Sound_ein
   Waitms Sound_ein_delay
   Piezo = Sound_aus
   Waitms Sound_pause_delay
   Piezo = Sound_ein
   Waitms Sound_ein_delay
   Piezo = Sound_aus

Return
'-- End Sound_double_beep -----------------------------------------------------

' *******************
' * Common routines *
' *******************

'------------------------------------------------------------------------------
' Gosub-Routine: Slave_verarbeitung
' Hier werden die via RS485 empfangenen Daten verarbeitet
'------------------------------------------------------------------------------
Slave_verarbeitung:

   ' ----- Programmcode -----

   ' In Abhängigkeit der Konstante Traceausgabe schreiben
   #if Rs485_testmodus
      Print #2 , "Slave_verarbeitung"
   #endif

   ' Übersicht über Verarbeitungstasks
   ' Task 1 = Cmd_licht_schalten
   ' Task 2 = Cmd_dimmer_schalten
   ' Task 3 = Cmd_sound_schalten
   ' Task 4 = Cmd_licht_dimmer_schalten (alles inklusive)
   ' Task 5 = Cmd_status_abfragen
   ' Task 6 = Cmd_uebertemperatur_setzen
   ' Taks 7 = Cmd_demo_sweep

   Select Case Rx_kommando

      ' [ *** Task 1 = Cmd_licht_schalten *** ]
      Case Cmd_licht_schalten:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_licht_schalten"
         #endif

         Select Case Rx_licht

            Case Licht_aus:
               ' Dimmer abschalten
               Gosub Dimmer_aus

               ' Relais abschalten
               Powerrelais = Relais_aus
               Lichtflag = Licht_aus

               ' ggf. Ausgabesound erzeugen
               If Soundflag = Sound_ein Then
                  ' Soundflag gesetzt, darum Doppel-Beep ausgeben
                  Gosub Sound_double_beep
               End If                                       ' Soundprüfung

            Case Licht_ein:
               ' Relais einschalten
               Powerrelais = Relais_ein
               Lichtflag = Licht_ein

               ' Dimmer einschalten
               Gosub Dimmer_ein

               ' ggf. Ausgabesound erzeugen
               If Soundflag = Sound_ein Then

                  ' Soundflag gesetzt, darum Beep ausgeben
                  Gosub Sound_one_beep
               End If                                       ' Soundprüfung

         End Select                                         ' Auswertung Licht

         ' Acknowledge senden
         If Rs485_broadcastflag = False Then
            ' Nur im Fall das es keine Broadcast-Botschaft war ACK senden
            Gosub Rs485_ack_send
         End If                                             ' Acknowledge
      ' [ *** *** ]

      ' [ *** Task 2 = Cmd_dimmer_schalten *** ]
      Case Cmd_dimmer_schalten:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_dimmer_schalten"
         #endif

         ' Aktuelle Variable für Helligkeitsstufe setzen
         Dim_helligkeitsstufe = Rx_dimmstufe

         ' Acknowledge senden
         If Rs485_broadcastflag = False Then
            ' Nur im Fall das es keine Broadcast-Botschaft war ACK senden
            Gosub Rs485_ack_send
         End If                                             ' Acknowledge
      ' [ *** *** ]

      ' [ *** Task 3 = Cmd_sound_schalten *** ]
      Case Cmd_sound_schalten:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_sound_schalten"
         #endif

         ' Aktuelle Variable für Soundausgabe setzten
         Soundflag = Rx_sound

         ' Acknowledge senden
         If Rs485_broadcastflag = False Then
            ' Nur im Fall das es keine Broadcast-Botschaft war ACK senden
            Gosub Rs485_ack_send
         End If                                             ' Acknowledge
      ' [ *** *** ]

      ' [ *** Task 4 = Cmd_licht_dimmer_schalten (alles inklusive) *** ]
      Case Cmd_licht_dimmer_schalten:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_licht_dimmer_schalten"
         #endif

         ' Aktuelle Variable für Helligkeitsstufe setzen
         Dim_helligkeitsstufe = Rx_dimmstufe

         ' Licht schalten
         Select Case Rx_licht

            Case Licht_aus:
               ' Dimmer abschalten
               Gosub Dimmer_aus

               ' Relais abschalten
               Powerrelais = Relais_aus
               Lichtflag = Licht_aus

               ' ggf. Ausgabesound erzeugen
               If Soundflag = Sound_ein Then
                  ' Soundflag gesetzt, darum Doppel-Beep ausgeben
                  Gosub Sound_double_beep
               End If                                       ' Soundprüfung

            Case Licht_ein:
               ' Relais einschalten
               Powerrelais = Relais_ein
               Lichtflag = Licht_ein
               ' Dimmer einschalten
               Gosub Dimmer_ein

               ' ggf. Ausgabesound erzeugen
               If Soundflag = Sound_ein Then

                  ' Soundflag gesetzt, darum Beep ausgeben
                  Gosub Sound_one_beep
               End If                                       ' Soundprüfung

         End Select                                         ' Auswertung Licht

         ' Aktuelle Variable für Sound setzten
         Soundflag = Rx_sound

         ' Acknowledge senden
         If Rs485_broadcastflag = False Then
            ' Nur im Fall das es keine Broadcast-Botschaft war ACK senden
            Gosub Rs485_ack_send
         End If                                             ' Acknowledge
      ' [ *** *** ]

      ' [ *** Task 5 = Cmd_status_abfragen *** ]
      Case Cmd_status_abfragen:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_status_abfragen"
         #endif

         ' Status zurück liefern
         ' Sende-Datenstruktur laden
         Tx_zieladresse = Masteradresse
         Tx_quelladresse = Rs485_slaveadresse
         Tx_framelength = Framelaenge
         Tx_kommando = Resp_status
         Tx_licht = Lichtflag
         Tx_dimmstufe = Dim_helligkeitsstufe
         Tx_temperatur = Ds1820_temperatur
         Tx_sound = Soundflag

         ' Sendeanforderung setzen
         Rs485_send_request = True
      ' [ *** *** ]

      ' [ *** Task 6 = Cmd_uebertemperatur_setzen *** ]
      Case Cmd_uebertemperatur_setzen:

         ' In Abhängigkeit der Konstante Traceausgabe schreiben
         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: Cmd_uebertemperatur_setzen"
         #endif

         ' Aktuelle Variable für Helligkeitsstufe setzen
         Uebertemperatur = Rx_temperatur
         Ee_data_temperature = Uebertemperatur

         ' ggf. Ausgabesound erzeugen
         If Soundflag = Sound_ein Then
            ' Soundflag gesetzt, darum Doppel-Beep ausgeben
            Gosub Sound_double_beep
         End If                                             ' Soundprüfung

         ' Acknowledge senden
         If Rs485_broadcastflag = False Then
            ' Nur im Fall das es keine Broadcast-Botschaft war ACK senden
            Gosub Rs485_ack_send
         End If                                             ' Acknowledge

         #if Main_testmodus
            Print #2 , "Slave_verarbeitung: setze " ; Uebertemperatur
            Temp_byte_1 = Ee_data_temperature
            Print #2 , "Slave_verarbeitung: lese " ; Temp_byte_1
         #endif

      ' [ *** *** ]

      ' [ *** Task 7 = Cmd_demo_sweep *** ]
      Case Cmd_demo_sweep:

         Select Case Rx_licht:

            Case Sweep_down:

               Temp_byte_1 = Dim_helligkeitsstufe
               For Temp_byte_2 = Temp_byte_1 To 1 Step -1
                  Dim_helligkeitsstufe = Temp_byte_2
                  Waitms Demo_sweep_time
               Next Temp_byte_2

            Case Sweep_up:

               For Temp_byte_1 = 1 To 31
                  Dim_helligkeitsstufe = Temp_byte_1
                  Waitms Demo_sweep_time
               Next Temp_byte_2

         End Select

      ' [ *** *** ]

   End Select

   ' Semaphore wieder auf False setzen um nächstes Datenpaket zu empfangen
   Rs485_data_received = False

Return
'-- End Slave_verarbeitung ----------------------------------------------------

'------------------------------------------------------------------------------
' Gosub-Routine: Scheduler
' Subroutine Abprüfen der in RUNNING befindlichen SW-Timer
'------------------------------------------------------------------------------
Scheduler:

   ' ----- Programmcode -----

   ' *** Sequence [01] - Temperaturmessung ***

   ' Überprüfung ob Temperatur gemessen werden kann und soll
   If Ds1820_erfassungs_counter = Timercounter Then

      Gosub Ds1820_measurement

      ' Scheduler erneut setzen
      Ds1820_erfassungs_counter = Timercounter + Ds1820_auswertung

      ' Prüfung auf Übertemperatur
      If Ds1820_temperatur >= Uebertemperatur Then

         ' JA; Übertemperatur

         ' Flag setzen
         Flag_uebertemperatur = True

         ' Dimmer abschalten
         Gosub Dimmer_aus

         ' Relais abschalten
         Powerrelais = Relais_aus

      Else                                                  ' Übertemperatur

         ' Nein, keine Übertemperatur -> Flag auf jeden Fall zurücksetzen
         Flag_uebertemperatur = False
         Piezo = Sound_aus
         Temp_led = Led_aus

      End If                                                ' Übertemperatur
   End If                                                   ' Ende Temperaturmessung

   ' *** Sequence [02] -  Receive-Timeout-Überwachung ***

   ' Prüfen, ob Überwachung gemacht werden muss
   If Receive_timeout_flag = True Then

      ' JA

      ' Prüfen ob Timeout abgelaufen
      If Timercounter > Receive_timeout_counter Then

         ' JA, Timeout abgelaufen

         ' ggf. Trace ausgeben
         #if Empfangsueberwachung_testmodus
            Print #2 , "Scheduler: Loeschen aller Buffer und Datenstrukturen"
         #endif

         ' Timeoutflag zurücksetzen
         Receive_timeout_flag = False

         ' ----- RS485 -----

         ' Sende- und Empfangsstrukturen initialisieren
         Rx_bufferindex = 1                                 ' Index auf 1
         Tx_bufferindex = 1                                 ' Index auf 1
         Rs485_broadcastflag = False                        ' Adresstyp zurücksetzen

         ' Eingangsbuffer und Ausgangsbuffer löschen
         Clear Serialin
         Clear Serialout

      End If                                                ' Timer abgelaufen
   End If                                                   ' Timeourüberwachung aktiv

Return
'-- End Scheduler -------------------------------------------------------------

'------------------------------------------------------------------------------
' Devices schließend und ggf. "Terminate Programm execution"
'------------------------------------------------------------------------------

Close #3                                                    ' RS232 Kanal 3 schließen
Close #2                                                    ' RS232 Kanal 2 schließen
Close #1                                                    ' RS232 Kanal 1 schließen

' System halt
End                                                         'end program

'------------------------------------------------------------------------------
' Definition von globalen Konstantenfeldern
'------------------------------------------------------------------------------

Igbt_schalttabelle:
Data 255 , 234 , 224 , 216 , 210 , 204 , 198 , 193
Data 189 , 185 , 179 , 175 , 171 , 167 , 163 , 159
Data 155 , 151 , 148 , 144 , 140 , 136 , 130 , 126
Data 120 , 116 , 110 , 105 , 99 , 91 , 81 , 60

' ----------------------------------------------------------------------------

'###################################### END ###################################

'################################### Historie #################################
' 01.08.2010 : Version 0.0
'              Beginn der Implementierungen für StarLight
' 14.02.2011 : Version 1.0
'              Erste inbetriebgenommene Gesamtversion
'##############################################################################