Aus RN-Wissen.de
Version vom 18. November 2005, 13:26 Uhr von PicNick (Diskussion | Beiträge) (Ein kleines Spiel mit BasCom)

Wechseln zu: Navigation, Suche
Rasenmaehroboter Test

Allgemeines zu Terminals

Was hat ein Terminal mit Robotik zu tun ? Eigentlich nix. Aber wer nicht ein LCD-Display und eine Tastatur auf seinem Board eingebaut hat, ist darauf angewiesen, mit einer Terminal-Emulation Kontakt mit seinem Controllerboard aufzunehmen.

Gleich vorweg: da kaum ein Bastler mit einem richtigen "physischen" Terminal was zu tun hat, werde ich den Zusatz "Emulation" in Zukunft streichen, das verwirrt nur und bringt nix. Bei so einem Terminal sind ein paar Dinge einzustellen, und auf die sollte man auch achten. Häufig verwendet werden

Artikel von PicNick

BasCom Terminal

Die Möglichkeiten beschränken sich auf das Wichtigste

Options-->Communications

http://www.roboternetz.de/wiki/uploads/Main/basterm1.jpg

Es ist nicht viel einzustellen, die gezeigten Werte sind der Normalfall

Hyperterm Terminal

Nach dem Programmstart erscheint

Neue Verbindung

http://www.roboternetz.de/wiki/uploads/Main/hyper1.jpg

Da gibt man irgendeinen Namen für die Verbindung ein, z.B. "Roboternetz"

Es erscheint Verbinden mit

http://www.roboternetz.de/wiki/uploads/Main/hyper2.jpg

Wir geben das COM-Port ein, wo das Kabel zum Controller angesteckt ist

Jetzt kommt's drauf an, was im Controller eingestellt wurde.

Anschlußeinstellungen

http://www.roboternetz.de/wiki/uploads/Main/hyper3.jpg

  • Baudrate (Bits pro Sekunde) - Beliebt ist 9600, das muß aber mit dem übereinstimmen, was wir dem Controller gesagt haben
  • Datenbits - Normalerweise "8"
  • Parität - Normalerweise "keine"
  • Stoppbits - Normalerweise "1"
  • Flußsteuerung - Normalerweise "kein"
Jetzt ist das Hyperterm soweit zufrieden, wir aber nicht.

http://www.roboternetz.de/wiki/uploads/Main/hyper4.jpg

Es geht weiter bei

Einstellungen

Datei-->Eigenschaften-->Einstellungen

http://www.roboternetz.de/wiki/uploads/Main/hyper5.jpg


Interessant sind

  • Rücktaste sendet*
    • CAN (Ctrl-H) --> Terminalsteuerung
    • DEL --> Terminalsteuerung

Emulation wird hier Verschiedenes angeboten

  • Auto Detect
  • TTY

Solange man nur "print" und "input" sagt, reicht das allemal

  • VT100 / VT220 und ev. andere

diese Typen verstehen die normalen "ANSII-Steuersequenzen" und einige mehr ANSII-Sequenzen

Das reicht, um mit dem Robby eine Unterhaltung führen zu können

ASCII-Konfiguration

Um das Interesse zu wecken, einmal ein Bild der Einstellungen. Beim Thema "Terminalsteuerung" gibt's dazu mehr Information

http://www.roboternetz.de/wiki/uploads/Main/hyper6.jpg

Terminalsteuerung ANSII

Ein Terminal bietet aber auch einiges mehr als das, was bei der allgemeinen Terminalsteuerung besprochen wurde.

  • Volle Kontrolle über den Bildschirm
  • Alle Tasten können verwendet werden

Dazu werden ANSII-Sequenzen verwendet,das sind Zeichenfolgen mit ganz bestimmtem Aufbau. Und auch die werden noch von verschiedenen Herstellern um zusätzliche Funktionen erweitert. Besonders hervorgetan hat sich hier DEC (digital equipment corporation) mit seinen VTxxx Terminals. Viele Terminal-Emulationen bieten solche Typen an, wobei besonders die VT220 und aufwärts interessant sind. Aber auch schon VT100 ist ganz nett.

Die ganzen Steuersequenzen sind auch im Internet zu finden und Power-User sind gebeten, sich dort über alle Feinheiten zu informieren.

Für Microcontroller ist wohl einiges zu aufwendig, aber einige Möglichkeiten möchte ich hier darstellen, da man damit doch von den unleserlich schnell durchlaufenden Einzelzeilen wegkommen kann.

Nicht jeder hat die Möglichkeit, und manchmal zahlt es sich auch garnicht aus, eigens ein graphikfähiges PC-Programm zu schreiben, um mit seinem Microcontroller Dialog zu führen, oder ein bißchen Balkengraphik zu zeigen.

