Aus RN-Wissen.de
Wechseln zu: Navigation, Suche


(Variante 2 ergänzt)
Zeile 578: Zeile 578:
 
Weitere Erklärungen stehen im Quelltext.
 
Weitere Erklärungen stehen im Quelltext.
 
Die Bedienung erfolgt wie bei Variante 1.
 
Die Bedienung erfolgt wie bei Variante 1.
 +
 +
Da jetzt zur Vereinfachung nur noch Nummern für die States geführt werden, empfiehlt es sich ein Plan (siehe Grafik oben) anzulegen und jeden Kasten mit einer Nummer zu versehen. Die Zuordnung der Status-Nummern entsprechend der Tasten-Verzweigung (UP/DOWN etc.) ist dann schnell abgelesen.
  
 
Getestet im Bascom-Simulator der  Versionen:
 
Getestet im Bascom-Simulator der  Versionen:

Version vom 25. Juli 2008, 14:51 Uhr

Bascom State Machine Menu

Beim der Umsetzung des Beispielcodes von Atmel für AVR Butterfly [[1]] (in IAR-C bzw. die GCC-Portierung) nach Bascom [[2]] entstand folgende hoch effiziente State Machine zur Umsetzung eines Menüs für einen Datalogger.

Der Code wurde hier stark reduziert, so dass vom gesamten Programm das Menü als Rahmen mit allen Unterprogrammen (leer) übrig geblieben ist.

Die Menü-Struktur

Als Beispiel wird hier die um die Umsetzung des Menüs aus dem AVR Butterfly Evaluation Kit in Bascom gezeigt: Butterflymenu.png

Sample Code Variante 1: unübersichtlich und wenig Code

Der Code ist die 1:1 Umsetzung des C-Codes aus dem AVR Butterfly Evaluation Kit. Das Code-Beispiel wurde für den Bascom Simulator optimiert und kann dort direkt mit den Ziffern-Tasten bedient werden (NumLock!). Auf dem Simulator-LCD-Display werden die Ebenen mit angezeigt (3 -> 31 -> 32 -> 321 etc.)

Getestet im Bascom-Simulator der Versionen:

  • BASCOM 1.11.9.1 [OK]
  • BASCOM 1.11.8.7 [Probleme mir der LCD Darstellung]
  • BASCOM 1.11.8.1 [OK]

Die Codelänge des Samples beträgt ca. 2300Byte. Der größte Teil geht für die LCD-Anzeige, Anzeigetexte etc. drauf. Der State Machine selber ist sehr schlank, da nur Pointer (Zeiger) gesetzt werden.

Weitere Erklärungen stehen im Quelltext.

'Beispiel für ein State Machine Menü
'Das Beispiel ist für den BASCOM-Simulator angepasst worden
'  getestet mit BASCOM 1.11.8.1
'  Codelänge 2362 Byte
'
'Hinweis: Im Simulator müssen die Eingaben in das "Terminal Emulator Window" erfolgen!
'Auf der Tastatur ergeben sich für die VIER Joystick-Positionen folgende Umsetzungen
'
'              [Key_plus ]
' [Key_prev]   [         ]    [Key_next]
'              [Key_minus]
'
'
'              [ Taste_8 ]
' [Taste_4 ]   [         ]    [Taste_6 ]
'              [ Taste_2 ]
'
'bzw. im ASCII-Code
Const Key_null = 0                                          'keine Taste gedrückt
Const Key_next = 54
Const Key_prev = 52
Const Key_plus = 56
Const Key_minus = 50

'los gehts:
$regfile = "m32def.dat"

$framesize = 32                                             'Stack
$swstack = 32
$hwstack = 64

'Pins des LCD-Modules setzen ggf. an eigene Anschlüsse anpassen
Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2 , E = Portc.6 , Rs = Portc.7
Config Lcdmode = Port
Config Lcdbus = 4                                           '4 bit mode
Config Lcd = 20 * 4
Initlcd
Cls

'******** state machine states ************************************************
' Menu state machine states
Const St_avrbf = 10
Const St_avrbf_rev = 11

Const St_time = 20
Const St_time_clock = 21
Const St_time_clock_func = 22
Const St_time_clock_adjust = 23
Const St_time_clock_adjust_func = 24
Const St_time_clockformat_adjust = 25
Const St_time_clockformat_adjust_func = 26
Const St_time_date = 27
Const St_time_date_func = 28
Const St_time_date_adjust = 29
Const St_time_date_adjust_func = 30
Const St_time_dateformat_adjust = 31
Const St_time_dateformat_adjust_func = 32

Const St_datalogger = 40
Const St_datalogger_logcycle = 41
Const St_datalogger_logcycle_func = 42
Const St_datalogger_erase = 43
Const St_datalogger_erase_select = 44
Const St_datalogger_erase_func = 45
Const St_datalogger_logcount = 46
Const St_datalogger_logcount_func = 47
Const St_datalogger_rs232 = 48
Const St_datalogger_rs232_select = 49
Const St_datalogger_rs232_func = 50

