'##############################################################################
' HD44780_1602_LCD_2x16.BAS                                    Stand 02.04.2017
' -------------------------                                    (C) Markus Fulde
'
' Testprogramm zur Inbetriebnahme eines LCD Displays Serie ERM1602-6 mit
' einem HD44780 Display-Controller.
'
' Die Inbetriebnahme erfolgt mit einem Experimentier-Steckbrett auf Basis eines
' ATmega8L. Die Inbetriebnahme is dahingehend eingeschränkt, dass mit einem
' ATmega8L nur der 4-Bit PIN-Modus umgesetzt werden kann. Der 8-Bit Bus-
' Interfacemodus benötigt einen ATmega mit externer Speicherverwaltung, z.B.
' ATmega128. Daher wird hier im Programm nur der 4-Bit-PIN-Modus umgesetzt.
' Die Umsetzung des 8-Bit Modus erfolgt gesondert.
'
' Die für die LCD-Display-Ansteuerung notwendigen Routinen sind sequentiell
' im Hautprogramm hintereinander programmiert und werden in einer Endlosschlei-
' fe wiederholt. Die für das LCD Display wichtigsten bzw. verfügbaren Funk-
' tionen sind damit abgebildet.
'
' Im ersten Teil des Programms werden die BASCOM eigenen Funktionen inkl. der
' Initialisierung verwendet. Im 2. Teil wird auf Inline-Assemembler zurück-
' gegriffen und die Register bzw. Arbeitsvariablen direkt beschrieben und das
' Display direkt gesteuert. Hierbei kommt die direkte Adressierung der
' Kommando-Befehle und Speicherzugriffe zum Einsatz.
'
'##############################################################################

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

$lcdvfo

'------------------------------------------------------------------------------
' Allgemeine Zusatzinformatonen 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

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

' ----- LED's -----

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

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

Rs_pin Alias Portc.5                                        ' GPIO für LCD RS
E_pin Alias Portc.4                                         ' 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.
Rw_pin Alias Pinc.3                                         ' GPIO für LCD RW
Rw Alias Portc.3

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

' ----- Flags für Testumgebung -----

' Die BASCOM IDE bietet in den Einstellungen eigene Settings zum LCD-Display
' welche mittel Kommando im Sourceode überschrieben werden können.
' Zum Test der IDE gibt es ein Flag das hier im Sourcecode alle Einstellunge
' deaktiviert. Dann müssen die EInstellungen in der IDE vorgenommen werden.

Const Ide_konfigurationsmodus = 1                           ' Flag

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

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

' ----- 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

'------------------------------------------------------------------------------
' 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 Rw_pin = Output
Rw = Pegel_low

' Konfiguration LCD Display

#if Ide_konfigurationsmodus

   ' Config Lcdpin = Pin , Db4 = Db4_pin , Db5 = Db5_pin , Db6 = Db6_pin , Db7 = Db7_pin , E = E_pin , Rs = Rs_pin
   ' Config Lcdbus = 4                                        ' LCD arbeitet über 4-Bit

   Config Lcdpin = Pin , Port = Portd , E = E_pin , Rs = Rs_pin
   Config Lcdbus = 8                                        ' LCD arbeitet über 8-Bit

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

#endif

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

' Definition benutzerdefinierter Zeichen
Deflcdchar 0 , 32 , 32 , 10 , 10 , 32 , 4 , 17 , 14         ' Smily
Deflcdchar 1 , 21 , 10 , 10 , 21 , 21 , 10 , 10 , 21        ' Muster

Cls                                                         ' Clear Screen

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

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

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

' ----- LED-Konfigurationen -----
Alive = Led_aus                                             ' Alive-LED aus

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

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

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

' #############################################################################
'
'                       Hauptprogramm HD44780_1602_LCD_2x16
'
' #############################################################################

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