Den Typ VT100 bieten BasCom und Hyperterm an, wollen wir mal sehen

VT100

Was wird gesendet ? (Auszug) Bei der normalen Schreibmaschinen-Tastatur ändert sich nix. Aber die anderen Blöcke werden nun lebendig

Nur das erste Zeichen eine Sequenz ist ein Kontrollzeichen, und zwar 
<ESC>, Code 27, die anderen sind normal lesbare ASCII Zeichen

Pfeiltasten

  • Pfeil rauf
<ESC>[A
  • Pfeil runter
<ESC>[B
  • Pfeil rechts
<ESC>[C
  • Pfeil links
<ESC>[D

EDIT Keys

  • Pos 1 (Home)
<ESC>[1~
  • Bild rauf
<ESC>[5~
  • Bild runter
<ESC>[6~

Was kann man senden ? (Auszug) Wie beim Empfangen, bei den "normalen" Zeichen ändert sich nichts. Ich will auch nur einige Beispiele bringen, die auf den Geschmack bringen sollen.

!!! Freie Positionierung des Cursors irgendwo am Schirm

<ESC>[nn;mmf

dabei ist

  • nn die Zeilennummer 1-24
  • mm die Spalternummer 1-80 oder 1-132

BasCom Beispiel, das auch der C-Programmierer versteht

PRINT chr(27);"[01;40f";

stellt den Cursor in die oberste Zeile, genau in die Mitte.'- (führende Nullen können sein, müssen aber nicht)-'

Zeichen-Attribute

<ESC>[paramm     '-(das ist ein kleines "m" am Schluß)-'

Mögliche "param" sind

  • 0 = normal
  • 1 = heller (bold)
  • 4 = unterstrichen
  • 5 = blinkend
  • 7 = reverse (dunkel auf hell bzw. umgekehrt)

dabei können mehrere Attribute angegeben werden, dann aber mit semikolon getrennt

<ESC>[param1;param2;param3m 

Beispiel: will man bei einer Eingabe den Aufforderungstext verkehrt darstellen, sendet man

PRINT chr(27);"[7m";   ' setzt attribut "revers"
PRINT "VORNAME ?>";    ' der Text
PRINT chr(27);"[0m";   ' Attribut wieder normal

http://www.roboternetz.de/wiki/uploads/Main/Ansii_2.jpg

(das geht natürlich auch in einem Print-Befehl auf einmal)


Lösch-Befehle

  • rechts vom Cursor die Zeile löschen
<ESC>[K
  • Links vom Cursor die Zeile löschen
<ESC>[1K
  • Vom Cursor abwärst den ganzen Schirm löschen
<ESC>[J
  • Oberhalb des Cursors den ganzen Schirm löschen
<ESC>[J

Beispiel: Beim Programmstart erstmal den gesamten Schirm löschen und eine Überschrift in der Mitte

PRINT chr(27);"[1;1f";    ' Cursor ganz rauf
PRINT chr(27);"[J";       ' den ganzen Schirm löschen
PRINT chr(27);"[1;38f";   ' In die Mitte der ersten Zeile 
PRINT chr(27);"[7m";      ' setzt attribut "revers"
PRINT "START";            ' Überschrift
PRINT chr(27);"[0m";      ' setzt attribut normal
PRINT                     ' (=neue Zeile) Cursor am Anfang der zweiten Zeile


Anmerkung: Man kann mit diesen Sequenzen einiges tun, auch einige Spiele aus der Urzeit lassen sich damit programmieren, vor allem aber kann man z.B. Sensorwerte übersichtlich an verschiedenen Stellen des Schirme so plazieren, daß man mehrere im Auge behalten kann.


Ein kleines Spiel mit BasCom

Das folgende Programm ist für einen ATmega32 geschrieben, sollte aber auch auf den meisten anderen AVRs zum Laufen zu bringen sein. Leider ist beim BasCom-Terminal die VT100-Emulation nicht ganz umfassend, es konnten z.B. beim Testen keine Codes für die Pfeil-Tasten empfangen werden. Für das Spiel müßte also das Hyperterm oder etwas ähnliches verwendet werden. Das Spiel ist in keiner Weise beeindruckend, anspruchsvoll oder ausgereift, es soll nur demonstrieren, wie man Terminal-Steuersequenzen anwenden kann.

http://www.roboternetz.de/wiki/uploads/Main/game.jpg

Der Ball bewegt sich kreuz und quer über den Schirm. Der Spieler kann mit den Pfeiltasten Rechts / Links den "Schläger" verschieben, und so versuchen, den Ball zu treffen. Klappt das, gibt's rechts oben einen Punkt. (Mit "C" wird ein neues Spiel gestartet)

 '=======================================================================================
 '  ANSII  Demo
 '   Author   R.Toegel
 '========================================================================================
 $crystal = 8000000                                          ' Quarzfrequenz
 $baud = 9600                                                'Baudrate für RS232


Das sind die obligaten Definitionen. Es wäre durchaus günstig, die Baudrate zu erhöhen, das Beispiel verwendet mit Absicht die Standard-Definition.

 Config Timer0 = Timer , Prescale = 1024                     'Timer 10mS
 Const Tmr_c_preload = 178
 Const Tmr_c_divisor = 10                                    ' gives 100ms flag

 On Timer0 Interrupt_ticker                               ' Timer 
 
 Dim Irptflag As Byte                                        ' Timer Interrupt occurred
 Const Irpt_0 = 0                                            'Timer 0

 Dim Divis As Byte                                           ' timer divisor

Es wird nur der Timer0 verwendet, der auf 10 mS eingestellt ist. Mit einem weiteren Zähler wird letztlich alle 100 mS ein Flag gesetzt, der eine Ballbewegung auslöst. Das erzeugt ein moderates Spiel. Um schneller werden zu können, müßte man die Baudrate hinaufsetzen.

 Const Escape = &H1B

 Dim Hit As Integer                                          ' current horz-position
 
 Dim X_pos As Integer                                        ' current horz-position
 Dim Y_pos As Integer                                        ' current vert-position
 Dim X_dir As Integer                                        ' horz movement
 Dim Y_dir As Integer                                        ' vert movement
 Dim Block As Byte                                           ' Objekt


Das sind die Felder zur Ballkontrolle. Um problemlos mit Vorzeichen rechnen zu können, sind sie als "integer" definiert.

  • x_pos ist die horizontale Position am Schirm, Bereich ist 1 - 80
  • y_pos ist die vertikale Position am Schirm, Bereich ist 1 - 24
  • .-dir sind +1, wenn die Bewegung nach rechts / unten gehen soll, und -1, wenn umgekehrt.
  • Block ist der Ascii-Code des "Balles". Im Beispiel wird einfach "blank" (=32) verwendet, das ergibt in der reversen Darstellung einen weißen/schwarzen Würfel.
 Dim X_bar As Byte                                           ' current Bar-pos left
 Dim X_bar2 As Byte                                          ' current Bar-pos right
 Dim X_barold As Byte                                        ' previous

Diese Felder sind für den "Schläger", der sich immer in Zeile 24 befindet.

  • x_bar ist die neue Schlägerposition 1 - 75
  • x_bar2 ist dessen rechtes Ende
  • x_barold ist vorhergegangene Position
Dim Rxchar As Byte                                          ' Keyboard data
Dim Rxflag As Byte                                          ' Escape-State

Rxchar ist das gerade von der Tastatur empfangene Zeichen. Rxflag wird zu Interpretation der PfeilTasten Sequenz verwendet

  • <ESC>[C Pfeil rechts
  • <ESC>[D Pfeil links
   Timer0 = Tmr_c_preload
   Enable Timer0 
   Enable Interrupts                                        'General enable
   Start Timer0                                             ' timer starten
 
   Gosub Re_set
   Rxflag = 0


Start & Initialisierung

 '==============================================================================
 '  M A I N    L O O P
 '==============================================================================
 Do
   If Irptflag.irpt_0 = 1 Then     ' dieser Flag wir alle 10 mS von TIM0 ISR gesetzt
      Irptflag.irpt_0 = 0          ' löschen 

      Gosub Set_cursor                        ' Ballposition 
      Print " ";                              ' Ball loeschen
      Print Chr(8);

      X_pos = X_pos + X_dir                                 ' ein Schritt horizontal +/-

      If X_pos >= 80 Or X_pos <= 1 Then                     ' limit ?
         X_dir = X_dir * -1                                 ' ja, richtungwechsel
         Print Chr(7) ;                                     ' click or beep
      End If

      If Y_pos = 1 And X_pos >= 70 Then       ' wenn der "score"-Text gelöscht wird, 
         Gosub Show_score                     ' dann neu schreiben
      End If

      Y_pos = Y_pos + Y_dir                                 ' ein Schritt vertial +/-

      If Y_pos = 23 Then                                    ' collision ?
         If X_pos >= X_bar And X_pos <= X_bar2 Then         ' schlaeger flaeche ?
            Y_dir = Y_dir * -1                              ' ja, richtungwechsel
            Print Chr(7) ;                                  ' click or beep
            Incr Hit                                        ' erhöhen Score
            Gosub Show_score                                ' und zeigen
         End If
      End If

      If Y_pos >= 24 Or Y_pos <= 1 Then                     'limit vertikal ?
         Y_dir = Y_dir * -1                                 'ja, richtungwechsel
         Print Chr(7) ;                                     ' click or beep
      End If

      Gosub Set_cursor                                      ' zeichnen block neu
      Gosub Set_reverse                                     ' reverse
      Print Chr(block);                                     ' der "Ball"
      Print Chr(8);                                         
      Gosub Set_normal

   End If

   Rxchar = Inkey()                   ' Keyboard ?
   If Rxchar > 0 Then
      Gosub Keyboard                  ' Yes
    End If
 Loop

 End


Ein Hinweis: daß nach dem Ball ein "Backspace" chr(8)gesendet wird, hat den Grund, den blinkenden Cursor gewissermaßen "hinter" dem Ball zu verstecken.

 '==============================================================================
 ' Timer 0  interrupt
 '==============================================================================
 Interrupt_ticker:
 Timer0 = Tmr_c_preload                                      ' refresh
      Incr Divis                            ' inkrementieren /10 Teiler
      If Divis > Tmr_c_divisor Then
         Divis = 0
         Irptflag.irpt_0 = 1                ' setzen 10mS Flag
      End If
 Return


Die Timer-Interrupt-Routine braucht nicht näher erklärt zu werden.

Keyboard-Routine

Je nach RxFlag hat diese Routine 3 Zustände:

  • 0 Im Normalfall, für alle Einzeltasten. Bei "C" wird ein Spiel-Reset durchgeführt

Wird aber das Zeichen <ESC> ( 27 , &H1B) empfangen, wechselt der Zustand auf "1"

  • 1 Nach einem Escape-Zeichen darf in unserm Spiel nur "[" kommen, was den Zustand auf "2" setzt, jedes andere Zeichen geht wieder auf "0", ein Klicken wird ausgelöst.
  • 2 Jetzt kann "C" für Pfeil rechts oder "D" für Pfeil links kommen. darauf reagiert das Spiel, indem es die "Schläger" -Position verändert.

Auf jeden Fall ist die Sequenz aber beendet, wir gehen wieder auf Zustand "0" = normal

 Keyboard:
   Select Case Rxflag

   Case 0:
      Select Case Rxchar
      Case Escape:
         Rxflag = 1
      Case "C":
         Gosub Re_set
      Case "c":
         Gosub Re_set
      Case Else:
         Print Chr(7) ;                                     ' click or beep
      End Select

   Case 1:
      If Rxchar = "[" Then
         Rxflag = 2                                         ' <ESC>[
      Else
         Rxflag = 0
      End If

   Case 2:
      Select Case Rxchar
      Case "C":                                             ' Arr RIGHT
         If X_bar < 75 Then
            Incr X_bar
            Gosub Draw_bar
         End If
      Case "D":                                             ' Arr LEFT
         If X_bar > 2 Then
            Decr X_bar
            Gosub Draw_bar
         End If
      End Select
      Rxflag = 0                                             ' anyhow
   End Select
   Return

Die folgenden Routinen sind "gosubs", um das Programm übersichtlicher zu machen.  

 Re_set:
   Gosub Clear_screen
   X_pos = 31
   Y_pos = 1
   Gosub Set_cursor
   Gosub Set_reverse
   Print " S T A R T VT100 ";                               ' text
   Gosub Set_normal

   X_pos = 1
   X_dir = 1
   Y_pos = 1
   Y_dir = 1
   Block = 32

   Hit = 0
   X_bar = 38
   X_barold = X_bar
   Gosub Draw_bar
   Gosub Show_score
   Return
 '-------------------------------------------------------------------
 Draw_bar:
   Print Chr(escape) ; "[24;" ; Str(x_barold) ; "H     ";
   Print Chr(escape) ; "[24;" ; Str(x_bar) ; "Hxxxxx";
   X_bar2 = X_bar + 4
   X_barold = X_bar
   Return
 '-------------------------------------------------------------------
 Show_score:
   Print Chr(escape) ; "[1;70" ; "HScore:" ; Str(hit) ;
   Return
 '-------------------------------------------------------------------
 Clear_screen:
   Print Chr(escape) ; "[1;1H";                             'Home
   Print Chr(escape) ; "[2J";                               'clear terminal screen
   Return
 '-------------------------------------------------------------------
 Set_cursor:
   Print Chr(escape) ; "[" ; Str(y_pos) ; ";" ; Str(x_pos) ; "H";
   Return
 '-------------------------------------------------------------------
 Set_reverse:
   Print Chr(escape) ; "[7m" ;
   Return
 '-------------------------------------------------------------------
 Set_normal:
   Print Chr(escape) ; "[0m";
   Return


Vielleicht konnte ich jemanden auf den Geschmack bringen, eigene Versuche weiterzuführen.


LiFePO4 Speicher Test