'##############################################################################
' HygroTherm.BAS                                               Stand 16.02.2020
' --------------                                               (C) Markus Fulde
'
' Programm für Thermometer und Hygrometer auf Basis eines Sensirion SH85
'
' Das Projekt verfügt über die folgenden einzelnen Funktions- und
' Teilkomponenten:
'     - Spannungsversorgung für +5V
'     - Mikrocontroller ATmega16 (inkl. ISP, RS232 und Reset)
'     - LCD-Display 16x2
'     - LED-Anzeigen für Funktionsanzeige
'     - I2C Sensor Sensirion SHT85
'
'##############################################################################

'------------------------------------------------------------------------------
' Allgemeine Zusatzinformationen zu Programmbeginn
'------------------------------------------------------------------------------

' DDRAM Adressen des Display (in HEX)
'
' Zeichen:    1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16
' Zeile 1:   00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F
' Zeile 2:   40  41  42  43  44  45  46  47  48  49  4A  4B  4C  4D  4E  4F

' HD44780 Befehlssatz
'
' Befehl                          Rs   Rw   D7   D6   D5   D4   D3   D2   D1   D0
' -------------------------------------------------------------------------------
' Bildschirminhalt Löschen        0    0    0    0    0    0    0    0    0    1
' Cursor Auf Startpos             0    0    0    0    0    0    0    0    1    X
' Modus Festlegen                 0    0    0    0    0    0    0    1    I/D  S
' Display/Cursor                  0    0    0    0    0    0    1    D    C    B
' Cursor/Display Schieben         0    0    0    0    0    1    S/C  R/L  X    X
' Funktionen                      0    0    0    0    1    DL   N    F    X    X
' Cgram Adresse Setzen            0    0    0    1    +     CGRAM-Adresse      +
' Ddram Adresse Setzen            0    0    1    +          DDRAM-Adresse      +
' Adresse/Status Lesen            0    1    BF   +      CG-/DDRAM-Adresse      +
' Daten In Ddram/Cgram Schreiben  1    0    +                 Daten            +
' Daten Aus Ddram/Cgram Lesen     1    1    +                 Daten            +

' Kodierung der Steuerbits
'
' Bit  |   0 = LOW                       |  1 = HIGH
' -----+---------------------------------+---------------------------------
' I/D  |  Cursorposition dekrementieren  |  Cursorposition inkrementieren
' S    |  Displayinhalt fest             |  Displayinhalt weiterschieben
' D    |  Display aus                    |  Display an
' C    |  Cursor aus                     |  Cursor an
' B    |  Cursor blinkt nicht            |  Cursor blinkt
' S/C  |  Cursor bewegen                 |  Displayinhalt schieben
' R/L  |  Nach links schieben            |  Nach rechts schieben
' DL   |  4-Bit Interface                |  8-Bit Interface
' N    |   1-zeiliges Display            |  2/4-zeiliges Display
' F    |  5×7-Font                       |  5×10-Font
' BF   |  Kann Kommandos annehmen        |  Ist beschäftigt

' Description of the SHT85 status register

' Bit  Field description                                              Default value
' =================================================================================
' 15   Alert pending status                                           '1'
'      '0': no pending alerts
'      '1': at least one pending alert
' ---------------------------------------------------------------------------------
' 14   Reserved                                                       '0'
' ---------------------------------------------------------------------------------
' 13   Heater status                                                  '0'
'      '0' : Heater OFF
'      '1' : Heater ON
' ---------------------------------------------------------------------------------
' 12   Reserved                                                       '0'
' ---------------------------------------------------------------------------------
' 1    RH tracking alert                                              '0'
'      '0' : no alert
'      '1' . alert
' ---------------------------------------------------------------------------------
' 10   T tracking alert                                               '0'
'      '0' : no alert
'      '1' . alert
' ---------------------------------------------------------------------------------
' 9:5  Reserved                                                       'xxxxx'
' ---------------------------------------------------------------------------------
' 4      System reset detected                                        '0'
'      '0': no reset detected since last 'clear status register' command
'      '1': reset detected (hard reset, soft reset command or supply fail)
' ---------------------------------------------------------------------------------
' 3:2  Reserved                                                       '00'
' ---------------------------------------------------------------------------------
' 1    Command status                                                 '0'
'      '0': last command executed successfully
'      '1': last command not processed. It was either invalid,  failed the
'           integrated command checksum
' ---------------------------------------------------------------------------------
' 0    Write data checksum status                                     '0'
'      '0': checksum of last write transfer was correct
'      '1': checksum of last write transfer failed
' ---------------------------------------------------------------------------------

