PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : State Machine aus Beispiel mit 5 Tasten



olby2
15.08.2008, 10:58
Hallo Leute,

ich wollte den Code aus dem Roboternetz / Wissen mal auf eine fünfte oder auch sechste Taste erweitern, doch bisher ohne Erfolg.


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

$regfile = "m32def.dat"
$framesize = 32 'Stack
$swstack = 32
$hwstack = 64
$sim
'
'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 * 5 ' im Orginal 4
'Key_plus|Key_minus|Key_prev|Key_next| Return
Keycode_string = "{056}{050}{052}{054}{051}" ' org fehlt {051}
Dim Keycode(5) As Byte At Keycode_string Overlay ' org (4)
Const Key_null = 0 'keine Taste gedrückt

'Pins des LCD-Modules setzen ggf. an eigene Anschlüsse anpassen
Config Lcd = 20 * 4
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
Dim W As Word

'********* State Variables ************************************************** **
Dim State As Word 'aktueller State
Dim State_renew As Byte 'Flag
Dim State_gosub As Word 'aktuelles Unterprogramm

'Initial state variables
State_renew = 1
State = Loadlabel(s10) 'Startbildschirm LADEN in dem Fall Stateview
Key = Key_null 'keine Taste gedrückt


'********** MAIN-Loop ************************************************** *******
Do
'Menüeintrag und Tastencodes finden und ggf. State wechseln
'hier nur Tastendruck auswerten
Gosub Change_state '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'Pointer nach Statuswechsel neu setzen
If State_renew = 1 Then Gosub Change_state

'Unterprogramm des aktuellen State anspringen
LDS R31, {State_gosub+1} 'High see Bascom-Doc Mixing ASM and BASIC
LDS R30, {State_gosub} 'Low
LSR R31 'Division durch 2 (Alternativ ADR verwenden)
ROR R30
'Call zum Sub
ICALL


'---------------------------------------------------------------
'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: Change_state
'Call from: main loop
'Purpose: Status der State Machine feststellen und ggf. Wechseln
'Result: Pointer auf State / Variable State_renew
'---------------------------------------------------------------
Change_state:
lds R8, {State}
lds R9, {State + 1}
For I = 1 To 5 ' org 4
Read W
If Key = Keycode(i) Then
If W <> Loadlabel(null) Then
State_renew = 1
Key = Key_null 'reset key status after get a new state of state machine (prevent influence on GOSUBs)
State = W
End If
End If
Next I
Read State_gosub 'Adresse des akt. Unterprogramms einlesen
Read Lcd_textbuffer 'read LCD text
Return

'---------------------------------------------------------------
'Subroutine: Change_state_by_sub
'Call from: subroutine
'Purpose: change state of state machine by a subbroutine
'---------------------------------------------------------------
Change_state_by_sub:
State_renew = 1
Gosub Change_state
Return

'---------------------------------------------------------------
'DATA: State Machine
'Result: Pointers auf States , Unterprogramme
' Menütexte
'---------------------------------------------------------------

Null:
'Null is a dummy flag for State and Gosub -> do nothing
Return

S10:
Adr2 Null : Adr2 S11 : Adr2 Null : Adr2 S20 : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog1wahl 'Subroutine for current State
Data " "
'Menue Display Text

S11:
Adr2 S10 : Adr2 S12 : Adr2 Null : Adr2 Null : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog2wahl
Data " "

S12:
Adr2 S11 : Adr2 S13 : Adr2 Null : Adr2 Null : Adr2 S20
Adr2 Prog3wahl
Data " "

S13:
Adr2 S12 : Adr2 S14 : Adr2 Null : Adr2 S20 : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog4wahl 'Subroutine for current State
Data " "
'Menue Display Text

S14:
Adr2 S13 : Adr2 S15 : Adr2 Null : Adr2 Null : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog5wahl
Data " "

S15:
Adr2 S14 : Adr2 S16 : Adr2 Null : Adr2 Null : Adr2 S20
Adr2 Prog6wahl
Data " "

S16:
Adr2 S15 : Adr2 S17 : Adr2 Null : Adr2 S20 : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog7wahl 'Subroutine for current State
Data " "
'Menue Display Text

S17:
Adr2 S16 : Adr2 Null : Adr2 Null : Adr2 Null : Adr2 S20 'Key_plus|Key_minus|Key_prev|Key_next
Adr2 Prog8wahl
Data " "