Const St_adc = 60
Const St_temperature = 65
Const St_temperature_func = 66
Const St_voltage = 70
Const St_voltage_func = 71
Const St_adc_raw = 75
Const St_adc_raw_func = 76
Const St_adc_batt = 80
Const St_adc_batt_func = 81

Const St_options = 90
Const St_options_display_contrast = 91
Const St_options_display_contrast_func = 92
Const St_options_power_off = 95
Const St_options_power_off_func = 97
Const St_options_auto_power_save = 100
Const St_options_auto_power_save_func = 101
Const St_options_keyclick = 105
Const St_options_keyclick_func = 106
Const St_options_boot = 110
Const St_options_boot_select = 111
Const St_options_boot_func = 112

'********* State Variables ****************************************************
Dim Tab_state As Byte , Tab_input As Byte , Tab_nextstate As Byte
Dim Tab_text As String * 25

Dim State As Byte , State_renew As Byte

'Initial state variables
State = St_avrbf
State_renew = 1

'******** Joystick/Key Settings ***********************************************
Dim Key As Byte                                             'key in Mainloop

'******** LCD *****************************************************************
Dim Lcd_textbuffer As String * 25

'******** allg Variablen ******************************************************
Dim I As Byte , J As Byte
Dim I1 As Byte
Dim W As Word , W1 As Word

'********** MAIN-Loop *********************************************************
Do
   'Tastaturabfrage
    Key = Inkey()

   'Menüeintrag und Tastencodes finden
   If Key <> Key_null Then                                  'save power
      State_renew = 0
      Restore State_machine
      Do
         Read Tab_state
         Read Tab_input
         Read Tab_nextstate
         If State = Tab_state Then
            If Key = Tab_input Then
               State = Tab_nextstate
               State_renew = 1                              'LCD refresh
               Key = Key_null                               'reset key status after get a new state of state machine (prevent influence on GOSUBs)
            End If
         End If
      Loop Until State_renew = 1 Or Tab_state = 255
   End If

   'Endlosschleife mit Unterprogrammen
   Select Case State                                        '320 Byte für 20 Gosub
      Case St_time_clock_func : Gosub Showclock
      Case St_time_clock_adjust_func : Gosub Setclock
      Case St_time_clockformat_adjust_func : Gosub Setclockformat
      Case St_time_date_func : Gosub Showdate
      Case St_time_date_adjust_func : Gosub Setdate
      Case St_time_dateformat_adjust_func : Gosub Setdateformat

      Case St_datalogger_logcycle_func : Gosub Datalogger_setloginterval
      Case St_datalogger_erase_func : Gosub Datalogger_erase
      Case St_datalogger_logcount_func : Gosub Datalogger_logcount
      Case St_datalogger_rs232_func : Gosub Datalogger_rs232

      Case St_temperature_func : Gosub Temperaturefunc
      Case St_voltage_func : Gosub Voltagefunc
      Case St_adc_raw_func : Gosub Adc_raw_func
      Case St_adc_batt_func : Gosub Adc_batt_func

      Case St_options_display_contrast_func : Gosub Setcontrast
      Case St_options_boot_func : Gosub Bootfunc
      Case St_options_power_off_func : Gosub Power_off_func
      Case St_options_auto_power_save_func : Gosub Autopower
      Case St_options_keyclick_func : Gosub Keyclick_set
   End Select

   '---------------------------------------------------------------
   'place for your own code in main loop
   '---------------------------------------------------------------

   'LCD refresh wenn Menü verändert
   If State_renew = 1 Then
      State_renew = 0
      Restore Menu_text_data
      Do
         Read Tab_state
         Read Tab_text
         If State = Tab_state Then Lcd_textbuffer = Tab_text
      Loop Until Tab_state = 255
      Gosub Lcd_print
   End If

 Loop
End

'********* LCD SUB routines ***************************************************
'---------------------------------------------------------------
'Subroutine: Lcd_print
'Call from:  anywhere
'Purpose:    gibt Lcd_textbuffer auf dem LCD-Display aus
'Result:     LCD
'---------------------------------------------------------------
Lcd_print:                                                  'Print lcd_textbuffer
    Cls
    Lcd Lcd_textbuffer
Return

'********* SUB Clock routines**************************************************
Showclock:
  'Show the clock on the LCD
  Lcd_textbuffer = "HH:MM:SS"
  Gosub Lcd_print
Return

Setclock:
  'Adjusts the Clock
  Lcd_textbuffer = "HH=11"
  Gosub Lcd_print
Return

Setclockformat:
  'Adjusts the Clockformat (12H or 24H)
  Lcd_textbuffer = "12H / 24H"
  Gosub Lcd_print
Return

'********* SUB date routines **************************************************

Showdate:
   'Show the date on the LCD
   Lcd_textbuffer = "DD.MM.YY"
   Gosub Lcd_print
Return