'------------------------------------------------------------------------------
' Compilerinstruktionen und Compilerdirektiven
'------------------------------------------------------------------------------
$regfile = "m16def.dat"                                     ' Definitionsdatei für ATmega128 laden
$crystal = 8000000                                          ' Quarzfrequenz 8 MHz intern festlegen

$hwstack = 128                                              ' HW-Stack auf 128 Bytes erweitern
$swstack = 64                                               ' SW-Stack auf 64 Bytes erweitern

$framesize = 80                                             ' Framesize auf 80 Byte festlegen

' Serielle Schnittstelle wird für Tracedatenausgabe verwendet
$baud = 38400                                               ' Baudrate für RS232 auf 38400 Bauf festlegen

' Einbinden der I2C-Library für das Hardware-Interface des ATmega
$lib "i2c_twi.lbx"                                          ' we do not use software emulated I2C but the TWI

' Instruct the compiler to generate very short Enable pulse for VFO displays.
' $lcdvfo !! NOT USED for 1602 Display in this Project because of identified issues during cold boot

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

' ----- LED: Anzeige-LED's -----

' Die Alive-LED wird sekündlich getoggelt um zu zeigen, dass der µC noch lebt
Alive_pin Alias Pinb.0                                      ' GPIO für Alive-LED (für DDR oder Input)
Alive Alias Portb.0                                         ' GPIO für Alive-LED (für Output oder Pullup)

' ----- LCD-Display -----

' LCD-Display
Db0_pin Alias Porta.0                                       ' GPIO für LCD Pin4
Db1_pin Alias Porta.1                                       ' GPIO für LCD Pin4
Db2_pin Alias Porta.2                                       ' GPIO für LCD Pin4
Db3_pin Alias Porta.3                                       ' GPIO für LCD Pin4
Db4_pin Alias Porta.4                                       ' GPIO für LCD Pin4
Db5_pin Alias Porta.5                                       ' GPIO für LCD Pin5
Db6_pin Alias Porta.6                                       ' GPIO für LCD Pin6
Db7_pin Alias Porta.7                                       ' GPIO für LCD Pin7
Lcd_data_port Alias Porta                                   ' Gesamter PORTA ist Datenport

Lcd_rs_pin Alias Portb.3                                    ' GPIO für LCD RS
Lcd_e_pin Alias Portb.2                                     ' GPIO für LCD E

' Der RW Pin kann auch direkt mit GND verbunden werden da BASCOM nicht vom
' LCD lesen kann. Hierzu wäre eine 3rd-Party-LIB notwendig.
Lcd_rw_pin Alias Pinb.1                                     ' GPIO für LCD RW
Lcd_rw Alias Portb.1

' ----- I2C: Two wire interface -----
' TWI-Bus Hardware für Ultraschallmodul
Sda_port Alias Portc.1                                      ' TWI Data = SDA-Pin (für Output oder PullUp)
Scl_port Alias Portc.0                                      ' TWI Clock = SCL-Pin (für Output oder PullUp)

' ----- FAN: Lüfter -----
Luefter_pin Alias Pind.7                                    ' GPIO für Lüftersteuerung (für DDR oder Input)
Luefter Alias Portd.7                                       ' GPIO für Lüftersteuerung (für Output oder Pullup)

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

' ----- Für Testumgebung bzw. Traceausgaben -----

Const Main_testmodus = 1                                    ' Flag für Testmodus Allgemeinsystem
Const Sht_testmodus = 1                                     ' Flag für Testmodus des Sensirion Sensors

' ----- Allgemeine Systemkonstanten -----

' Tatsächliches Allgemeines
Const False = 0
Const True = 1

Const Pegel_low = 0
Const Pegel_high = 1

Const Led_aus = 0
Const Led_ein = 1

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

' ----- SHT85 Humidity and Temperatur Sensor -----

' SHT:  Adressen für das Sensirion Sensor-Modul

