Forum: Mikrocontroller und Digitale Elektronik Menü Programmierung


von Tester (Gast)


Lesenswert?

Hallo Forum,
Ich bin noch recht neu auf dem Gebiet µC und habe schon einpaar 
Programme geschrieben und nun würde ich gerne mal mit einem Menü was 
machen aber leider weis ich nicht wie

gibt es da ein Tut oder eine Vorlage für?
habe leider nichts selbst gefunden :(

Ich nutzte das Display was auf dem Pollin Addon ist falls das weiter 
hilft

von Bastler (Gast)


Lesenswert?

Mein Tip:

Stift und Blatt Papier

...zeichne dir dein Vorhaben auf, das hilft weiter.

Läuft vermutlich auf ein großes switch / case raus.


Menü? ..wo?  im Hyperterminal? auf einem Display? grafisch?
 nur Text? in Restaurant? (ok, Joke)

von Ano (Gast)


Lesenswert?

Klassischerweise macht man das mit nem Zustandsautomat in irgendeiner 
Form.

Was passiert denn?
Knopf A -> Menüpunkt 1
Knopf B -> Menüpunkt 2
etc...

von Bastler (Gast)


Lesenswert?

Ich würde es über vier Taster steuern:

1. Hoch (Menüpunkt++)
2. Runter (Menüpunkt--)
3. Auswahl
4. Zurück


und dahinter wie bereits erwähnt das switch / case...

von Tester (Gast)


Lesenswert?

Hallo,
danke für die schnellen Antworten
Das Menü soll auf einem Text-LCD ablaufen
über drei Taster
Taster1=hoch
Taster2=runter
Taster3=enter

Als Programmiersprache verwende ich übrigens C

von pacer (Gast)


Lesenswert?

Wenn du einigermaßen gut in C bist, schau dir doch mal den Code vom 
AVR-Butterfly an. Der ist frei verfügbar und hat ein mehrstufiges Menü.

von Bastler (Gast)


Lesenswert?

Bei drei taster würde ich in jedem Untermenü ein Feld für "Zurück" 
einbauen.

von Tester (Gast)


Lesenswert?

pacer schrieb:
> Wenn du einigermaßen gut in C bist, schau dir doch mal den Code vom
>
> AVR-Butterfly an. Der ist frei verfügbar und hat ein mehrstufiges Menü.

Da ich noch recht neu im bereich µC bin sind meine C-Kenntnisse auch 
noch nicht so umwerfend :(
Ich habe mir den Code vom Butterfly mal rausgesucht und angeschaut...
der ist im gegensatzt zu meinen bisherigen Programme ein Riese!


Ich wollte erstmal mit drei Menüpunkten anfangen die ich später 
erweitern wollte mit untermenüs.
Wisst Ihr da vielleicht etwas einfacheres?
Wäre schön wenn da jemand ein klerines Beispiel hätte =)

Bastler schrieb:
> Ich würde es über vier Taster steuern:
>
>
>
> 1. Hoch (Menüpunkt++)
>
> 2. Runter (Menüpunkt--)
>
> 3. Auswahl
>
> 4. Zurück

Das könnte ich auch machen über vier Tastern

von Ano (Gast)


Lesenswert?

Switch Case
Zustandsautomat

Das sind deine Freunde. Ansonsten vielleicht erstmal mit Hallo Welt und 
konsorten Anfangen ;)

von Tom (Gast)


Lesenswert?

Das ist ein interessantes Thema.

Ich habe mir in letzter Zeit auch Gedanken gemacht. Wie man Menus am 
besten angeht. Wichtig ist ja bei der ganzen Sache auch, das das 
Programm flexibel bleibt, man Menu´s ohne viel Aufwand ändern kann und 
einzelne Menupunkte auch mal verschieben kann.

Ob man jetzt zur Bedienung vier Tasten braucht ist GeschmacksSache.

So einer Taste kann man verschiedene Zustände entlocken.
Taste kurz gedrückt, Taste lange gedrückt oder Taste sehr lange 
gedrückt.

Darüber könnte man am Ende sogar seine "zurückFunktion" machen.

Mal die drei Zustände an einer Taste abfragen, ist eine gute Fingerübung
zum Programmieren.

Eine gute Routine zur Tastenabfrage ist das A & O!

Das mit der Statemachine erschließt sich mir nicht ganz. Das Beispiel 
mit der Ampel läßt sich schlecht für ein Menu umdenken.

Hat jemand mal ein Codeschnipsel für ein Menu mit dieser switch/case 
Sache?

Ansonsten hab ich mal gesehen das sich Menus recht einfach über 
FunktionsZeiger und Tabellen realisieren lassen.

Aber das mit dem switch/case sieht nach ganz schönem Geraffel aus.
Erinnert mich ein bißchen an die ersten Menus in BASIC.

IF A$= "1"
 PRINT "eins" .... ;)

Aber wie gesagt. Es wäre schön wenn jemand mal eine Bespiel für ein Menu 
mit switch/case hätte.

von spess53 (Gast)


Lesenswert?

Hi

>Eine gute Routine zur Tastenabfrage ist das A & O!

Ein Drehgeber mit Tastenfunktion geht auch ganz gut.

>Aber wie gesagt. Es wäre schön wenn jemand mal eine Bespiel für ein Menu
>mit switch/case hätte.

Ehrlich gesagt, so etwas tue ich mir noch nicht einmal in Assembler an. 
Unter einer Hochsprache bietet sich eine verkettete Liste an.

MfG Spess

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Könnte eine Statemachine so aussehen?

Das ist ja einfach, und ich dachte ein Zustandsautomat wäre urst 
kompliziert.
Kann man da noch den Überblick behalten, wenn mehrere Tasten zur Auswahl 
stehen?

@spess
Wie funktioniert es in Assembler?
Wenn das Menu mit einer verketteten Liste aufgebaut ist, muss man da bei
Veränderungen nicht gleich mehrere Stellen ändern?

von spess53 (Gast)


Lesenswert?

Hi

>@spess
>Wie funktioniert es in Assembler?
>Wenn das Menu mit einer verketteten Liste aufgebaut ist, muss man da bei
>Veränderungen nicht gleich mehrere Stellen ändern?