Setdate:
   'Adjusts the Date
   Lcd_textbuffer = "Month=12"
   Gosub Lcd_print
Return

'---------------------------------------------------------------
Setdateformat:
   'Adjusts the Dateformat "DDMMYY" , "MMDDYY" , "YYMMDD"
   Lcd_textbuffer = "DDMMYY/YYMMDD"
   Gosub Lcd_print
Return

'********* Datalogger routines ************************************************
Datalogger_setloginterval:
   'set the datalog intervall HOUR:MINUTES
   Lcd_textbuffer = "HH:MM"
   Gosub Lcd_print
Return

Datalogger_erase:
  'erase the dataflash
  State = St_datalogger_erase
  State_renew = 1
Return

Datalogger_logcount:
  'Show DF_LogCount
   Lcd_textbuffer = "1234"
   Gosub Lcd_print
Return


Datalogger_rs232:
   'Print all DataLogs to RS232
   State = St_datalogger_rs232                              'next status of state machine
   State_renew = 1
Return


Temperaturefunc:
   'temperature measurement in °C
   Lcd_textbuffer = "+24C"
   Gosub Lcd_print
Return

Voltagefunc:
 'voltage measurement mV
   Lcd_textbuffer = "0mV"
   Gosub Lcd_print
Return


Adc_raw_func:
  'ADC Temperature/Voltage/Light result as RAW
   Lcd_textbuffer = "CH:RAW"
   Gosub Lcd_print
Return


Adc_batt_func:
  'battery voltage measurement
   Lcd_textbuffer = "2900mV"
   Gosub Lcd_print
Return


'********* Sub MENU / OPTIONS  ********************************
Setcontrast:
   'Adjust the LCD contrast
   Lcd_textbuffer = "0...15"
   Gosub Lcd_print
Return


Bootfunc:
   State = St_avrbf                                         'next status of state machine
   State_renew = 1
Return

Power_off_func:
  'LCD OFF
  State = St_options_power_off
Return


Autopower:
   'Enable/Disable auto power save
   Lcd_textbuffer = "ON/OFF"
   Gosub Lcd_print
Return


Keyclick_set:
    'Enable/Disable keyclick
   Lcd_textbuffer = "ON/OFF"
   Gosub Lcd_print
Return

'*********** State Machine ***************************************************
'112 Datensätze der State Machine ca. 350 Byte
'State with xxx_func forward to GOSUB xxx in main loop
'
'             [Key_plus ]
'[Key_prev]   [Key_enter]    [Key_next]
'             [Key_minus]

State_machine:
'  CURRENT_STATE   INPUT    NEXT_STATE
Data St_avrbf , Key_plus , St_options
Data St_avrbf , Key_next , St_avrbf_rev
Data St_avrbf , Key_minus , St_time

   Data St_avrbf_rev , Key_prev , St_avrbf

'Date+Time-----------------------------------------------------------------
Data St_time , Key_plus , St_avrbf
Data St_time , Key_next , St_time_clock
Data St_time , Key_prev , St_avrbf
Data St_time , Key_minus , St_datalogger

   Data St_time_clock , Key_plus , St_time_date
   Data St_time_clock , Key_next , St_time_clock_func
   Data St_time_clock , Key_prev , St_time
   Data St_time_clock , Key_minus , St_time_date

      Data St_time_clock_func , Key_prev , St_time_clock
      Data St_time_clock_func , Key_next , St_time_clock_adjust
      Data St_time_clock_func , Key_minus , St_time_date_func

         Data St_time_clock_adjust , Key_plus , St_time_clockformat_adjust
         Data St_time_clock_adjust , Key_next , St_time_clock_adjust_func
         Data St_time_clock_adjust , Key_prev , St_time_clock_func
         Data St_time_clock_adjust , Key_minus , St_time_clockformat_adjust

            Data St_time_clock_adjust_func , Key_prev , St_time_clock_func

         Data St_time_clockformat_adjust , Key_plus , St_time_clock_adjust
         Data St_time_clockformat_adjust , Key_next , St_time_clockformat_adjust_func
         Data St_time_clockformat_adjust , Key_prev , St_time_clock_func
         Data St_time_clockformat_adjust , Key_minus , St_time_clock_adjust

            Data St_time_clockformat_adjust_func , Key_prev , St_time_clock_func

   Data St_time_date , Key_plus , St_time_clock
   Data St_time_date , Key_next , St_time_date_func
   Data St_time_date , Key_prev , St_time
   Data St_time_date , Key_minus , St_time_clock

      Data St_time_date_func , Key_plus , St_time_clock_func
      Data St_time_date_func , Key_prev , St_time_date
      Data St_time_date_func , Key_next , St_time_date_adjust

         Data St_time_date_adjust , Key_plus , St_time_dateformat_adjust
         Data St_time_date_adjust , Key_next , St_time_date_adjust_func
         Data St_time_date_adjust , Key_prev , St_time_date_func
         Data St_time_date_adjust , Key_minus , St_time_dateformat_adjust

            Data St_time_date_adjust_func , Key_prev , St_time_date_func

         Data St_time_dateformat_adjust , Key_plus , St_time_date_adjust
         Data St_time_dateformat_adjust , Key_next , St_time_dateformat_adjust_func
         Data St_time_dateformat_adjust , Key_prev , St_time_date_func
         Data St_time_dateformat_adjust , Key_minus , St_time_date_adjust

            Data St_time_dateformat_adjust_func , Key_prev , St_time_date_func