' Standardadresse ist &HE0 = &B11100000
Const Sht_address_write = &B10001000                        ' Adresse des SHT85 = &H44 (schreiben)
Const Sht_address_read = &B10001001                         ' Adresse des SHT85 = &H45 (lesen)

' Measurement Commands for Single Shot Data Acquisition Mode
Const Sht_cmd_single_rep_high_msb = &H24                    ' repeatability High
Const Sht_cmd_single_rep_high_lsb = &H00

Const Sht_cmd_single_rep_medium_msb = &H24                  ' repeatability Medium
Const Sht_cmd_single_rep_medium_lsb = &H0B

Const Sht_cmd_single_rep_low_msb = &H24                     ' repeatability Low
Const Sht_cmd_single_rep_low_lsb = &H16

' Measurement Commands for Periodic Data Acquisition Mode
Const Sht_cmd_cycle_05_rep_high_msb = &H20                  ' 0.5 mps repeatability High
Const Sht_cmd_cycle_05_rep_high_lsb = &H32
Const Sht_cmd_cycle_05_rep_medium_msb = &H20                ' 0.5 mps repeatability Medium
Const Sht_cmd_cycle_05_rep_medium_lsb = &H24
Const Sht_cmd_cycle_05_rep_low_msb = &H20                   ' 0.5 mps repeatability Low
Const Sht_cmd_cycle_05_rep_low_lsb = &H2F

Const Sht_cmd_cycle_1_rep_high_msb = &H21                   ' 1 mps repeatability High
Const Sht_cmd_cycle_1_rep_high_lsb = &H30
Const Sht_cmd_cycle_1_rep_medium_msb = &H21                 ' 1 mps repeatability Medium
Const Sht_cmd_cycle_1_rep_medium_lsb = &H26
Const Sht_cmd_cycle_1_rep_low_msb = &H21                    ' 1 mps repeatability Low
Const Sht_cmd_cycle_1_rep_low_lsb = &H2D

Const Sht_cmd_cycle_2_rep_high_msb = &H22                   ' 2 mps repeatability High
Const Sht_cmd_cycle_2_rep_high_lsb = &H36
Const Sht_cmd_cycle_2_rep_medium_msb = &H22                 ' 2 mps repeatability Medium
Const Sht_cmd_cycle_2_rep_medium_lsb = &H20
Const Sht_cmd_cycle_2_rep_low_msb = &H22                    ' 2 mps repeatability Low
Const Sht_cmd_cycle_2_rep_low_lsb = &H2B

Const Sht_cmd_cycle_4_rep_high_msb = &H23                   ' 4 mps repeatability High
Const Sht_cmd_cycle_4_rep_high_lsb = &H34
Const Sht_cmd_cycle_4_rep_medium_msb = &H23                 ' 4 mps repeatability Medium
Const Sht_cmd_cycle_4_rep_medium_lsb = &H22
Const Sht_cmd_cycle_4_rep_low_msb = &H23                    ' 4 mps repeatability Low
Const Sht_cmd_cycle_4_rep_low_lsb = &H29

Const Sht_cmd_cycle_10_rep_high_msb = &H27                  ' 10 mps repeatability High
Const Sht_cmd_cycle_10_rep_high_lsb = &H37
Const Sht_cmd_cycle_10_rep_medium_msb = &H27                ' 10 mps repeatability Medium
Const Sht_cmd_cycle_10_rep_medium_lsb = &H21
Const Sht_cmd_cycle_10_rep_low_msb = &H27                   ' 10 mps repeatability Low
Const Sht_cmd_cycle_10_rep_low_lsb = &H2A

' Readout of Measurement Results for Periodic Mode
Const Sht_cmd_fetch_data_msb = &HE0                         ' Fetch Data command for Periodic Mode
Const Sht_cmd_fetch_data_lsb = &H00

' ART Command
Const Sht_cmd_art_msb = &H2B                                ' accelerated response time
Const Sht_cmd_art_lsb = &H32

' Break command / Stop Periodic Data Acquisition Mode
Const Sht_cmd_break_msb = &H30                              ' Break command
Const Sht_cmd_break_lsb = &H93

' Reset
Const Sht_cmd_reset_msb = &H30                              ' Soft Reset / Re-Initialization
Const Sht_cmd_reset_lsb = &HA2