''
S20:
Adr2 Null : Adr2 Null : Adr2 S10 : Adr2 Null
Adr2 Menu1
Data "Prog1"

'********* LCD SUB routines ************************************************** *
'---------------------------------------------------------------
'Subroutine: Lcd_print
'Call from: anywhere
'Purpose: gibt Lcd_textbuffer auf dem LCD-Display aus
'Result: LCD
'---------------------------------------------------------------
Prog1wahl:
'Adjusts the Clock
Lcd_textbuffer = "PUNKT1"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt2"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt3"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt4"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0
Return

Prog2wahl:
'Adjusts the Clock
Lcd_textbuffer = "punkt1"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT2"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt3"
Locate 3 , 1
Lcd Lcd_textbuffer
State_renew = 0

Return

Prog3wahl:
'Adjusts the Clock

Lcd_textbuffer = "punkt2"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT3"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt4"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0
Return

Prog4wahl:
'Adjusts the Clock

Lcd_textbuffer = "punkt3"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT4"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0
Return

Prog5wahl:
'Adjusts the Clock
Lcd_textbuffer = "punkt2"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt3"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt4"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT5"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0

Return

Prog6wahl:
'Adjusts the Clock
Lcd_textbuffer = "punkt3"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt4"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt5"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT6"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0

Return

Prog7wahl:
'Adjusts the Clock
Lcd_textbuffer = "punkt4"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt5"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt6"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT7"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0

Return

Prog8wahl:
'Adjusts the Clock
Lcd_textbuffer = "punkt5"
Locate 1 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt6"
Locate 2 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "punkt7"
Locate 3 , 1
Lcd Lcd_textbuffer

Lcd_textbuffer = "PUNKT8"
Locate 4 , 1
Lcd Lcd_textbuffer
State_renew = 0

Return



Lcd_print: 'Print lcd_textbuffer
Cls
Lcd Lcd_textbuffer
State_renew = 0
Return


Menu1: 'Print lcd_textbuffer
Cls
Lcd Lcd_textbuffer
State_renew = 0
Return


Ich habe wohl noch nicht ganz verstanden wie hier sehr clever und mit sehr wenig Aufwand die entsprechenden sub´s aufgerufen werden, wenn eine der Tasten betätigt wird.

Kann mir jemand behilflich sein

vielen dank
olby2

-tomas-
15.08.2008, 23:00
Hallo olby2,

worin besteht das Problem?
Du musst beim Label S20 noch das Label für die fünfte Taste ergänzen, da sonst ICALL in die Leere führt.

S20:
Adr2 Null : Adr2 Null : Adr2 S10 : Adr2 Null : Adr2 Null

olby2
16.08.2008, 15:15
Hallo Tomas,

vielen dank für deine schnelle Antwort.

Da habe ich wohl eine Zeile übersehen, in der noch eine Ergänzung notwendig war , vielen dank.

Das Beispiel ist wohl für ein einzeiliges Display gemacht worden, wenn
ich jetzt gleich mehlere Zeilen aus das Display bringen möchte ( a la Handymenu zum durchscrollen ) genügt es wohl nicht nur ein paar zusätzliche Data-Zeilen in die Tabelle zu bringen.

Ich habe also eine Sub Aufgerufen, wo dann der entsprechende Inhalt aufs Display gebracht wird.

Gibt es noch eine bessere, platzsparendere Möglichkeit ?

vielen Dank für eure Hilfe

cu
olby2

-tomas-
17.08.2008, 00:36
wir hatten vor kurzen eine heftige Diskussion im Forum, in Folge dessen ich den State Machine Code mit ADR2 als Kompaktlösung entwickelt hatte:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=41890

in dem Link in RNWissen findest Du weitere Ansätze... https://www.roboternetz.de/wissen/index.php/Bascom_State_Machine_Menu

zur Frage:
Ein mehrzeiliges Scrollmenü könnte man natürlich durch Aufbohren der DATA Zeilen erreichen und hier im Code ein paar Read LCD_Zeile_n ergänzen:

Read State_gosub 'Adresse des akt. Unterprogramms einlesen
Read Lcd_textbuffer 'read LCD text

Das ganze wäre uneffektiv, da alle Texte mehrfach auftauchen.
Die bessere Lösung wäre hier, in der DATA Zeile nur die Nummer des Eintrages einer Texttabelle zu notieren und auf dem Display dann den Ausschnitt der Texttabelle darzustellen.
Ähnlich der ersten Lösung in RNWissen.