'Data Logger---------------------------------------------------------------
Data St_datalogger , Key_plus , St_time
Data St_datalogger , Key_next , St_datalogger_logcycle
Data St_datalogger , Key_prev , St_avrbf
Data St_datalogger , Key_minus , St_adc

   Data St_datalogger_logcycle , Key_plus , St_datalogger_rs232
   Data St_datalogger_logcycle , Key_next , St_datalogger_logcycle_func
   Data St_datalogger_logcycle , Key_prev , St_datalogger
   Data St_datalogger_logcycle , Key_minus , St_datalogger_erase

      Data St_datalogger_logcycle_func , Key_prev , St_datalogger_logcycle

   Data St_datalogger_erase , Key_plus , St_datalogger_logcycle
   Data St_datalogger_erase , Key_next , St_datalogger_erase_select
   Data St_datalogger_erase , Key_prev , St_datalogger
   Data St_datalogger_erase , Key_minus , St_datalogger_logcount

      Data St_datalogger_erase_select , Key_next , St_datalogger_erase_func
      Data St_datalogger_erase_select , Key_prev , St_datalogger_erase

         'SUB St_datalogger_erase_func  -> new State = St_datalogger_erase

   Data St_datalogger_logcount , Key_plus , St_datalogger_erase
   Data St_datalogger_logcount , Key_next , St_datalogger_logcount_func
   Data St_datalogger_logcount , Key_prev , St_datalogger
   Data St_datalogger_logcount , Key_minus , St_datalogger_rs232

      Data St_datalogger_logcount_func , Key_prev , St_datalogger_logcount

   Data St_datalogger_rs232 , Key_plus , St_datalogger_logcount
   Data St_datalogger_rs232 , Key_next , St_datalogger_rs232_select
   Data St_datalogger_rs232 , Key_prev , St_datalogger
   Data St_datalogger_rs232 , Key_minus , St_datalogger_logcycle

      Data St_datalogger_rs232_select , Key_next , St_datalogger_rs232_func
      Data St_datalogger_rs232_select , Key_prev , St_datalogger_rs232

         'SUB St_datalogger_rs232_func -> new State = St_datalogger_rs232

'ADC-----------------------------------------------------------------------
Data St_adc , Key_plus , St_datalogger
Data St_adc , Key_next , St_temperature
Data St_adc , Key_prev , St_avrbf
Data St_adc , Key_minus , St_options

   Data St_temperature , Key_plus , St_adc_raw
   Data St_temperature , Key_next , St_temperature_func
   Data St_temperature , Key_prev , St_avrbf
   Data St_temperature , Key_minus , St_voltage

      Data St_temperature_func , Key_prev , St_temperature

   Data St_voltage , Key_plus , St_temperature
   Data St_voltage , Key_next , St_voltage_func
   Data St_voltage , Key_prev , St_avrbf
   Data St_voltage , Key_minus , St_adc_raw

      Data St_voltage_func , Key_prev , St_voltage

   Data St_adc_raw , Key_plus , St_voltage
   Data St_adc_raw , Key_next , St_adc_raw_func
   Data St_adc_raw , Key_prev , St_avrbf
   Data St_adc_raw , Key_minus , St_adc_batt

      Data St_adc_raw_func , Key_prev , St_adc_raw

   Data St_adc_batt , Key_plus , St_adc_raw
   Data St_adc_batt , Key_next , St_adc_batt_func
   Data St_adc_batt , Key_prev , St_avrbf
   Data St_adc_batt , Key_minus , St_temperature

      Data St_adc_batt_func , Key_prev , St_adc_batt