' General i2c Reset
Const Sht_adr_i2c_reset = &H00
Const Sht_cmd_i2c_reset = &H06                              ' Reset through General Call

' Heater
Const Sht_cmd_heater_msb = &H30                             ' Heater command
Const Sht_cmd_heater_lsb_enable = &H6D                      ' Heater Enable
Const Sht_cmd_heater_lsb_disable = &H66                     ' Heater Disabled

' Read Out of status register
Const Sht_cmd_status_msb = &HF3                             ' Status Register
Const Sht_cmd_status_lsb = &H2D

' Clear Status Register
Const Sht_cmd_clear_status_msb = &H30                       ' Clear Status Register
Const Sht_cmd_clear_status_lsb = &H41

' Command to read out the Serial Number
Const Sht_cmd_read_serial_msb = &H36                        ' Get Serial Number
Const Sht_cmd_read_serial_lsb = &H82

' SHT command - read idle Zeit
Const Sht_t_idle = 2                                        'Idle Zeit nach command bis read

' SHT Messzyklus-Zeit
Const Sht_measurement_speed = 30                            ' Zeit in Sekunden
Const Sht_t_meas = 20                                       ' zeit in ms

' ----- FAN: Luefetersteuerung -----

Const Luefter_ein = 1
Const Luefter_aus = 0

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

' ----- Allgemeine systembedingte globale Variablen -----

' temporäre globale Arbeitsvariablen
Dim Temp_byte_1 As Byte                                     ' Temporäre Byte-Variable 1
Dim Temp_byte_2 As Byte                                     ' Temporäre Byte-Variable 2

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

Dim Temp_string As String * 32                              ' Temporärer String

' ----- Systemvariablen für SHT85 -----

' This is how it will be stored in SRAM
' 7------ Sht_serial_number ------>
' +-------+-------+-------+-------+
' | snb_0 | snb_1 | snb_23| snb_3 |
' +-------+-------+-------+-------+

'But when you print it with print bin(Variable) you will see it as

' <------ Sht_serial_number ------>
' +-------+-------+-------+-------+
' | snb_3 | snb_2 | snb_1 | snb_0 |
' +-------+-------+-------+-------+

Dim Sht_crc_byte As Byte                                    ' Arbeitsvaraible für Checksumme
Dim Sht_error_flag As Byte                                  ' Flag für Fehler während I2C Kommunikation

Dim Sht_status_flags As Word                                ' 16 Bit Status Flags des SHT85
Dim Sht_status_lsb As Byte At Sht_status_flags Overlay      ' LSB
Dim Sht_status_msb As Byte At Sht_status_flags + 1 Overlay  ' MSB

Dim Sht_serial_number As Dword                              ' SHT86 Serial number
Dim Sht_snb_0 As Byte At Sht_serial_number Overlay          ' LSB
Dim Sht_snb_1 As Byte At Sht_serial_number + 1 Overlay
Dim Sht_snb_2 As Byte At Sht_serial_number + 2 Overlay
Dim Sht_snb_3 As Byte At Sht_serial_number + 3 Overlay      ' MSB

Dim Sht_temperature_word As Word
Dim Sht_temperature_lsb As Byte At Sht_temperature_word Overlay       ' LSB
Dim Sht_temperature_msb As Byte At Sht_temperature_word + 1 Overlay       'MSB

Dim Sht_humidity_word As Word
Dim Sht_humidity_lsb As Byte At Sht_humidity_word Overlay   ' LSB
Dim Sht_humidity_msb As Byte At Sht_humidity_word + 1 Overlay       ' MSB

Dim Sht_temperature_float As Single                         ' Berechnete Temperatur
Dim Sht_humidity_float As Single                            ' Berechnete Feuchtigkeit

'------------------------------------------------------------------------------
' Prototyping
'------------------------------------------------------------------------------

' ========== Funktionen ==========

' ----- Allgemeine Funktionen -----

' ========== Sub-Funktionen ==========

' ----- Fehlerbehandlung -----
Declare Sub Sht_error_handling(byval Error_string As String )

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

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

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

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

' ----- LCD Display -----

