Arbeiten mit dem Inkrementalgeber

Erstellen einer Library für den Inkrementalgeber

Die Auswertung des Inkrementalgebers erfolgt mit dem Keyboard Interrupt (siehe Pro­jekt Test_Encoder (Kapitel 0, Seite 28). Die Konfiguration und Freigabe des Key­board-Interrupts soll in der Funktion „v_InitEncoder()“ erfolgen. Diese Funktion und die ISR sollen im Sourcemodul Encoder_Lib.c abgespeichert werden. Die Be­we­gung des Encoders wird in der Variablen ucValue abgespeichert. Die LEDs an Port 2 sollen den Wert von ucValue enthalten. Erstellen sie das Projekt aus Tabelle 48.

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_EncoderLib

Test_EncoderLib

TestEncLib.c

 

..\Library

Encoder_Lib.c, PortConfig.c

Tabelle 48  Projekt Test_EncoderLib

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <PortConfig.H>

 

void main(void)

{

   v_PortConfig(Port2, AllPins, BiDir); // Port 2 konfiguriert

   v_InitEncoder();  // Keyboard-Interrupt initialisiert

   EA = 1;           // allgemeine Interruptsperre aufheben

 

   while(1)          // Endlosschleife

   {

      P2 = cValue;   // Wertuebernahme an Port 2

   }

}

Listing 42  Inhalt von TestEncLib.c

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

 

static unsigned char ucActEncVal;

char cValue;

 

void v_InitEncoder(void)

{

   ucActEncVal = P0 & 0xA0;  // Abspeichern der akt. Position

   cValue = 0;               // Ruecksetzen

 

   KBPATN = P0 & 0xE0;       // Setzen des Keyboard-Patterns

   KBCON = 0x00;

   KBMASK = 0xE0;  // Maske fuer Portpin 5, 6 und 7

   EKBI = 1;       // ISR fuer Keyboard-Int. freigeben

}

 

void v_KeyboardInt(void) interrupt 7

{

   KBPATN = P0 & 0xE0; // Neues Keyboard-Pattern setzen

 

   if (ucActEncVal != (P0 & 0xA0)) // Abfrage, ob Aenderung beim

   {                              // Inkrementalgebers erfolgt ist

      switch(P0&0xA0)

      {

      case 0x00:

         if (ucActEncVal == 0x20)

           cValue++;

         else

           cValue--;

         break;

      case 0x20:

         if (ucActEncVal == 0xA0)

           cValue++;

         else

           cValue--;

         break;

      case 0x80:

         if (ucActEncVal == 0x00)

           cValue++;

         else

           cValue--;

         break;

      case 0xA0:

         if (ucActEncVal == 0x80)

           cValue++;

         else

           cValue--;

         break;

      }

      ucActEncVal = P0 & 0xA0;  // Abspeichern der neuen Positon

   }                            // des Inkrementalgebers

   KBCON = 0x00;                // Loeschen des Keyboard Flags

}

Listing 43  Inhalt von Encoder_Lib.c

Steuerung des Cursors auf dem LCD-Display mit Hilfe des Inkrementalgebers

Jedes moderne Gerät wird seit einiger Zeit mit einer „Einknopf“-Bedienung ausge­lie­fert. Das Bedienelement für diese Funktion besteht aus einer Kombination aus Taster und Inkremental­ge­ber. Mit dem Taster wird zwischen den Rubriken ausgewählt bzw. die Eingabe bestätigt. Der Inkrementalgeber scrollt zwischen den Rubriken bzw. zwischen den Unterpunkten.

Erstellen sie ein Projekt, das den Cursor auf dem LCD mit dem Inkrementalgeber bewegt. Die Umschaltung zwischen horizontal und vertikal erfolgt mit der Taste des In­kre­mentalgebers. Die LCD wird über den Port 2 angesteuert. Das Komman­do „Cursor and Display Shift“ des HD44780 (siehe [2], Ka­pitel 5, „Kurzbe­schrei­bung der einzelnen Befehle“) setzt den Cursor auf eine Adresse im DD-RAM. Dieses Kommando zur Umsetzung des Cursors kann mit der Steuer­an­wie­sung „\n“ (printf(), v_SM_Printf()) erreicht werden. Die Adresszuordnung der Cur­sor­­po­sition im DD-RAM können sie der Tabelle 49 entnehmen. Die Tabelle 50 enthält die Projektstruktur.

Display Position

1

2

3

4

5

...

13

14

15

16

DD-RAM Adr (Zeile 1)

0x00

0x01

0x02

0x03

0x04

...

0x0C

0x0D

0x0E

0x0F

Zeile 2

0x40

0x41

0x42

0x43

0x44

...

0x4C

0x4D

0x4E

0x4F

Tabelle 49  DD-RAM-Adressen bei einem 2x16 Zeichen Display

Die Variablen „ucHPos“ und „ucVPos“ enthalten die aktuelle Position des Cursors. Sie sind lokal in der Funktion „main()“ vom Datentyp unsigned char definiert (siehe Listing 44, ). Die Bitvariable „btIsHor“ speichert den Wechsel zwischen horizontaler und ver­ti­kaler Bewegung (siehe ). Nach der Initalisierung von Port 2, dem Inkrementalgeber und der LCD-Anzeige wird auf eine Zustandsänderung des Inkrementalgebers gewartet (siehe ƒ). Bei einer Betätigung der Taste oder Bewegung des Inkrementalgebers wird die Aus­wer­tung begonnen. Ist die Taste betätigt worden, wird der Zustand von btIsHor gewech­selt (siehe ). Danach wird abgewartet, bis die Taste wieder losgelassen wird (sie­he ). Wurde der Inkrementalgeber gedreht, wird zuerst die Richtung überprüft (siehe ). Ist der Wert von cValue positiv, wird jetzt noch geprüft, ob es sich um eine horizontale Bewegung handelt (btIsHor = 1) und ob der Cursor bereits am linken Ende der Zeile steht (siehe ). Ist dies der Fall, wird „ucHPos“ um eins erhöht. Enthält btIsHor den Wert 0, wird „ucVPos“ auf 1 gesetzt (siehe ˆ). Ist der Wert negativ, finden die gleichen Überprüfungen statt, in diesem Fall auf die Minimal­wer­te. Vor dem Um­set­zen des Cursors wird „cValue“ auf 0 gesetzt (siehe ). Das Umset­zen des Cursors erfolgt in diesem Beispiel mit der Funktion „v_SM_Printf()“ (siehe Š). Die Variable „ucVPos“ wird mit 0x40 multipliziert, da die zweite Zeile mit dieser Start­adresse beginnt (siehe Tabelle 49).

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_LCDCursor

Test_SteuerungLCDCursor

TestSteuerungLCDCursor.c

 

..\Library

Encoder_Lib.c, PortConfig.c, CGRAM_V7.c, sm_printf.c, LCDLib_4bitPort.c, itoa.a51, bcd2hex.a51

Tabelle 50  Projekt Test_LCDCursor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

 

 

 

ˆ

 

 

 

 

 

 

 

 

Š

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <PortConfig.H>

#include <lcd_def.h>

#include <sm_printf.h>

 

void main(void)

{

   unsigned char ucHPos =0, ucVPos =0;

   bit btIsHor = 1;

   v_PortConfig(Port2, AllPins, BiDir); // Port 2 konfigurieren

   v_InitEncoder();             // Inkrementalgeber konfigurieren

   uc_LCDIni(_2LINE | _7DOTS);  // Initialisierung des HD44780

   EA = 1;                      // allg. Interruptsperre aufheben

 

   while(1)

   {

      while(cValue == 0 && EncSwitch == 1);

      if (EncSwitch == 0)

      { // wechseln zwischen hor. und ver. Bewegung

         btIsHor = !btIsHor;

         while (EncSwitch == 0); // Warten bis Taste losgelassen

      }

      else // Auswertung der Cursorbewegung

      {

        if (cValue >0)

        {

          if (btIsHor == 1 && ucHPos < 0x0F)

             ucHPos++;

          else if (btIsHor == 0)

             ucVPos = 1;

        }

        else

        {

          if (btIsHor == 1 && ucHPos > 0)

             ucHPos--;

          else if (btIsHor == 0)

             ucVPos = 0;          

        }

        cValue = 0;

        v_SM_Printf( "\n%c",ucVPos * 0x40 + ucHPos);

      }

   }

}

Listing 44  Inhalt von TestSteuerungLCDCursor.c

Menüführung mit dem Inkrementalgeber

Im vorangegangenen Abschnitt haben sie den Umgang mit dem Inkrementalgeber in Verbindung mit dem LCD gelernt. Jetzt soll eine Menüführung mit Hilfe des Inkre­men­talgebers entstehen. In Abhängigkeit der Drehrichtung sollen unterschiedliche Menü­punk­te aus dem Array „aucHauptMenu“ (siehe Listing 45, ) angezeigt werden. Das Array selbst liegt im Speicherbereich „code“. Als Ende­kennung für die Liste ist eine Zeile mit Minuszeichen vorhanden (siehe ). Damit man er­kennt, dass die obere Zeile selektierbar ist, wird der Cursor nach Ausgabe des Textes an das erste Zeichen gesetzt (siehe ƒ). Nach dem Start des Programms werden die ersten zwei Zeilen des Arrays auf dem LCD ausgegeben. Das Programm wartet nun so­lange, bis der Inkrementalgeber gedreht wurde (siehe ). Ist der Wert von cValue positiv, wird überprüft, ob das untere Ende des Menüs ausgegeben ist. Diese Län­gen­­überprüfung erfolgt mit dem sizeof()-Operator (siehe ). Dieser Operator liefert eine Konstante, in diesem Fall die Gesamtlänge des Arrays (sizeof(aucHauptmenu)) und die Länge eines Eintrags (sizeof(aucHauptmenu[0])), zurück. Damit lässt sich errechnen, wie viele Menüeinträge vorhanden sind. Man hätte an dieser Stelle auch eine Konstante mit der Länge 5 einfügen können. Wird ein weiterer Eintrag hinzugefügt bzw. ein Eintrag entfernt, müsste in diesem Fall die Konstante um eins erhöhen bzw. erniedrigt werden. Beim sizeof()-Operator wird dies auto­ma­tisch beim Compilieren angepasst.

F !! Eine ausführliche Beschreibung zum sizeof()-Operator finden sie im Ka­pitel 11.9 [1]. !!

Nachdem der neue Offsetwert in der Variablen „ucMenuOff“ abgespeichert ist, wird die Variable cValue auf den Wert 0 gesetzt (siehe ). Das Programm gibt nun den zweiten und dritten Eintrag auf dem LCD aus und wartet danach wieder auf eine Änderung des Inkrementalgebers.

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_LCDMenu

Test_SteuerungLCDMenu

TestSteuerungLCDMenu.c

 

..\Library

Encoder_Lib.c, PortConfig.c, CGRAM_V7.c, sm_printf.c, LCDLib_4bitPort.c, itoa.a51, bcd2hex.a51

Tabelle 51  Projekt Test_LCDMenu

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

 

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <PortConfig.H>

#include <lcd_def.h>

#include <stdio.h>

 

unsigned char code aucHauptMenu[][17] ={"Ausgabe         ",

                                        "Einstellungen   ",

                                        "Test            ",

                                        "Reset           ",

                                        "----------------"};

 

void main(void)

{

   unsigned char ucMenuOff = 0;

   v_PortConfig(Port2, AllPins, BiDir); // Port 2 konfigurieren

   v_InitEncoder();             // Inkrementalgeber konfigurieren

   uc_LCDIni(_2LINE | _7DOTS);  // Initialisierung des HD44780

   EA = 1;                      // allg. Interruptsperre aufheben

 

   while(1)

   {

      printf( "\n%c%s",0, aucHauptMenu[ucMenuOff]);

      printf( "\n%c%s",0x40, aucHauptMenu[ucMenuOff + 1]);

      printf("\n%c",0x0);

      while(cValue == 0 && EncSwitch == 1);

      if (cValue > 0)

      {

        if (ucMenuOff < ((sizeof(aucHauptMenu)/

                          sizeof(aucHauptMenu[0]))-2))

          ucMenuOff++;

      }

      else

      {

        if (ucMenuOff > 0)

          ucMenuOff--;

      }

      cValue =0;

   }

}

Listing 45  Inhalt von TestSteuerungLCDMenu.c

Erstellen sie ein Projekt, das Untermenüs für jeden Eintrag anbietet. Mit Drücken der Taste des Inkrementalgebers soll der ausgewählte Menüeintrag übernommen werden. In der zwei­ten Zeile sollen die Untereinträge angezeigt und mit Hilfe des In­kre­men­tal­ge­bers verändert werden.

Die Untermenüs sind als eigenständige Arrays angelegt worden (siehe Listing 46, ). Somit wird nur soviel Speicherplatz belegt, wie jedes Untermenü benötigt. Bei einem mehrdimensionalen Array würde der Platzverbrauch immer vom größten Untermenü berechnet werden. Die Ausgabe auf dem LCD hängt jetzt von der Variablen „ucMenu“ ab. Enthält sie den Wert HAUPTMENU, werden beide Zeilen beschrieben, ansonsten nur die zweite Zeile (siehe ). Beim drücken der Taste wird „ucMenu“ überprüft (siehe ƒ). Befindet man sich im Haupt­menü, wird der aktuelle Offset von „ucMenuOff“ direkt als Menüeintrag über­nom­men. Die­se direkte Zuweisung ist nur deshalb möglich, weil dem HAUPTMENU der Wert „-1“ zugewiesen ist (siehe ). Andernfalls wird überprüft, ob man sich im ersten Untereintrag befindet (siehe ). In dem Fall wird zurück ins Haupt­me­nü verzweigt. Das switch-Konstrukt wurde um die Untereinträge erweitert (siehe ).

Projektname

Verzeichnis

Verwendete Sourcemodule

Test_2DimLCDMenu

Test_SteuerungLCDUnterMenu

Test_2DimLCDMenu.c

 

..\Library

Encoder_Lib.c, PortConfig.c, CGRAM_V7.c, sm_printf.c, LCDLib_4bitPort.c, itoa.a51, bcd2hex.a51

Tabelle 52  Projekt Test_2DimLCDMenu

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ƒ

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <REG932.H>

#include <Encoder_Lib.h>

#include <PortConfig.H>

#include <lcd_def.h>

#include <stdio.h>

enum enMenu {HAUPTMENU = -1, AUSGABE, EINSTELLUNGEN, TEST, RESET};

 

unsigned char code aucHauptMenu[][17] ={"Ausgabe         ",

                                        "Einstellungen   ",

                                        "Test            ",

                                        "Reset           ",

                                        "----------------"};

 

unsigned char code aucAusgabeMenu[][17] ={"Aus. Hauptmenu  ",

                                          "Aus. Eintrag 2  ",

                                          "Aus. Eintrag 3  ",

                                          "Aus. Eintrag 4  ",

                                          "----------------"};

 

unsigned char code aucEinstellMenu[][17] ={"Ein. Hauptmenu  ",

                                           "Ein. Eintrag 2  ",

                                           "Ein. Eintrag 3  ",

                                           "Ein. Eintrag 4  ",

                                           "----------------"};

 

unsigned char code aucTestMenu[][17] ={"Test Hauptmenu  ",

                                       "Test Eintrag 2  ",

                                       "Test Eintrag 3  ",

                                       "Test Eintrag 4  ",

                                       "----------------"};

 

unsigned char code aucResetMenu[][17] ={"Res. Hauptmenu  ",

                                        "Res. Eintrag 2  ",

                                        "Res. Eintrag 3  ",

                                        "Res. Eintrag 4  ",

                                        "----------------"};

 

void main(void)

{

   unsigned char ucMenuOff = 0;

   char ucMenu = HAUPTMENU;

   v_PortConfig(Port2, AllPins, BiDir); // Port 2 konfigurieren

   v_InitEncoder();             // Inkrementalgeber konfigurieren

   uc_LCDIni(_2LINE | _7DOTS);  // Initialisierung des HD44780

   EA = 1;                      // allg. Interruptsperre aufheben

 

   while(1)

   {

      if (ucMenu == HAUPTMENU)

      {

         printf( "\n%c%s",0, aucHauptMenu[ucMenuOff]);

         printf( "\n%c%s",0x40, aucHauptMenu[ucMenuOff + 1]);

         printf("\n%c",0x0);

      }

      else

      {

        switch(ucMenu)

        {

        case AUSGABE:

         printf( "\n%c%s",0x40, aucAusgabeMenu[ucMenuOff]); break;

        case EINSTELLUNGEN:

        printf( "\n%c%s",0x40, aucEinstellMenu[ucMenuOff]); break;

        case TEST:

         printf( "\n%c%s",0x40, aucTestMenu[ucMenuOff]); break;

        case RESET:

         printf( "\n%c%s",0x40, aucResetMenu[ucMenuOff]); break;

        }

        printf("\n%c",0x40);      

      }

 

      while(cValue == 0 && EncSwitch == 1);

      if (EncSwitch == 0)

      {

         if (ucMenu == HAUPTMENU)

         {

           ucMenu = ucMenuOff;

           ucMenuOff = 0;

         }

         else

         {

           if (ucMenuOff == 0)

              ucMenu = HAUPTMENU;

         }

         while (EncSwitch == 0);

      }

      if (cValue > 0)

      {

        switch(ucMenu)

        {

        case HAUPTMENU:

           if (ucMenuOff < ((sizeof(aucHauptMenu)/

                             sizeof(aucHauptMenu[0]))-2))

              ucMenuOff++; break;

        case AUSGABE:

           if (ucMenuOff < ((sizeof(aucAusgabeMenu)/

                             sizeof(aucAusgabeMenu[0]))-2))

              ucMenuOff++; break;

        case EINSTELLUNGEN:

           if (ucMenuOff < ((sizeof(aucEinstellMenu)/

                             sizeof(aucEinstellMenu[0]))-2))

              ucMenuOff++; break;

        case TEST:

           if (ucMenuOff < ((sizeof(aucTestMenu)/

                             sizeof(aucTestMenu[0]))-2))

              ucMenuOff++; break;

        case RESET:

           if (ucMenuOff < ((sizeof(aucResetMenu)/

                             sizeof(aucResetMenu[0]))-2))

              ucMenuOff++; break;

        }

      }

      else

      {

        if (ucMenuOff > 0)

          ucMenuOff--;

      }

      cValue =0;

      printf("\n%c",0x3);

   }

}

Listing 46  Inhalt von Test_2DimLCDMenu.c