Die Anregung 'Verkettete Liste' war eigentlich primär für Hochsprachen 
gedacht. Allerdings dürfte der der 'Veränderungsaufwand' dort genau so 
hoch sein wenn die Liste programmiert wird. Also wenn man ein 
Listenelement nachträglich einfügt muss man mindesten 4 Werte ändern. 
Bei Assembler sind es auch nicht mehr. Für Assembler habe ich das 
eigentlich bisher nur angedacht.
Das letzte Menü (Assembler) habe ich über Sprungtabellen/Listen 
realisiert.  Vereinfacht: jeder Menüpunkt hat eine eigene Nummer über 
die Beschriftung, Behandlungsroutine, Exitroutine usw. bestimmt werden.
Also keine verkettet Liste, aber auch keine cpi/brne-Orgie.

MfG Spess

von Tom (Gast)


Lesenswert?

Stimmt, Assembler hat ja die Sprungtabellen. Da kann man ja mit ijmp 
bequem überall hinspringen.

von spess53 (Gast)


Lesenswert?

Hi

>Stimmt, Assembler hat ja die Sprungtabellen. Da kann man ja mit ijmp
>bequem überall hinspringen.

In dem Fall mit icall über die Sprungtabelle zur Routine.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:
> Könnte eine Statemachine so aussehen?
>
> Das ist ja einfach, und ich dachte ein Zustandsautomat wäre urst
> kompliziert.
> Kann man da noch den Überblick behalten, wenn mehrere Tasten zur Auswahl
> stehen?

Na ja, bis zu einem Menüsystem ist da schon noch ein weiter weg

Ein universelles Menüsystem baut darauf auf, dass man in einer 
Datenbeschriebung alles zusammenfasst, was es einen Menüpunkt ausmacht.
Also: Den anzuzeigenden Text und eine Möglichkeit, wie man die zum 
Menüpunkt gehörende Funktionalität beschreiben kann.
Text ist wohl klar.
Die Funktionalität kann man im einfachsten Fall so aufbauen, dass man 
einen Funktionszeiger auf eine Funktion installiert, die aufgerufen 
werden soll, wenn genau dieser Menüpunkt ausgewählt wird.

Postulat: gegeben seien 3 Tasten. Ihre Bedeutung ist:
  Vorhergehender Menüpunkt (wenn einer existiert)
  nachfolgender Menüpunkt (wenn einer existiert)
  Menüpunkt auswählen

weiter sei ein Menüpunkt so aufgebaut
1
typedef void (*MenuFnct)(void);
2
3
struct MenuEntry
4
{
5
  char     Text[20];      // anzuzeigender Text
6
  MenuFnct Function;      // auszuführende Funktion, wenn der Menüpunkt
7
                          // ausgewählt wird
8
};
damit kann man erst mal einen Menüpunkt definieren, zb "Help" und wenn 
der ausgewählt wird, dann soll die Funktion Help() aufgerufen werden
1
void Help()
2
{
3
  ... mach irgendwas
4
}
5
6
struct MenuEntry = { "Help", Help };

Soweit so gut. Aber das ist ja noch kein Menü.
Was ist denn ein Menü?
Ein Menü ist eine Sammlung von Menüpunkten, also mehrere.
Das stellt jetzt erst mal kein Problem dar, denn das kann im einfachsten 
Fall einfach nur ein Array von derartigen Menüpunkten sein. Du möchtest 
zb ein Menü haben, welches die Menüpunkte "Options", "Zeit" und "Hilfe" 
umfasst. Wenn "Options" ausgewählt wird, dann soll die Funktion 
Options() aufgerufen werden, bei "Zeit" die Funktion Time() und bei 
"Hilfe" soll Help() aufgerufen werden:
1
void Options()
2
{
3
}
4
5
void Time()
6
{
7
}
8
9
void Help()
10
{
11
}
12
13
struct MenuEntry MainMenu[] =
14
{
15
  { "Optionen", Options },
16
  { "Uhrzeit",  Time },
17
  { "Hilfe",    Help }
18
};

soweit so gut.
Was jetzt noch benötigt wird, ist eine Funktion, die das Menü zum Leben 
erweckt. Bis jetzt gibt es das Menü ja nur als Datenstruktur.

Was heißt denn zum Leben erwecken? Was muss die Funktion machen?
Sie muss ganz sicher erst einmal alle Menüpunkte an das LCD schreiben.
Dann muss sie weiters die Tasten überwachen. Die Funktion wird so etwas 
wie einen gerade "ausgewählten" Menüpunkt brauchen. Mit den Tasten kann 
dann der nächste bzw der vorhergehende Menüpunkt ausgewählt werden. Und 
wenn der Benutzer diesen Menüpunkt haben will, dann soll diese 
Menüsteuerung genau die zu diesem Menüpunkt gehörende Funktion aufrufen. 
Kommt die Funktion zurück, dann bekommt diese Menüsteuerung wieder die 
Kontrolle und weiter gehts mit der Tastenüberwachung.
Zusätzlich vereinbaren wir noch: Gibt es zu einem Menüpunkt keinen 
Funktionspointer, dann behandelt das die Menüsteuerung als "Menü 
abbrechen und zurückkehren zum Aufrufer". Wozu das gut sein soll, siehst 
du dann, wenn ein Submenü gemacht wird, das einen Menüpunkt "Exit" hat, 
der wieder zum Hauptmenü zurückkehrt. Dort wird das dann eingesetzt.

Zurück zur Menüsteuerung. Das ist eine Funktion die 2 Informationen 
erhält: Nämlich einen Verweis auf das Menü-Array und die Größe dieses 
Arrays (weil ja Funktionen diese Größe nicht selbst eruieren können)

Beschäftigen wir uns mit dem ersten Teil, den die Funktion machen soll: 
Das Hinschreiben der Menütexte. Dazu schreiben wir gleich wieder eine 
eigene Funktion, um diesen Teil aus der Menüsteuerung rauszuhalten. Die 
Hinschreib-Funktion ist sehr einfach. Auch sie kriegt die Größe des 
Arrays und einen Verweis auf das Array selber
1
void DrawMenu( int MenuSize, struct MenuEntry Menu[] )
2
{
3
  int i;
4
5
  lcd_clr();
6
  for( i = 0; i < MenuSize; ++i )
7
  {
8
    lcd_goto_xy( 2, i );
9
    lcd_write( Menu[i].Text );
10
  }
11
}

Das pinselt alle Menüpunkte beginnend in der Spalte 2 untereinander auf 
ein LCD. Ich hab jetzt einfach von ein paar LCD Funktionen angenommen, 
das sie existieren. Was sie tun sollte selbst erklärend sein.