'Options-------------------------------------------------------------------
Data St_options , Key_plus , St_adc
Data St_options , Key_next , St_options_display_contrast
Data St_options , Key_prev , St_avrbf
Data St_options , Key_minus , St_avrbf

   Data St_options_display_contrast , Key_plus , St_options_keyclick
   Data St_options_display_contrast , Key_next , St_options_display_contrast_func
   Data St_options_display_contrast , Key_prev , St_options
   Data St_options_display_contrast , Key_minus , St_options_boot

      Data St_options_display_contrast_func , Key_prev , St_options_display_contrast

   Data St_options_boot , Key_plus , St_options_display_contrast
   Data St_options_boot , Key_next , St_options_boot_select
   Data St_options_boot , Key_prev , St_options
   Data St_options_boot , Key_minus , St_options_power_off

      Data St_options_boot_select , Key_next , St_options_boot_func
      Data St_options_boot_select , Key_prev , St_options_boot

   Data St_options_power_off , Key_plus , St_options_boot
   Data St_options_power_off , Key_next , St_options_power_off_func
   Data St_options_power_off , Key_prev , St_options
   Data St_options_power_off , Key_minus , St_options_auto_power_save

      'SUB St_options_power_off_func -> new State = St_options_power_off

   Data St_options_auto_power_save , Key_plus , St_options_power_off
   Data St_options_auto_power_save , Key_next , St_options_auto_power_save_func
   Data St_options_auto_power_save , Key_prev , St_options
   Data St_options_auto_power_save , Key_minus , St_options_keyclick

      Data St_options_auto_power_save_func , Key_prev , St_options_auto_power_save

   Data St_options_keyclick , Key_plus , St_options_auto_power_save
   Data St_options_keyclick , Key_next , St_options_keyclick_func
   Data St_options_keyclick , Key_prev , St_options
   Data St_options_keyclick , Key_minus , St_options_display_contrast

      Data St_options_keyclick_func , Key_prev , St_options_keyclick

'Stop Condition
Data 255 , 255 , 255

'************ menu text strings: max. length 24 Byte!! ***********************
Menu_text_data:
Data St_avrbf , "1 Butterfly Bascom"
   Data St_avrbf_rev , "11 Rev 1"

Data St_time , "2 Time"
   Data St_time_clock , "21 Clock"
      Data St_time_clock_adjust , "211 Adjust Clock"
      Data St_time_clockformat_adjust , "212 Clock Format"
   Data St_time_date , "22 Date"
      Data St_time_date_adjust , "221 Adjust Date"
      Data St_time_dateformat_adjust , "222 Date Format"

Data St_datalogger , "3 DataLogger"
   Data St_datalogger_logcycle , "31 Log Cycle"
   Data St_datalogger_erase , "32 Delete Flash"
      Data St_datalogger_erase_select , "321 RIGHT Delete DF"
   Data St_datalogger_logcount , "33 Show LogCount"
   Data St_datalogger_rs232 , "34 Print to RS232"
      Data St_datalogger_rs232_select , "341 RIGHT Print9600B"

Data St_adc , "4 ADC"
   Data St_temperature , "41 Temperature"
   Data St_voltage , "42 Voltage"
   Data St_adc_raw , "43 ADC Port RAW"
   Data St_adc_batt , "44 Battery"

Data St_options , "5 Options"
   Data St_options_display_contrast , "51 LCD contrast"
   Data St_options_boot , "52 Bootloader"
      Data St_options_boot_select , "521 RIGHT bootloader"
   Data St_options_power_off , "53 LCD OFF"
   Data St_options_auto_power_save , "54 LCD Auto Power"
   Data St_options_keyclick , "55 Key Click"


Data 255 , ""                                               'Stop Condition

Sample Code Variante 2: übersichtlich und viel Code

Die Variante 1 ist leider unübersichtlich, da 3 Tabellen getrennt geführt werden (die State Machine, die Menütexte und die zugehörigen Unterprogrammeinsprünge). Nachfolgend eine Variante, in der nur eine Tabelle (Select Case State...) geführt wird. In jedem Statement Blocks steht ein Menütext (falls erforderlich), der Pointer für den Unterprogrammeinsprung (falls erforderlich) und ein Datensatz für die Verzweigung der State Machine (zwingend erforderlich).

Die Codelänge des Samples beträgt jetzt immerhin 3300Byte anstatt der 2300Byte von Variante 1. Dafür ist das Menü deutlich einfacher zu editieren.

Weitere Erklärungen stehen im Quelltext. Die Bedienung erfolgt wie bei Variante 1.

Da jetzt zur Vereinfachung nur noch Nummern für die States geführt werden, empfiehlt es sich ein Plan (siehe Grafik oben) anzulegen und jeden Kasten mit einer Nummer zu versehen. Die Zuordnung der Status-Nummern entsprechend der Tasten-Verzweigung (UP/DOWN etc.) ist dann schnell abgelesen.

Getestet im Bascom-Simulator der Versionen:

  • BASCOM 1.11.9.1 [OK]
'Beispiel für ein State Machine Menü
'Das Beispiel ist für den BASCOM-Simulator angepasst worden
'  getestet mit BASCOM 1.11.9.1
'  Codelänge 3288 Byte

$regfile = "m32def.dat"
$framesize = 32                                             'Stack
$swstack = 32
$hwstack = 64

'
'Hinweis: Im Simulator müssen die Eingaben in dem blauen "Terminal Emulator Window" erfolgen!
'Auf der Tastatur ergeben sich für die VIER Joystick-Positionen folgende Umsetzungen
'
'              [Key_plus ]
' [Key_prev]   [         ]    [Key_next]
'              [Key_minus]
'
'
'              [ Taste_8 ]
' [Taste_4 ]   [         ]    [Taste_6 ]
'              [ Taste_2 ]
'
'bzw. im ASCII-Code:

Dim Keycode_string As String * 4
'Key_plus|Key_minus|Key_prev|Key_next
Keycode_string = "{056}{050}{052}{054}"
Dim Keycode(4) As Byte At Keycode_string Overlay
Const Key_null = 0                                          'keine Taste gedrückt

'Pins des LCD-Modules setzen ggf. an eigene Anschlüsse anpassen
Config Lcd = 16 * 1
Initlcd
Cls

'******** Joystick/Key Settings ***********************************************
Dim Key As Byte                                             'key in Mainloop

'******** LCD *****************************************************************
Dim Lcd_textbuffer As String * 25

'******** allg Variablen ******************************************************
Dim I As Byte , J As Byte

'********* State Variables ****************************************************
Dim State As Byte , State_renew As Byte
Dim Gosub_adr As Word

'Initial state variables
State_renew = 1
State = 10                                                  'Startbildschirm
Key = Key_null

'********** MAIN-Loop *********************************************************
Do

   'Menüeintrag und Tastencodes finden und ggf. State wechseln
   If Key <> Key_null Then                                  'save power
      State_renew = 0
      Gosub State_detect                                    'hier nur Tastendruck auswerten
      For I = 1 To 4
        'Read J
        LPM R24,Z+
        sts {J},R24
        If Key = Keycode(i) Then
           If J > 0 Then
              State_renew = 1
              Key = Key_null                                'reset key status after get a new state of state machine (prevent influence on GOSUBs)
              State = J
           End If
        End If
      Next I
   End If

   'Unterprogramm des aktuellen State auslesen und ggf. anspringen
   Gosub State_detect
   If Gosub_adr > 0 Then
      Gosub_adr = Gosub_adr / 2                             'see Bascom-Doc Mixing ASM and BASIC
      LDS R31, {Gosub_Adr+1}                                'High
      LDS R30, {Gosub_Adr}                                  'Low
      'Call zum Sub
      ICALL
   End If

   '---------------------------------------------------------------
   'place for your own code in main loop
   '---------------------------------------------------------------

   'LCD refresh wenn Menü verändert
   If State_renew = 1 Then
      State_renew = 0
      Gosub Lcd_print
   End If

   'Tastaturabfrage mit Halt nur für Simulator, ansonsten Sleep+Timer_ISR verwenden!!
    Key = Waitkey()

 Loop
End