' RW-Ping auf LOW=GND schalten (wird nicht weiter benötigt)
Config Lcd_rw_pin = Output
Lcd_rw = Pegel_low

' Konfiguration LCD Display

Config Lcdpin = Pin , Port = Lcd_data_port , E = Lcd_e_pin , Rs = Lcd_rs_pin
Config Lcdbus = 8                                           ' LCD arbeitet über 8-Bit

Config Lcd = 16 * 2                                         ' Display is 2-zeilig mit 16 Zeichen

Initlcd                                                     ' LCD initialisieren
Waitms 100                                                  ' 100ms nach Init warten
Cursor Off Noblink                                          ' Blinkenden Cursor abschalten

Cls

' ----- Sensirion SHT85 Sensor -----

' Konfiguration I2C-Bus
Config Sda = Sda_port                                       ' TWI SDA = Data
Config Scl = Scl_port                                       ' TWI SCL = Clock

I2cinit                                                     ' we need to set the pins in the proper state

' Achtung: Die genaue TWI Frequenz des SRF08 ist nicht klar und ergeht auch nicht aus
' dem Datenblatt. Der referenzierte Speicherbaustein kann 100 kBaud. Aus diesem Grund
' wird die Geschwindigkeit zunächst auf diese Geschwindigkeit begrenzt.

Config Twi = 100000                                         ' Taktfrequenz 100 kBaud

' TWI gleich einschalten, das macht BASCOM ansonsten erst beim I2CStart
Twcr = &B00000100                                           ' nur TWEN setzen

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

' ----- LED-Konfigurationen -----

Config Alive_pin = Output                                   ' GPIO für Alive-LED ist Output

' ----- Luefeter-Steuerung -----

Config Luefter_pin = Output                                 ' GPIO für Lüfter auf Output schalten
Luefter = Luefter_aus                                       ' Lüfter ausschalten

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

Sht_error_flag = False

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

' In Abhängigkeit der Konstante Traceausgabe schreiben
#if Main_testmodus
   ' Systemstart auf RS232 ausgeben
   Print ""
   Print ""
   Print "********** Iginiton sequence start **********"
#endif

' ----- Freigabe aller Interrupts ----

' Timer aktivieren und Interrupts freigeben
Enable Timer1
Enable Interrupts                                           ' Damit auch Empfang von Daten über Buffer

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

' #############################################################################
'
'                    Hauptprogramm Thermometer Gygrometer
'
' #############################################################################

' Disclaimer auf LCD anzeigen
Cls                                                         ' Clear Screen
Home                                                        ' Place the cursor at the specified line at location 1.

'                    1234567890123456
Locate 1 , 1 : Lcd "HygroTherm  V1.0"
Locate 2 , 1 : Lcd "Markus Fulde '20"
Wait 3

Cls

' Seriennummer des SHT85 auslesen und anzeigen
Gosub Sht_read_serial_number
If Sht_error_flag = True Then
   '                         1234567890123456
   Call Sht_error_handling( "ReadSerialNumber" )
End If

' Statusbytes des SHT85 auslesen und anzeigen
Gosub Sht_read_status_bytes
If Sht_error_flag = True Then
   '                         1234567890123456
   Call Sht_error_handling( "ReadStatusFlags " )
End If

'                    1234567890123456
Locate 1 , 1 : Lcd "Serial: " ; Hex(sht_serial_number)
Locate 2 , 1 : Lcd Bin(sht_status_flags)
Wait 3

Cls

'                    1234567890123456
Locate 1 , 1 : Lcd "Temp  [" ; Chr(223) ; "C]: 00.0"
Locate 2 , 1 : Lcd "rel.F. [%]: 00.0"

' Lüfter einschalten
#if Main_testmodus                                          ' Trace
   Print "Luefter EIN"
   Print ""
#endif                                                      ' Trace

Luefter = Luefter_ein

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

' Controll-Output schreiben und los's gehts
#if Main_testmodus                                          ' Trace
   Print ""
   Print "** Enter MainLoop **"
   Print ""
#endif                                                      ' Trace