Warum Spalte 2?
Weil ich vor dem Menüpunkt etwas Platz brauche um dort meinen 'Dieser 
Menüpunkt wäre es, wenn du jetzt bestätigen' Marker unterzubringen. Der 
Einfachheit halber mach ich einfach vor den ausgwewählten Menüpunkt ein 
Sternchen '*' hin, damit der Benutzer eine Rückmeldung hat, welcher 
Menüpunkt denn jetzt gilt. Im Grunde verschiebt er also einfach nur 
dieses Sternchen in den Menüzeilen am LCD wobei die Menüfunktion 
natürlich darüber Buch führen muss, wo denn nun eigentlich das Sternchen 
ist.

Also fangen wir mal an
1
void DoMenu( uint8_t MenuSize, struct MenuEntry Menu[] )
2
{
3
  uint8_t active = 0;     // active sei der momentan ausgewählte Menüpunkt
4
  uint8_t running;
5
6
  DrawMenu( MenuSize, Menu );    // alles hinpinseln lassen
7
8
  // die Markierung für den Benutzer (das Sternchen) hinmalen
9
  lcd_gotoxy( 0, active );
10
  lcd_write( "*" );
11
12
  running = TRUE;
13
14
  // soweit ist alles aufgesetzt, ab jetzt werden die Tasten überwacht
15
  // und das Menü soll arbeiten
16
  while( running )
17
  {
18
    if( get_keypress( UP ) )   // Taste "Rauf" gedrückt ?
19
    {
20
      if( active > 0 )         // geht da überhaupt was?
21
      {
22
        lcd_gotoxy( 0, active );    // ja, tut es. Das Sternchen wegnehmen
23
        lcd_write( " " );
24
25
        active--;
26
27
        lcd_gotoxy( 0, active );    // und neu hinsetzen, in die Zeile davor
28
        lcd_write( "*" );
29
      }
30
    }
31
32
    else if( get_keypress( DOWN ) )  // Taste "Runter" gedrückt?
33
    {
34
      if( active < MenuSize - 1 )    // geht das überhaupt
35
      {
36
        lcd_gotoxy( 0, active );     // ja, da gibt es noch einen Menupunkt
37
        lcd_write( " " );
38
39
        active++;
40
41
        lcd_gotoxy( 0, active );
42
        lcd_write( "*" );
43
      }
44
    }
45
46
    else if( get_keypress( EXECUTE ) ) // Taste "Ausführen" gedrückt?
47
    {
48
      if( Menu[active].Function )      // gibt es eine auszuführende Funktion?
49
        Menu[active].Function();       // Ja: führe sie aus
50
      else
51
        running = FALSE;               // Nein: Das war der "Exit" Menüpunkt
52
                                       // Menüsteuerung beenden
53
    }
54
  }
55
}

Tja. Und das wars im Großen und Ganzen auch schon.
Die Funktion DoMenu nimmt sich die Menübeschreibung aus dem Array und 
führt die entsprechenden auf Benutzerwunsch hin aus.

(2. Posting kommt noch)

von Karl H. (kbuchegg)


Lesenswert?

Ein Menu kann jetzt auch über Submenues verfügen. Auch das ist kein 
Problem. Alles was man braucht, ist eine Funktion die wieder ein neues 
Menü startet.

Die Menühierarchie soll zb so aussehen

   Optionen                             -> Funktion  Options()
   Uhrzeit   ->  SubMenu   Stunden      -> Funktion  Hours()
        ^                  Minuten      -> Funktion  Minutes()
        +----------------- Exit

(Bei Auswahl von Uhrzeit kommt man in ein Submenu mit den Menüpunkten 
"Stunden" und "Minuten". Mit dem Punkt "Exit" kommt man aus dem Submenu 
wieder zurück ins Hauptmenü.
1
typedef void (*MenuFnct)(void);
2
3
struct MenuEntry
4
{
5
  char     Text[20];      // anzuzeigender Text
6
  MenuFnct Function;      // auszuführende Funktion, wenn der Menüpunkt
7
                          // ausgewählt wird
8
};
9
10
void DoMenu( uint8_t MenuSize, struct MenuEntry Menu[] )
11
{
12
   .... wie gehabt
13
}
14
15
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
16
17
void Hours()
18
{
19
  ...
20
}
21
22
void Minutes()
23
{
24
  ...
25
}
26
27
struct MenuEntry TimeMenu[] =
28
{
29
  { "Stunden", Hours },
30
  { "Minuten", Minutes },
31
  { "Exit",    NULL }
32
};
33
34
void Options()
35
{
36
}
37
38
void Time()
39
{
40
  DoMenu( ARRAY_SIZE( TimeMenu ), TimeMenu );
41
}
42
43
struct MenuEntry MainMenu[] =
44
{
45
  { "Optionen", Options },
46
  { "Uhrzeit",  Time },
47
};
48
49
int main()
50
{
51
   ....
52
53
   while( 1 )
54
   {
55
      .....
56
57
      DoMenu( ARRAY_SIZE( MainMenu ), MainMenu );
58
59
      .....
60
   }
61
}

Eine kleine Ergänzung sollte man in DoMenu dann noch vornehmen: Wenn 
DoMenu die Funktion aufruft, sollte sie vorher das LCD löschen um der 
Funktion keine Altlasten zu hinterlasten und es sollte nachdem die 
Funktion zurückgekehrt ist, sein Menü-Display wieder neu aufbauen.

Aber das ist ja kein Problem
1
void DoMenu( uint8_t MenuSize, struct MenuEntry Menu[] )
2
{
3
  uint8_t active = 0;     // active sei der momentan ausgewählte Menüpunkt
4
  uint8_t running;
5
6
  .....
7
8
9
    else if( get_keypress( EXECUTE ) ) // Taste "Ausführen" gedrückt?
10
    {
11
      if( Menu[active].Function )      // gibt es eine auszuführende Funktion?
12
      {
13
        lcd_clr();                     // vorher Display löschen
14
        Menu[active].Function();       // Funktion ausführen lassen
15
        DrawMenu( MenuSize, Menu );    // Menütexte neu aufbauen lassen
16
        lcd_gotoxy( 0, active );       // und die Markierung für den aktiven Menüpunkt
17
        lcd_write( "*" );              // neu setzen
18
      }
19
      else
20
        running = FALSE;               // Nein: Das war der "Exit" Menüpunkt
21
                                       // Menüsteuerung beenden
22
    }
23
  }
24
}

von Karl H. (kbuchegg)


Lesenswert?

Anzumerken sei noch, dass das EINE Möglichkeit ist, wie man universelle 
Menüs aufbauen kann.