'********* State routines ***************************************************
'---------------------------------------------------------------
'Subroutine: State_detect
'Call from:  main loop
'Purpose:    Status der State Machine feststellen
'Result:     Pointer auf "DATA KeyCodes" und zugehörige Gosub
'---------------------------------------------------------------
State_detect:
   Gosub_adr = 0
   Select Case State
     Case 10:
         Lcd_textbuffer = "1 Butterfly Bascom"
         !Call Restore_label
         Data 0 , 20 , 0 , 11                               'Key_plus|Key_minus|Key_prev|Key_next
     Case 11:
             Lcd_textbuffer = "11 Rev 2"
             !Call Restore_label
             Data 0 , 0 , 10 , 0                            'Key_plus|Key_minus|Key_prev|Key_next
     Case 20:
         Lcd_textbuffer = "2 Time"
         !Call Restore_label
         Data 10 , 30 , 0 , 21
     Case 21:
             Lcd_textbuffer = "21 Clock"
             !Call Restore_label
             Data 0 , 22 , 20 , 23
     Case 22:
             Lcd_textbuffer = "22 Date"
             !Call Restore_label
             Data 21 , 0 , 20 , 24
     Case 23:                                               'Show HH:MM:SS
                   Gosub_adr = Loadlabel(showclock)
                   !Call Restore_label
                   Data 0 , 24 , 21 , 25
     Case 24:                                               'Show DD:MM:YY
                   Gosub_adr = Loadlabel(showdate)
                   !Call Restore_label
                   Data 23 , 0 , 22 , 26
     Case 25:
                   Lcd_textbuffer = "211 Adjust Clock"
                   !Call Restore_label
                   Data 27 , 0 , 23 , 65
     Case 26:
                   Lcd_textbuffer = "221 Adjust Date"
                   !Call Restore_label
                   Data 0 , 28 , 24 , 66
     Case 27:
                   Lcd_textbuffer = "212 Clock Format"
                   !Call Restore_label
                   Data 0 , 25 , 23 , 67
     Case 28:
                   Lcd_textbuffer = "222 Date Format"
                   !Call Restore_label
                   Data 26 , 0 , 23 , 68
     Case 30:
         Lcd_textbuffer = "3 DataLogger"
         !Call Restore_label
         Data 20 , 40 , 0 , 31
     Case 31:
             Lcd_textbuffer = "31 Log Cycle"
             !Call Restore_label
             Data 0 , 32 , 30 , 35
     Case 32:
             Lcd_textbuffer = "32 Delete Flash"
             !Call Restore_label
             Data 31 , 33 , 30 , 36
     Case 33:
             Lcd_textbuffer = "33 Show LogCount"
             !Call Restore_label
             Data 32 , 34 , 30 , 37
     Case 34:
             Lcd_textbuffer = "34 Print to RS232"
             !Call Restore_label
             Data 33 , 0 , 30 , 38
     Case 35:                                               'HH:MM
                   Gosub_adr = Loadlabel(datalogger_setloginterval)
                   !Call Restore_label
                   Data 0 , 0 , 31 , 0
     Case 36:
                   Lcd_textbuffer = "321 RIGHT Delete DF"
                   !Call Restore_label
                   Data 0 , 0 , 32 , 76
     Case 37:                                               '1234
                   Gosub_adr = Loadlabel(datalogger_logcount)
                   !Call Restore_label
                   Data 0 , 0 , 33 , 0
     Case 38:
                   Lcd_textbuffer = "341 RIGHT Print9600B"
                   !Call Restore_label
                   Data 0 , 0 , 34 , 78
     Case 40:
        Lcd_textbuffer = "4 ADC"
        !Call Restore_label
        Data 30 , 50 , 0 , 41
     Case 41:
            Lcd_textbuffer = "41 Temperature"
            !Call Restore_label
            Data 0 , 42 , 40 , 45
     Case 42:
            Lcd_textbuffer = "42 Voltage"
           !Call Restore_label
           Data 41 , 43 , 40 , 46
     Case 43:
            Lcd_textbuffer = "43 ADC Port RAW"
            !Call Restore_label
            Data 42 , 44 , 40 , 47
     Case 44:
            Lcd_textbuffer = "44 Battery"
           !Call Restore_label
           Data 43 , 0 , 40 , 48
     Case 45:                                               '+24°C
                   Gosub_adr = Loadlabel(temperaturefunc)
                   !Call Restore_label
                   Data 0 , 0 , 41 , 0
     Case 46:                                               '0 mV
                   Gosub_adr = Loadlabel(voltagefunc)
                   !Call Restore_label
                   Data 0 , 0 , 42 , 0
     Case 47:                                               'CH:RAW
                   Gosub_adr = Loadlabel(adc_raw_func)
                   !Call Restore_label
                   Data 0 , 0 , 43 , 0
     Case 48:                                               '2900mV
                   Gosub_adr = Loadlabel(adc_batt_func)
                   !Call Restore_label
                   Data 0 , 0 , 44 , 0
     Case 50:
        Lcd_textbuffer = "5 Options"
        !Call Restore_label
        Data 40 , 0 , 0 , 51
     Case 51:
            Lcd_textbuffer = "51 LCD contrast"
           !Call Restore_label
           Data 0 , 52 , 50 , 56
     Case 52:
            Lcd_textbuffer = "52 Bootloader"
           !Call Restore_label
           Data 51 , 53 , 50 , 57
     Case 53:
            Lcd_textbuffer = "53 LCD OFF"
           !Call Restore_label
           Data 52 , 54 , 50 , 83
     Case 54:
            Lcd_textbuffer = "54 LCD Auto Power"
           !Call Restore_label
           Data 53 , 55 , 50 , 58
     Case 55:
            Lcd_textbuffer = "55 Key Click"
           !Call Restore_label
           Data 54 , 0 , 50 , 59
     Case 56:                                               '0...15
                   Gosub_adr = Loadlabel(setcontrast)
                   !Call Restore_label
                   Data 0 , 0 , 51 , 0
     Case 57:
                   Lcd_textbuffer = "521 RIGHT bootloader"
                   !Call Restore_label
                   Data 0 , 0 , 52 , 87
     Case 58:                                               'OFF/5..90min
                   Gosub_adr = Loadlabel(autopower)
                   !Call Restore_label
                   Data 0 , 0 , 54 , 0
     Case 59:                                               'ON/OFF
                   Gosub_adr = Loadlabel(keyclick_set)
                   !Call Restore_label
                   Data 0 , 0 , 55 , 0
'Untermenüs zu State 25 bis 28
     Case 65:                                               'sub for "211 Adjust Clock"
                          Gosub_adr = Loadlabel(setclock)
                         !Call Restore_label
                          Data 67 , 0 , 23 , 0
     Case 66:                                               'sub for "221 Adjust Date"
                          Gosub_adr = Loadlabel(setdate)
                          !Call Restore_label
                          Data 0 , 68 , 24 , 0
     Case 67:                                               'sub for "212 Clock Format"
                          Gosub_adr = Loadlabel(setclockformat)
                          !Call Restore_label
                          Data 0 , 65 , 23 , 0
     Case 68:                                               'sub for  "222 Date Format"
                          Gosub_adr = Loadlabel(setdateformat)
                          !Call Restore_label
                          Data 66 , 0 , 24 , 0