Do

   ' --------------------------------- Messung --------------------------------

   ' SHT85 Messung durchführen
   Gosub Sht_measurement
   If Sht_error_flag = True Then
      '                         1234567890123456
      Call Sht_error_handling( "SHT85Measurement-" )
   End If

   ' -------------------------------- Auswertung ------------------------------

   ' Messwerte auf Display schreiben
   If Sht_temperature_float <= -10 Then
      Locate 1 , 12 : Lcd Fusing(sht_temperature_float , "###.#" )
   Else
      Locate 1 , 13 : Lcd Fusing(sht_temperature_float , "##.#" )
   End If

   Locate 2 , 13 : Lcd Fusing(sht_humidity_float , "##.#" )

   ' ---------------------------------- Warten --------------------------------

   ' Bis nächste Messunge warten
   Wait Sht_measurement_speed

Loop

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

End                                                         ' Terminate program execution.

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

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

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

   Timer1 = Timervorgabe                                    ' Timer neu laden
   Toggle Alive                                             ' Alive-LED toggeln lassen

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

'******************************************************************************
' Funktionen
'******************************************************************************

'******************************************************************************
' Subroutinen
'******************************************************************************

' *********************
' * SHT85: Sensirion  *
' *********************

'------------------------------------------------------------------------------
' SHT - Suboutine: Sht_read_serial_number
'
' Funktion gibt einen Fehlertext auf dem Display aus und hält die Ausfrührung
' des Programm an.
'------------------------------------------------------------------------------
Sub Sht_error_handling(byval Error_string As String )

   ' ----- Locale Variablen -----

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

   Cls                                                      ' Bildschirm löschen

   ' Fehlertext ausgeben

   '                   1234567890123456
   Locate 1 , 1 : Lcd "I2C Comm Failure"
   Locate 2 , 1 : Lcd Error_string

   ' Terminate program execution.
   End

End Sub
'-- End Sht_read_serial_number ------------------------------------------------

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

' *********************
' * SHT85: Sensirion  *
' *********************

'------------------------------------------------------------------------------
' SHT - Gosub-Routine: Sht_read_serial_number
'
' Funktion liest die Seriennummer des Sensor aus und schreibt diese in eine
' globale Variable.
'------------------------------------------------------------------------------
Sht_read_serial_number:

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

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "++Enter Sht_read_serial_number"
   #endif

   ' Error flag zurücksetzen
   Sht_error_flag = False

   I2cstart                                                 ' START-Sequenz senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_write                               ' Daten schreiben initiieren
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_read_serial_msb                         ' MSB schreiben
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_read_serial_lsb                         ' LSB schreiben
   If Err = 1 Then Sht_error_flag = True

   ' I2cstop                                                  ' STOP-Bedingung wird nicht zwingend gefordert

   Waitms Sht_t_idle

   ' Hinweis: Auf die Auswertung der CRC wird verzichtet.
   '          Keine Sicherheitskritische Umsetzung

   I2cstart                                                 ' START-Sequenz erneut senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_read                                ' Daten lesen initiieren
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_snb_3 , Ack                                 ' Byte 3 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_snb_2 , Ack                                 ' Byte 2 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_crc_byte , Ack                              ' Checksumme lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_snb_1 , Ack                                 ' Byte 3 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_snb_0 , Ack                                 ' Byte 2 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_crc_byte , Ack                              ' Checksumme lesen
   If Err = 1 Then Sht_error_flag = True

   I2cstop                                                  ' STOP-Sequenz

   ' Seriennummer verarbeiten und ggf. auf RS232 ausgeben

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "Serial Number : " ; Hex(sht_serial_number)
   #endif

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "--Leaving Sht_read_serial_number"
      Print ""
   #endif

Return
'-- End Sht_read_serial_number -----------------------------------------------