Eine ganz andere Möglichkeit besteht zb darin, dass man in einem 
Menüpunkt beschreibt, wer sein vorhergehender Menüpunkt ist, wer sein 
Nachfolger ist, welcher Menüpunkt sich als Submenü auftun soll, wie man 
wieder zurück kommt und welche Funktion aufgerufen werden soll.

Das oben gezeigte Menü könnte dann zb inclusive des Submenues so 
aussehen
1
struct LinkedEntry[] =
2
{
3
  { "Optionen", 1, 2, -1, -1, Options },   // 0
4
  { "Uhrzeit",  2, 0,  3, -1, NULL    },   // 1
5
  { "Hilfe",    0, 1, -1, -1, Help    },   // 2
6
  { "Stunden",  4, 5, -1, -1, Hours   },   // 3
7
  { "Minuten",  5, 4, -1, -1, Minutes },   // 4
8
  { "Exit",     3, 4, -1,  1, NULL    }    // 5
9
}

Die 4 Zahlen bei jedem Menüpunkt bedeuten jeweils

* welches ist der nächste Menüpunkt
  welches wird also aktiv, wenn Taste "Runter" gedrückt wird
* welches ist der vorhergehende Menüpunkt
  welcher wird also aktiv, wenn Taste "Rauf" gedrückt wird
* welches ist der erste Menüpunkt eines Submenüs
  wenn die Taste "Ausführen" gedrückt wird und der Menüpunkt in ein
  Submenü verzweigt
* welches ist der Menüpunkt (und damit welches Menü) der aktiv
  ist, wenn aus einem Submenü wieder ausgestiegen werden soll

(wobei -1 jeweils einen Nicht-Eintrag kennzeichnet)

Auch das ist eine Möglichkeit.
Oder man könnte ....
Man könnte aber auch ....

Es gibt viele Möglichekeiten, wie man allgemeine Menüsysteme aufziehen 
kann. Welches vernünftig ist, hängt auch ein wenig von der Anwendung 
selber ab.
Einfach mal ein wenig experimentieren.

von Tom (Gast)


Lesenswert?

Vielen Dank Karl-Heinz.
Das ist recht wertvoll was Du hier geschrieben hast. Es sollte 
vielleicht in die Artikelsammlung oder ins Tutorial.

von Tom B. (botas)


Lesenswert?

Wenn man es wie Karl-Heinz macht und es noch etwas weiter spinnt (kein 
Array benutzen, sondern direkt Pointer auf die Structs statt Zahlen) 
dann kann man die Daten auch noch gleich in den Flash schreiben. So kann 
man sich dann immer den gerade nötigen Teil laden.
Warum? Weil so ein Menü schnell mal das eine oder andere kb groß werden 
kann. Wenn man nur 2-4 kb RAM hat ist das schlecht auf dem Stack unter 
zu bringen.
Ich hoffe es war verständlich was ich meine.

von Nachtaktiver (Gast)


Lesenswert?

Das was hier Karl-Heinz Buchegger geschrieben hat mir persönlich immens 
weiter geholfen. Aber nun hat sich bei mir eine Frage ergeben.

1
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))

Mit dieser Definition bekommt man die größe eines beliebigen Array und 
der Präprozessor (?) ersetzt diese durch den exakten Wert.
Ich benutzte diese Definition damit ich mit den "UP/DOWN Tasten" einen 
Ringdurchlauf durch das Menu machen kann.
Also damit wenn ich mich im Menü auf den letzten Eintrag stehe ich bei 
einen erweiterten "UP" Tastendruck auf den ersten Menüeintrag stehe (und 
umgekehrt)

Nun habe ich aber das Problem das wenn ich einen Menüeintrag auswähle 
(und in ein Submenü reinspringe) , das dieser wieder unterschiedlich 
viele Einstellungen hat wo ich wieder die Arraygröße benötige womit ich 
wieder einen Ringdurchlauf ermöglichen kann.

Da ich die aus einen Wert die Menüeintrag kenne in den ich 
hereingesprungen bin habe ich mir überlegt das ich mir ein Array anlege 
in denen ich für jeden Menüeintrag die maximalen Einträge kenne.

Die Frage ist:
Wie kann man sich ein Array mit konstanten Arraygrößen anlegen?
Mit den oben dargestellten Definition Funktioniert das bei einer 
Struktur leider nicht. Ansonsten benutze ich diese Definition 
erfolgreich.

Natürlich kann ich auch die Werte einfach abzählen und die richtigen 
Werte reinschreiben, aber ich würde es gerne per Definition machen. =)

Damit man sich das vorstellen kann:
1
struct MenuEntry
2
{
3
  char    Number    [4];  
4
  char    Text    [20];   
5
  MenuFnct  Function;                       
6
};
7
8
9
struct ValueEntry
10
{
11
  char    Numer    [4];
12
  char    Text    [20];
13
  unsigned char   Parameter;    
14
};
15
16
17
struct MenuEntry SettingMenu[] =
18
{
19
  { "1." , "Backlight"    , NULL},
20
  { "2." , "LCD-Contrast"  , NULL },
21
  { "3." , "Temperature"  , NULL },
22
};
23
24
struct ValueEntry Backlight[] =
25
{
26
  { "1.", "On" , 0x01},
27
  { "2.", "Off", 0x00},
28
};
29
30
struct ValueEntry LCD_Contrast[] =
31
{
32
  { "1.", "1/8", 0x01 },
33
  { "2.", "2/8", 0x02}},
34
  { "3.", "3/8", 0x03 },
35
  { "4.", "4/8", 0x04 },
36
  { "5.", "5/8", 0x05 },
37
  { "6.", "6/8", 0x06 },
38
  { "7.", "7/8", 0x07 },
39
  { "8.", "8/8", 0x08 },
40
};
41
42
struct ValueEntry Temperature[] =
43
{
44
  {"1.", "°C", NULL },
45
};
46
47
48
49
struct ArraySize
50
{
51
 unsigned char Size;
52
}


So sollte meine Wunschstruktur aussehen:
1
struct ArraySize SettingSubmenu[] =
2
{
3
  { /* Hier sollte 1 stehen */}, // Anzahl Unterpunkte von Backlight-1
4
  { /* Hier sollte 7 stehen */}, // Anzahl Unterpunkte von LCD-Contrast-1
5
  { /* Hier sollte 0 stehen */}, // Antahl Unterpunkte von Temperature-1
6
};

von Karl H. (kbuchegg)