' Endlose Hauptschleife
Do

   ' ----- Teil 1: BASCOM eigene Funktionen -----

   Cls
   '                   1234567890123456
   Locate 1 , 1 : Lcd "***** Hallo ****"

   Wait 5

   Cls
   Home : Lcd "Cursor-Test"
   Locate 2 , 1 : Lcd "Mit Cursor"
   Cursor On Blink

   Wait 5

   Locate 2 , 1 : Lcd "Ohne Cursor"
   Cursor Off Noblink

   Wait 5

   Cls
   '                   1234567890123456
   Locate 1 , 1 : Lcd "Userdefined Char"
   Locate 2 , 1 : Lcd Chr(0) : Locate 2 , 16 : Lcd Chr(0)
   Locate 2 , 3 : Lcd Chr(1) : Locate 2 , 14 : Lcd Chr(1)
   Locate 2 , 5 : Lcd Chr(0) : Locate 2 , 12 : Lcd Chr(0)
   Locate 2 , 7 : Lcd Chr(1) : Locate 2 , 10 : Lcd Chr(1)

   Wait 5

   ' ----- Teil 2: Das ganze geht auch in Assembler -----

   ' Bildschirm löschen
   '                 +-- Kommando Bildschirm löschen
   '                 |
   _temp1 = &B00000001
   !rCall _Lcd_control

   ' Cursor auf Startposition
   '                +--- Kommando Cursor auf Startposition
   '                |
   _temp1 = &B00000010
   !rCall _Lcd_control

   ' Ausgabe von 1-8 aus Display via Assembler
   _temp1 = 49                                              ' Für Buchstabe 1
   !RCALL _Write_lcd
   _temp1 = 50                                              ' Für Buchstabe 2
   !RCALL _Write_lcd
   _temp1 = 51                                              ' Für Buchstabe 3
   !RCALL _Write_lcd
   _temp1 = 52                                              ' Für Buchstabe 4
   !RCALL _Write_lcd
   _temp1 = 53                                              ' Für Buchstabe 5
   !RCALL _Write_lcd
   _temp1 = 54                                              ' Für Buchstabe 6
   !RCALL _Write_lcd
   _temp1 = 55                                              ' Für Buchstabe 7
   !RCALL _Write_lcd
   _temp1 = 56                                              ' Für Buchstabe 8
   !RCALL _Write_lcd

   Wait 5

   ' Display ausschalten
   '              +----- Kommando Display/Cursor
   '              |+---- Display aus
   '              ||+--- Cursor aus
   '              |||+-- Cursor blinkt nicht
   '              ||||
   _temp1 = &B00001000
   !rCall _Lcd_control

   Wait 5

   ' Display einsschalten
   '              +----- Kommando Display/Cursor
   '              |+---- Display ein
   '              ||+--- Cursor ein
   '              |||+-- Cursor blinkt
   '              ||||
   _temp1 = &B00001111
   !rCall _Lcd_control

   Wait 5

   ' Display einsschalten
   '              +----- Kommando Display/Cursor
   '              |+---- Display ein
   '              ||+--- Cursor aus
   '              |||+-- Cursor blinkt nicht
   '              ||||
   _temp1 = &B00001100
   !rCall _Lcd_control

   Wait 5

   Cls

   ' So, und nun zum Schluss noch gezielt adressiertes Schreiben von Daten
   ' in den Speicher des LCD-Displays

   ' 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

   ' DDRAM Adresse setzen
   '          +--------- DDRAM Adresse setzen
   '          |+++++++-- DDRAM_Adresse
   _temp1 = &B10000000                                      ' Adresse 00 für 1. Zeichen Locate 1,1
   !rCall _Lcd_control

   ' Zeichen schreiben
   _temp1 = 42                                              ' Für Buchstabe *
   !RCALL _Write_lcd

   ' DDRAM Adresse setzen
   '          +--------- DDRAM Adresse setzen
   '          |+++++++-- DDRAM_Adresse
   _temp1 = &B11000111                                      ' Adresse 47 für 2. Zeichen Locate 2,8
   !rCall _Lcd_control

   ' Zeichen schreiben
   _temp1 = 42                                              ' Für Buchstabe *
   !RCALL _Write_lcd

    Wait 5

Loop                                                        ' Hauptschleife

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

End

'******************************************************************************
' 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  --------------------------------------------------------

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

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

' ----- KEINE -----

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

' ***************
' * LCD-Dsiplay *
' ***************

' ----- KEINE -----

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

' System halt
End                                                         'end program

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

' ----- KEINE -----

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

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

'################################### Historie #################################
' 02.04.2017 : Version 1.0
'              Erstellung der 1. Version der generellen Inbetriebnahme HD44780
'##############################################################################