'------------------------------------------------------------------------------
' SHT - Gosub-Routine: Sht_read_status_bytes
' Funktion liest die Statusregister des SHT85 aus und speichert diese in einer
' globalen Variable.
'------------------------------------------------------------------------------
Sht_read_status_bytes:

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

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "++Enter Sht_read_status_bytes"
   #endif

   ' Error flag zurücksetzen
   Sht_error_flag = False

   I2cstart                                                 ' START-Sequenz senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_write                               ' Daten schreiben initiieren
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_status_msb                              ' MSB schreiben
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_status_lsb                              ' LSB schreiben
   If Err = 1 Then Sht_error_flag = True

   ' I2cstop                                                  ' STOP-Bedingung wird nicht zwingend gefordert

   Waitms Sht_t_idle

   ' Hinweis: Auf die Auswertung der CRC wird verzichtet.
   '          Keine Sicherheitskritische Umsetzung

   I2cstart                                                 ' START-Sequenz erneut senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_read                                ' Daten lesen initiieren
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_status_msb , Ack                            ' Byte 3 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_status_lsb , Ack                            ' Byte 2 lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_crc_byte , Ack                              ' Checksumme lesen
   If Err = 1 Then Sht_error_flag = True

   I2cstop                                                  ' STOP-Sequenz

   ' Statusflags verarbeiten und ggf. auf RS232 ausgeben

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "Status Flags : " ; Bin(sht_status_flags)
   #endif

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "--Enter Sht_read_status_bytes"
      Print ""
   #endif

Return
'-- End Sht_read_status_bytes -------------------------------------------------

'------------------------------------------------------------------------------
' SHT - Gosub-Routine: Sht_measurement
' Funktion startet einen single shot Messzyklus und wertet diesen aus. Die
' ermittelte Temperatur und die Luftfeuchtigkeit werden in globalen Variablen
' gespeichert.
'------------------------------------------------------------------------------
Sht_measurement:

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

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "++Enter Sht_measurement"
   #endif

   ' Error flag zurücksetzen
   Sht_error_flag = False

   I2cstart                                                 ' START-Sequenz senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_write                               ' Daten schreiben initiieren
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_single_rep_high_msb                     ' MSB schreiben
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_cmd_single_rep_high_lsb                     ' LSB schreiben
   If Err = 1 Then Sht_error_flag = True

   ' I2cstop                                                  ' STOP-Bedingung wird nicht zwingend gefordert

   Waitms Sht_t_meas

   ' Hinweis: Auf die Auswertung der CRC wird verzichtet.
   '          Keine Sicherheitskritische Umsetzung

   I2cstart                                                 ' START-Sequenz erneut senden
   If Err = 1 Then Sht_error_flag = True

   I2cwbyte Sht_address_read                                ' Daten lesen initiieren
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_temperature_msb , Ack                       ' Temperature MSB lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_temperature_lsb , Ack                       ' Temperature LSB lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_crc_byte , Ack                              ' Checksumme lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_humidity_msb , Ack                          ' Humidity MSB lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_humidity_lsb , Ack                          ' Humidity LSB lesen
   If Err = 1 Then Sht_error_flag = True

   I2crbyte Sht_crc_byte , Ack                              ' Checksumme lesen
   If Err = 1 Then Sht_error_flag = True

   I2cstop                                                  ' STOP-Sequenz

   ' Statusflags verarbeiten und ggf. auf RS232 ausgeben

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "RAW Temperature : " ; Hex(sht_temperature_word) ; " = " ; Sht_temperature_word
      Print "RAW Humidity    : " ; Hex(sht_humidity_word) ; " = " ; Sht_humidity_word
   #endif

   ' Achtung: hier Rechnen leider nur mit SINGLE möglich

   ' Temperatur berechnen
   Sht_temperature_float = Sht_temperature_word / 65535
   Sht_temperature_float = Sht_temperature_float * 175
   Sht_temperature_float = Sht_temperature_float - 45

   ' Luftfeuchtigketi berechnen
   Sht_humidity_float = Sht_humidity_word / 65535
   Sht_humidity_float = Sht_humidity_float * 100

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "Temperature : " ; Fusing(sht_temperature_float , "##.#" )
      Print "Humidity    : " ; Fusing(sht_humidity_float , "##.#" )
   #endif

   ' ggf. Traceausgaben auf RS232 erzeugen
   #if Sht_testmodus
      Print "--Enter Sht_measurement"
      Print ""
   #endif

Return
'-- End Sht_measurement -------------------------------------------------------

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

' System halt
End                                                         'end program

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

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

'################################### Historie #################################
'
' 16.02.2020 : Version 1.0
'              Erste offizielle und vollständig umgesetzte Produktivsoftware
'              Review der Software und Erstinbetriebnahme auf Hardware
'              Dauertest über ca. 5 Stunden
' -----------------------------------------------------------------------------
'
' -----------------------------------------------------------------------------
'
'##############################################################################