Lesenswert?

Mir ist zwar nicht klar, warum du dafür ein eigenes Array machen willst 
und die Größe der Submenüs nicht dort mit abspeicherst, wo sie 
hingehört, nämlich in die struct MenuEntry, aber grundsätzlich würde das 
so aussehen
1
struct ArraySize SettingSubmenu[] =
2
{
3
  { ARRAY_SIZE( Backlight ) - 1 },
4
  { ARRAY_SIZE( LCD_Contrast ) - 1 },
5
  { ARRAY_SIZE( Temperature ) - 1 },
6
};

das erfüllt deine Vorgabe.

Aber wenn du genauer darüber nachdenkst, brauchst du dieses Array an 
sich gar nicht. Denn an der Stelle, an der du aus dem Menüpunkt für 
"Backlight" ableitest, dass dafür das Array Backlight zuständig ist, 
kannst du genausogut dort die ARRAY_SIZE von Backlight benutzen um die 
Anzahl der Menüpunkte zu erhalten und mit der an dieser Stelle dort 
weiterarbeiten.

Was anderes habe ich ja hier
1
void Time()
2
{
3
  DoMenu( ARRAY_SIZE( TimeMenu ), TimeMenu );
4
}
auch nicht gemacht.
Die Time Funktion weiß, dass sie das Array 'TimeMenu' als neues Menü 
aktivieren muss, und zu diesem Zwecke lässt es sich mittels ARRAY_SIZE 
die größe dieses Arrays ermitteln.

PS: Musst du wirklich die Menupunkt Nummerierung mit in die Menüpunkte 
aufnehmen? Die nehmen nur Platz weg und solange die Menüpunkte sowieso 
von 1 beginnend durchnummeriert werden, lässt sich dieser Teil ja auch 
zur Laufzeit ganz leicht generieren.

von Nachtaktiver (Gast)


Lesenswert?

Du hast mir wirklich weitergeholfen. Ich habe so viel experimentiert und 
habe das eigentliche Ziel verloren. Die Arraygröße selbst hatte ich in 
den Unterpunkten des Submenus selbst abspeichern wollen und es hatte 
mich gestört das ich dann z.B für die Backlightfunktion 8 mal die 
Arraygröße speicher obwohl ich das gar nicht brauche. Dabei kann ich 
doch einfach die Struktur "SettingMenu" um einen Wert erweitern und dort 
die Arraygröße
des Submenüs ablegen. =D

Eine Erklärung warum ich das so gerne machen würde:

Ich selber habe nicht deine Menüführung übernommen, sondern habe auf 
Basis darauf mein eigenes Untermenü entworfen. Es ist aber wirklich gut 
gewesen, mal zu sehen wie man es machen könnte. Mit meinen ersten 
Versuchen bin ich Kläglich gescheitert da ich gar nicht "wusste" was man 
alles mit z.B Strukturen anstellen kann. Ich selber habe viele Blätter 
Papier vollgeschrieben und hatte ganz merkwürdige if else if Klamotten 
angefangen welche ziemlich daneben gegangen sind.

Meine Menüführung besteht darin das die Funktion "Zeige das Setting 
Menü" aus 2 Unterpunkten besteht welche aus einmal den Main Teil und 
einen Sub Teil besteht. Den Mainteil habe ich schon fertig und dieser 
Funktioniert richtig gut.

Das Problem war wenn man einen Unterpunkt angewählt hatte ich keinen 
Wert habe welcher mir Rückschlüsse gibt wie viele Menüunterpunkte es 
überhaupt gibt. Erstmal wollte ich es über einen Funktionsaufruf machen, 
da man in einer Struktur selbst einen Funktionsaufruf integrieren kann, 
aber das wurde mir ein wenig zu unübersichtlich und gefällt mir 
persönlich nicht so.
Dementsprechend die Nachfrage nach eine Struktur mit den Arraygrößen der 
einzelnen Unterpunkten. - Wobei ich jetzt feststellen muss das dass 
natürlich quatsch ist.

Wenn ich vom Hauptmenü in das Submenü gesprungen bin kann ich mit den 
Index des MenuEntry SettingMenu [] eindeutig das jetzige Position 
bestimmen an der ich mich befinde (Ist ja logisch). Also habe ich 
verzweifelt nachgedacht damit ich mit diesen Index gleichzeitig auf die 
Array größe schließen kann. Wenn ich zu jeder Zeit die richtige Größe 
abfragen kann kann ich das komplette Menü nun konstruieren.
Man stellt sich ganz doof als Anfänger an wenn man gerade
nicht weiter weiß "Wie man es machen würde".


Das P.S: werde ich beachten und ich werde mal schauen was ich mir dafür 
speziell ausdenken werde. Das ganze ist jetzt nur ein Prototyp da 
hinterher das meinste im Flashspeicher abgelegt wird. (Davon kann ich 
viel mehr "verschwenden" als RAM)


Vielen Dank für deine wirklich Hilfreiche Antwort. =)

von Nachtaktiver (Gast)


Lesenswert?

Ist nicht beabsichtig aber ich habe mal wieder eine Frage und würde 
gerne
wissen ob jemand eine Idee hat wie man es auch anders lösen könnte.

Speziell geht es nun darum das ich wenn ich von den MainManu "Options" 
in das ein Submenü gesprungen bin - Gar nicht weiß in welche Submenü 
Struktur ich anzeigen soll. Gelöst habe ich das mit einen switch case, 
da man Anhand der letzten Menüposition schließen kann welches Submenü 
angezeigt werden soll.