'Untermenüs zu State 36 und 38
     Case 76:                                               'sub for  "321 RIGHT Delete DF"
                          Gosub_adr = Loadlabel(datalogger_erase)
                          !Call Restore_label
                          Data 0 , 0 , 36 , 0
     Case 78:                                               'sub for  "341 RIGHT Print9600B"
                          Gosub_adr = Loadlabel(datalogger_rs232)
                          !Call Restore_label
                          Data 0 , 0 , 38 , 0
'Untermenü zu State 53 und 57
     Case 83:                                               'sub for  "53 LCD OFF"
                          Gosub_adr = Loadlabel(power_off_func)
                          !Call Restore_label
                          Data 0 , 0 , 53 , 0
     Case 87:                                               'sub for "521 RIGHT bootloader"
                          Gosub_adr = Loadlabel(bootfunc)
                          !Call Restore_label
                          Data 0 , 0 , 57 , 0
'Error Handling
     Case Else
        State = 10
        !Call Restore_label
        Data 0 , 0 , 0 , 0

 End Select
Return

'---------------------------------------------------------------
'Subroutine: Restore_label
'Call from:  State_detect
'Purpose:    Ersatz für RESTORE Label, erspart das Setzen der Labels für DATA
'Result:     Pointer ZH:ZL steht auf der Rücksprungadresse => DATA aa,bb,cc,dd
'---------------------------------------------------------------
Restore_label:
   Pop ZH                                                   'R31
   POP ZL                                                   'R30
   LSL ZL                                                   'Multipliziere Adr mit 2
   ROL ZH
   'this is a return from Sub State_detect to main loop
Return

'********* LCD SUB routines ***************************************************
'---------------------------------------------------------------
'Subroutine: Lcd_print
'Call from:  anywhere
'Purpose:    gibt Lcd_textbuffer auf dem LCD-Display aus
'Result:     LCD
'---------------------------------------------------------------
Lcd_print:                                                  'Print lcd_textbuffer
    Cls
    Lcd Lcd_textbuffer
    State_renew = 0
Return

'********* SUB Clock routines**************************************************
Showclock:
  'Show the clock on the LCD
  Lcd_textbuffer = "HH:MM:SS"
  Gosub Lcd_print
Return

Setclock:
  'Adjusts the Clock
  Lcd_textbuffer = "HH=11"
  Gosub Lcd_print
Return

Setclockformat:
  'Adjusts the Clockformat (12H or 24H)
  Lcd_textbuffer = "12H / 24H"
  Gosub Lcd_print
Return

'********* SUB date routines **************************************************
Showdate:
   'Show the date on the LCD
   Lcd_textbuffer = "DD.MM.YY"
   Gosub Lcd_print
Return

Setdate:
   'Adjusts the Date
   Lcd_textbuffer = "Month=12"
   Gosub Lcd_print
Return

'---------------------------------------------------------------
Setdateformat:
   'Adjusts the Dateformat "DDMMYY" , "MMDDYY" , "YYMMDD"
   Lcd_textbuffer = "DDMMYY/YYMMDD"
   Gosub Lcd_print
Return

'********* Datalogger routines ************************************************
Datalogger_setloginterval:
   'set the datalog intervall HOUR:MINUTES
   Lcd_textbuffer = "HH:MM"
   Gosub Lcd_print
Return

Datalogger_erase:
  'erase the dataflash
  State = 32                                                'St_datalogger_erase
  State_renew = 1
Return

Datalogger_logcount:
  'Show DF_LogCount
   Lcd_textbuffer = "1234"
   Gosub Lcd_print
Return

Datalogger_rs232:
   'Print all DataLogs to RS232
   State = 34                                               'St_datalogger_rs232 as next status of state machine
   State_renew = 1
Return

Temperaturefunc:
   'temperature measurement in °C
   Lcd_textbuffer = "+24C"
   Gosub Lcd_print
Return

Voltagefunc:
 'voltage measurement mV
   Lcd_textbuffer = "0mV"
   Gosub Lcd_print
Return

Adc_raw_func:
  'ADC Temperature/Voltage/Light result as RAW
   Lcd_textbuffer = "CH:RAW"
   Gosub Lcd_print
Return

Adc_batt_func:
  'battery voltage measurement
   Lcd_textbuffer = "2900mV"
   Gosub Lcd_print
Return

'********* Sub MENU / OPTIONS  ********************************
Setcontrast:
   'Adjust the LCD contrast
   Lcd_textbuffer = "0...15"
   Gosub Lcd_print
Return

Bootfunc:
   State = 10                                               'St_avrbf as next status of state machine
   State_renew = 1
Return

Power_off_func:
  'LCD OFF
  State = 53                                                'Return  State is St_options_power_off
Return

Autopower:
   'Enable/Disable auto power save
   Lcd_textbuffer = "ON/OFF"
   Gosub Lcd_print
Return

Keyclick_set:
    'Enable/Disable keyclick
   Lcd_textbuffer = "ON/OFF"
   Gosub Lcd_print
Return

Siehe auch