Das Funktioniert zwar, gefällt mir aber nicht ganz so richtig da ich für 
jedes Submenü einen neuen "case" brauche. Es mag zwar sich hier um nur 3 
Einträge handeln, aber in wirklichkeit kommen da noch eine Handvoll 
Einträge hinzu.
1
volatile unsigned char  SELECTED_MAIN_MENU;
2
3
#define          No_Menu          0
4
#define          ChangeOptions_Menu    1
5
#define          ChangeVoltage_Menu    2
6
#define          ChanceCurrent_Menu    3
7
#define          SwitchKeylock_Menu    4
8
9
volatile unsigned char  ACTIVE_MENU;
10
11
#define          NoMenu          0
12
#define          MainMenu        1
13
#define          SubMenu          2
14
15
volatile unsigned char  ACTIVE_SUBMENU;
16
17
#define          Backlight_SubMenu    0
18
#define          LcdContrast_SubMenu    1
19
#define          Temperature_SubMenu   2
20
21
volatile unsigned char  MENU_POSITION;
22
volatile unsigned char  SUBMENU_POSITION;
23
24
25
void  SwitchBacklight_On()
26
{
27
    PORTA_EXPANDER_DATABYTE |= (1<<PIN_BACKLIGHT);
28
    Expander_Set_PORTA( PORTA_EXPANDER_DATABYTE);
29
}
30
31
void  SwitchBacklight_Off()
32
{
33
    PORTA_EXPANDER_DATABYTE &= ~(1<<PIN_BACKLIGHT);
34
    Expander_Set_PORTA( PORTA_EXPANDER_DATABYTE);
35
}
36
37
void ShowOptions_Menu( void)
38
{  
39
cli();
40
41
  if( !ACTIVE_MENU)
42
  {
43
  MENU_POSITION  = 0;
44
  SUBMENU_POSITION= 0;
45
  ACTIVE_MENU   = MainMenu;
46
  }
47
48
  switch( ACTIVE_MENU)
49
{
50
  case MainMenu:
51
  
52
  LCD_Clear();
53
  LCD_Cursor_Home();
54
  LCD_String_Progmem( SETTING_STRING);
55
  LCD_Cursor_Set( 2, 0);
56
  
57
      if( (KEY_B).CLICKS_SHORT)
58
    {
59
          if( MENU_POSITION == 0)
60
        {
61
            MENU_POSITION = (ARRAY_SIZE (OptionsMenu) -1);
62
            (KEY_B).CLICKS_SHORT--;
63
        }
64
      
65
          else
66
        {
67
            MENU_POSITION--;
68
            (KEY_B).CLICKS_SHORT--;
69
        }
70
    }
71
72
      else if ( (KEY_C).CLICKS_SHORT)
73
    {
74
          if( MENU_POSITION == ARRAY_SIZE(OptionsMenu)- 1)
75
        {
76
            MENU_POSITION=0;
77
            (KEY_C).CLICKS_SHORT--;
78
        }
79
80
          else
81
        {
82
            MENU_POSITION++;
83
            (KEY_C).CLICKS_SHORT--;
84
        }
85
    
86
    }
87
          
88
      else if( (KEY_D).CLICKS_SHORT)
89
  
90
    {
91
        ACTIVE_MENU = SubMenu;
92
        (KEY_D).CLICKS_SHORT--;      
93
    }
94
95
    
96
      else if( (KEY_A).CLICKS_SHORT)
97
    {
98
        ACTIVE_MENU = NoMenu;        
99
        (KEY_A).CLICKS_SHORT--;
100
    }
101
102
  LCD_String( OptionsMenu[MENU_POSITION].Number);
103
  LCD_String( OptionsMenu[MENU_POSITION].Text);  
104
105
  break;
106
107
  
108
  case SubMenu:
109
110
  LCD_Clear();
111
  LCD_Cursor_Home();
112
  LCD_String( OptionsMenu[MENU_POSITION].Text);  
113
  LCD_Data(':');
114
  LCD_Cursor_Set( 2, 0);
115
116
      if( (KEY_B).CLICKS_SHORT)
117
    {
118
          if( SUBMENU_POSITION == 0)
119
        {
120
            SUBMENU_POSITION = OptionsMenu[MENU_POSITION].ArraySize;
121
            (KEY_B).CLICKS_SHORT--;
122
        }
123
      
124
          else
125
        {
126
            SUBMENU_POSITION--;
127
            (KEY_B).CLICKS_SHORT--;
128
        }
129
    }
130
131
      else if ( (KEY_C).CLICKS_SHORT)
132
    {
133
          if( SUBMENU_POSITION == OptionsMenu[MENU_POSITION].ArraySize)
134
        {
135
            SUBMENU_POSITION=0;
136
            (KEY_C).CLICKS_SHORT--;
137
        }
138
139
          else
140
        {
141
            SUBMENU_POSITION++;
142
            (KEY_C).CLICKS_SHORT--;
143
        }
144
    
145
    }  
146
147
      
148
      else if( (KEY_A).CLICKS_SHORT)
149
    {
150
        ACTIVE_MENU = MainMenu;
151
        SUBMENU_POSITION = 0;
152
        (KEY_A).CLICKS_SHORT--;
153
    }
154
155
156
// DIESES SWITCH MEINE ICH
157
// Hier wird anhand der Menüposition bestimmt in welcher Submenüeintrag
158
// angezeigt werden soll. Jedes Submenü wird einzeln aufgeführt.
159
160
      switch (MENU_POSITION)
161
    {      
162
      case Backlight_SubMenu:
163
    
164
      LCD_String( Backlight[SUBMENU_POSITION].Number);
165
      LCD_String( Backlight[SUBMENU_POSITION].Text);
166
167
        if( (KEY_D).CLICKS_SHORT)
168
        {
169
            Backlight[SUBMENU_POSITION].Function();
170
            (KEY_D).CLICKS_SHORT--;      
171
        }
172
173
      break;
174
175
      case LcdContrast_SubMenu:
176
/*
177
      LCD_String( LcdContrast[SUBMENU_POSITION].Number);
178
      LCD_String( LcdContrast[SUBMENU_POSITION].Text);
179
*/
180
      /* Funktionsaufruf noch nicht implementiert */
181
182
      break;
183
    }
184
    
185
186
187
  break;

von Karl H. (kbuchegg)


Lesenswert?

Nachtaktiver schrieb:
> Ist nicht beabsichtig aber ich habe mal wieder eine Frage und würde
> gerne
> wissen ob jemand eine Idee hat wie man es auch anders lösen könnte.
>
> Speziell geht es nun darum das ich wenn ich von den MainManu "Options"
> in das ein Submenü gesprungen bin - Gar nicht weiß in welche Submenü
> Struktur ich anzeigen soll. Gelöst habe ich das mit einen switch case,
> da man Anhand der letzten Menüposition schließen kann welches Submenü
> angezeigt werden soll.


Nun ja,
Ich frage mich schon, warum ich mir den Mund fusselig rede, äh die 
Finger wund tippe, um dir zu zeigen, dass der Schlüssel zum Ganzen darin 
liegt, dass man sich Strukturen aufbaut, in denen die kompletten 
Steuerdaten für das Menü abgelegt werden und die eigentlich 
ausprogrammierten Menüfunktionen von diesen Steuerdaten getrieben 
werden, wenn du es dann doch
1
> volatile unsigned char  SELECTED_MAIN_MENU;
2
> 
3
> #define          No_Menu          0
4
> #define          ChangeOptions_Menu    1
5
> #define          ChangeVoltage_Menu    2
6
> #define          ChanceCurrent_Menu    3
7
> #define          SwitchKeylock_Menu    4
8
> 
9
> volatile unsigned char  ACTIVE_MENU;
10
> 
11
> #define          NoMenu          0
12
> #define          MainMenu        1
13
> #define          SubMenu          2
14
> 
15
> volatile unsigned char  ACTIVE_SUBMENU;
16
> 
17
> #define          Backlight_SubMenu    0
18
> #define          LcdContrast_SubMenu    1
19
> #define          Temperature_SubMenu   2
20
> 
21
> volatile unsigned char  MENU_POSITION;
22
> volatile unsigned char  SUBMENU_POSITION;

alles wieder anders machst und den Vorschlag nicht aufgreifst, die 
Vorteile davon aber nutzen willst.

Entweder du programmierst ein Menüsystem in allen Zweigen komplett aus 
oder du überlegst dir welche Progammteile ja eigentlich, von Daten 
getrieben, einen immer gleichen Universalmechanismus ansteuern können.


Dein Menüsystem könnte wie der Mechanismus in einer Drehorgel sein. 
Immer gleich. Was diese Drehorgel abspielt wird durch die Papierstreifen 
mit den Löchern an den richtigen Stellen geregelt.
Der Papierstreifen mit den Löchern: Das sind die Datenstrukturen, die 
den kompletten Menüaufbau in allen Einzelheiten beschreiben.
Und der Mechanismus der den Streifen abtastet: Das ist die Menüfunktion, 
die sich aus der Beschreibung in den Daten die für sie relevanten 
Funktionen herauszieht und entsprechend reagiert. Genauso wie eine 
Drehorgel genau dann ein C abspielt, wenn das entsprechende Loch im 
Papierstreifen gestanzt ist.
Willst du ein anderes Musikstück, musst du einen anderen Papierstreifen 
einlegen aber nicht den Mechanismus ändern.
Willst du ein anderes Menü, musst du die Daten in den Menübeschreibungen 
ändern, aber nicht die Menüfunktionen.

von Nachtaktiver (Gast)


Lesenswert?

Dann muss ich ganz ehrlich zu geben das es mir einfach nicht einleuchten 
will wie ich das so hinbekomme.
Also nochmal zurück auf Los und ziehe keine 2000€ ein. Gedankensotieren:

Ich habe bis jetzt eine Struktur für das Hauptmenü in der:
- Alle Unterpunkte
- Nummerierung
- Umfang des Submenüs

drin steht. Anhand der Position im Hauptmenü stelle ich fest welches 
Element ich des Hauptmenü ich anzeigen. Da die Größe des Hauptmenüs 
bekannt ist, kann ich das ganze so Steuern das ich in einen 
Ringdurchlauf die Hauptmenü Unterpunkte blättern kann. Soweit ist ja 
noch alles richtig.

Nun wurde ein Tastendruck ausgelöst und ich möchte in einen Unterpunkt 
des Hauptmenüs einspringen. Und nun kommen die ersten Probleme.

Neues Problem:
-> Ich weiß nicht wie ich nun Unterscheide zwischen Haupt<->Untermenü:
Meine Lösung: Switch Case

Dadurch wird eine völlig neuer Mechanismus aufbaut, und nicht der 
Papierstreifen gewechselt. Dadurch muss man eine komplette 
Tasterauswertung neuschreiben. Ich führe einen neuen Zähler ein mit den 
ich durch das Submenüblättern. Die Anzahl der Elemente aus den Submenüs 
kann ich aus den Hauptmenüzähler aus der Hauptmenüstruktur entnehmen.

Neues Problem:
-> Ich weiß nicht wie ich nun unterscheide in welcher Eintrag 
ausgewertet wurde.
Meine Lösung: Noch ein Switch Case

Anhand des Submenü Zählers entnehme die Position an der ich mich 
befinde.
In eines Switch Case Werte ich das aus und Löse die entsprechende Aktion 
beim Tastendruck aus.

Fazit:
Scheinbar überflüssig.
Ich muss ganz ehrlich zugeben das ich es einfach nicht verstehe wie man 
es anders machen kann. Vorallen weil das Menü ja Funktioniert. Ich kann 
im Options Menü rumblättern, einen Punkt anschauen und die 
Hintergrundbeleuchtung An/Aus schalten, oder kann mir die Aktuelle 
Temperatur ansehen. Ich will das irgendwie nicht verstehen.

Nochmal von vorne:
Anhand der Haupmenü Position weiß ich ob ich mich in Backlight, 
LCD-Contrast befinde.
Anhand der Submenü Position weiß ich ob ich mich bei An oder Aus 
befinde.

Soll die Lösung eine weitere Struktur sein, oder eher ein 2Dimensionales 
Array anlege, in der ich mit den Hauptmenü Index ausmache welche 
Funktion aufgerufen werden soll, und mit der Submenüposition den 
entsprechenden Operanten bestimme?

Irgendwie drehe ich mich im Kreis. :(

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Hallo nochmal.
Ich habe in den letzten Tagen verucht mit den den Vorschlägen von 
Karl-Heinz ein MenuSystem zu entwerfen. Den Vorschlag von Tom B. habe 
ich auch versucht zu berücksichtigen und alles was viel Speicher braucht 
ins Flash zu schreiben.

Leider ist mein C etwas eingerostet und ich musste die ganze Zeit an 
Klassen denken.

Drei TastenZustände werden abgefrage:
1 Taste1 kurz  letzter  MenuPunkt
2 Taste2 kurz  nächster MenuPunkt
3 Taste3 lang  MenuPunkt auswählen.

Für die einzelnen Menus sind die Einträge in Arrays zusammengefasst. Die 
Arrays werden dann in struct Menu mit der Anzahl der Einträge und dem 
aktuell ausgewählten Eintrag verknüpft. Alle menus bilden wieder ein 
array und die Enumeration aktMenu beinhaltet, welches Menu gerade aktiv.

Könnt ihr, bitte, mal drüber schauen, ob man das so machen kann?!

Gibt es eine bessere Lösung für "menuStart()" & "menuEnd()"?

Ist es besser ein Menu ringsrum laufen zu lassen oder nur bis zum 
Anfang/Ende?

Könnt ihr, bitte, mal drüber sehen, ob das so geht?!

von Martin K. (spyro07)


Lesenswert?

Hallo,

ich bin jetzt auch dabei eine Menüsteuerung zu realisieren. Ich wollte
eigentlich die oben geschilderte Idee von Karl-Heinz aufgreifen.
Gestalten wollte ich das dann noch so, das Menü - Text und Funktions -
Pointer im Flash liegen. Aber das ist erstmal eine andere Sache.
Allerdings habe ich eine Frage, die vielleicht Karl-Heinz am Besten
beantworten kann:

Mit der oben aufgezeigten Menüsteuerung hänge ich dann ja immer in dem
UP Do_Menu fest, oder sehe ich das falsch. Und wenn ich in ein Untermenü
wechsle, dann hänge ich in der Do_Menu - Routine des UP's fest, oder?

Denn mir ist es wichtig, das die Menü - Programme universell sind. Das
heißt für mich auch automatisch mit, das ich das Menü - Programm (was ja
an sich nichts zeitkritisches ist) einfach in main() mit aufrufen kann.
Also ich möchte mit der Menüsteuerung nicht den µc tot legen, sondern ab
und zu noch was andres in main() machen können. Klappt das in dem oben
gezeigten Beispiel? Bis jetzt eher noch nicht, oder?

von Martin K. (spyro07)


Lesenswert?

Karl Heinz Buchegger schrieb:
> // soweit ist alles aufgesetzt, ab jetzt werden die Tasten überwacht
>   // und das Menü soll arbeiten
>   while( running )
>   {
>     if( get_keypress( UP ) )   // Taste "Rauf" gedrückt ?
>     {
>       if( active > 0 )         // geht da überhaupt was?
>       {
>         lcd_gotoxy( 0, active );    // ja, tut es. Das Sternchen wegnehmen
>         lcd_write( " " );
>
>         active--;
>
>         lcd_gotoxy( 0, active );    // und neu hinsetzen, in die Zeile davor
>         lcd_write( "*" );
>       }
>     }
>
>     else if( get_keypress( DOWN ) )  // Taste "Runter" gedrückt?
>     {
>       if( active < MenuSize - 1 )    // geht das überhaupt
>       {
>         lcd_gotoxy( 0, active );     // ja, da gibt es noch einen Menupunkt
>         lcd_write( " " );
>
>         active++;
>
>         lcd_gotoxy( 0, active );
>         lcd_write( "*" );
>       }
>     }
>
>     else if( get_keypress( EXECUTE ) ) // Taste "Ausführen" gedrückt?
>     {
>       if( Menu[active].Function )      // gibt es eine auszuführende Funktion?
>         Menu[active].Function();       // Ja: führe sie aus
>       else
>         running = FALSE;               // Nein: Das war der "Exit" Menüpunkt
>                                        // Menüsteuerung beenden
>     }
>   }

Ich habe gerade nochmal nachgeschaut:
theoretisch könnte man das festhängen einfach umgehen, wenn man die 
erste while() einfach rausnimmt. Dann brüchte man natürlich eine 
separate menu_init().
und statt der while einfach rein
1
if(running == FALSE)
2
 ...

Nur bin ich mir dann noch nicht sicher, wie man dafür sorgt, das beim 
nächsten Menüaufruf dann wieder in die obere Menü-Ebene gewechselt wird. 
Einfach dem Menüaufruf als nächstes wieder den Pointer / das Array für 
die obere Menübene übergeben?

von Karl H. (kbuchegg)


Lesenswert?

Martin K. schrieb:

> Ich habe gerade nochmal nachgeschaut:

Mit der Nebenbedingung

> Das heißt für mich auch automatisch mit, das ich das Menü - Programm
> (was ja an sich nichts zeitkritisches ist) einfach in main() mit
> aufrufen kan

bedeutet das, dass diese Variante nicht benutzt werden kann.

Aber ich hab ja (nach einem kurzen Überfliegen des Beitrags) ja auch 
noch andere Varianten angesprochen.

Du brauchst eine Lösung, bei der ein Menü nicht durch eine Funktion 
realisiert ist, sondern ein datengetriebenes Menü, bei dem die komplette 
Menüinformation in den Datenstrukturen steckt, so dass eine Funktion 
unter Auswertung dieser Datenstruktur und durch Hinzunahme eines 
möglichen Tastendrucks entscheiden kann, was zu tun ist. Und zwar in 
allen Einzelheiten. Danach gibt diese Funktion die Kontrolle wieder ab 
und beim nächsten Aufruf entscheidet sie wieder, wie ein möglicher 
Tastendruck durch die in den Strukturen enthaltenen Informationen 
auszuwerten ist.

Das ganze geht schon viel mehr in Richtung Zustandsautomat (wobei der 
komplette Automat durch Daten beschrieben wird) als in irgend eine 
andere Richtung.

von G. O. (aminox86)


Lesenswert?

Textbasierte Menüs sind ein abgenagter Knochen.
Mit bester Empfehlung:
http://www.mikrocontroller.net/articles/Tinykon

von Fzzz (Gast)


Lesenswert?

>So einer Taste kann man verschiedene Zustände entlocken.
Taste kurz gedrückt, Taste lange gedrückt oder Taste sehr lange
gedrückt.


Ist leider Muell, das ist nicht intuitiv. Nach zehn Jahren weiss niemand 
mehr wie's geht, resp weshalb es nicht geht. Lieber ein paar Tasten 
mehr...

von Martin K. (spyro07)


Lesenswert?

Ok,

ich bin jetzt in Richtung Zustandsautomat gegangen. Der AVR - Butterfly 
Code eignet sich ja wirklich bestens dafür. Und ich bin erstaunt, wie 
einfach da das Prinzip eigentlich ist. Alleine wäre ich da zwar nicht 
darauf gekommen, aber wie gesagt, das Grundprinzip ist ja äußerst 
simpel. Totzdem danke ich euch.

P.S. mal sehen, vllt. stelle ich wenn ich mit dem Butterfly das hab mal 
was in die Codesammlung, nur die Sache was das Menü betrifft. Da gehört 
ja nicht allzuviel dazu.

von Markus _. (markush)


Lesenswert?

Martin K. schrieb:
>
> P.S. mal sehen, vllt. stelle ich wenn ich mit dem Butterfly das hab mal
> was in die Codesammlung, nur die Sache was das Menü betrifft. Da gehört
> ja nicht allzuviel dazu.

Hi,

das wäre ne super sache. ich versuch mich auch daran, aber ich hab 
einfach nicht die zeit da richtig dran zu bleiben - leider...

Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.