www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller menüstruktur in C


Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute



So ich bin Anfänger und grade beim Versuch in C eine Menüstruktur zu 
programmieren. Nur leider komme ich bei meinem Code einfach nicht mehr 
weiter.



Ich glaube, dass der Compiler das variable Array in der Menüstruktur 
nicht versteht, aber wie kann man das anders Programmieren.



Weiß irgendwer weiter?




#include <avr/io.h>
#include "lcd-routines.h"
#include <avr/pgmspace.h>

#define ungueltig   0
#define L      1
#define up      2
#define down    3
#define  R      4
#define true    1
#define false    0


int input;                  //Eingabevariable


/*    Menüstruktur  */

typedef struct SubMenue {
  const char SubText;            //Name des Untermenüs
  int data_size;              //Größe des Auswahlarrays
  int data[data_size];          //Auswahlarray              Wenn nicht aus einer bestimmten Anzahl an Auswahlmöglichkeiten gewählt werden soll
  int data_select;            //Ausgewähltes Arrayglied        kann data[] und data_size auf NULL gesetzt werden. Es wird dann data_select einfach hoch gezählt
}                      

struct Menue {
   const char Text;            //Name des Menüs
  int sub_size;              //Anzahl der Untermenüs
  struct SubMenue sm[sub_size];      //Untermenüarray
  int sub_select;              //Ausgewähltes Untermenü
}

void writeMenue(struct Menue *pointer)    //Schreibt das Menü auf das Display
{
  lcd_clear();
  lcd_home();
  lcd_data( (*pointer).Text );
  lcd_setcursor(2,5);
  lcd_data( (*pointer).sm[sub_select].SubText );
}

void writeSubMenue(struct SubMenue *pointer)  //Schreibt das Untermenü auf das Display
{
  lcd_clear();
  lcd_home();
  lcd_data( (*pointer).SubText );
  lcd_setcursor(2,5);
  if ( (*pointer).data[sub_select]= true)
  {
    lcd_data( (*pointer).data[sub_select] );
  }
  else
  {
    lcd_data( (*pointer).data_select );
  }
}

void lower(int *selected, int *size)        //lower und rais zählen mit der Grenze size einen int hoch oder runter
{
  if(selected=0)
  {
    selected=size;
  }
  else
  {
    selected--;
  }
}

void rais(int *selected, int *size)
{
  if(selected=size)
  {
    selected=0;
  }
  else
  {
    selected++;
  }
}

int getinput(int *input)            //getinput soll der Variable input den dem Tastendruck entsprechende Zahl zuweisen
{

}



void EnterSubMenue(struct SubMenue *pointer)          
{
  writeSubMenue(&(*pointer));
  getinput(input);
  do
  {
  switch(input)
  {
          case L:
              
              if(data[0]=true)
              {
                lower(&(*pointer).data_select , &(*pointer).data_size);
              }
              else if((*pointer).data=false)                    //Wenn data[] Null ist soll einfach hochgezählt werden
              {                                  //die Daten befinden sich dann nicht in dem von data[data_select]
                break;                              //sondern in data_select selbst
              }
              else
              {
                (*pointer).data_select--;
              }
              break;
            
          case R:
              
              if(data=true)
              {
                rais(&(*pointer).data_select , &(*pointer).data_size);
              }
              else
              {
                (*pointer).data_select++;
              }
              break;
            
          case up:
                      
              EnterMenue(&(*pointer));
              break;
            
          case down:
            
              break;
  }
            
  }
  while(input = down );
}
          


void EnterMenue(struct Menue *Mpointer)          //Funktion um in das Einstellungsmenü zu kommen
{
  writeMenue(&(*Mpointer));
  getinput(&input);
  do
  {
  switch(input)
  {
          case L:
              
              lower(&(*Mpointer).sub_select,&(*Mpointer).sub_size);
              break;
            
          case R:
              
              rais(&(*Mpointer).sub_select,&(*Mpointer).sub_size);
              break;
            
          case up:
            
              break;
            
          case down:
            
              EnterSubMenue(&(*Mpointer).sm[&(*Mpointer).sub_select]);
              break;
  }
            
  }
  while(input = up );
}


void Main (void)
{
  struct Menue Haupt =
  {
    "Einstellunge:", 2 ,
    {"Led-einstellungen", 4 ,{"Aus","Dunkel","Mittel","Hell"},0},
    {"Motor-einstellungen",2,{"Aus","Ein"},0}
    ,0
  };
  while(1)
  {
  init_lcd();
  EnterMenue(&Haupt);
  }
}


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alex schrieb:

> Ich glaube, dass der Compiler das variable Array in der Menüstruktur
> nicht versteht,

richtig

> aber wie kann man das anders Programmieren.

Mittels Verpointerungen.

Kauf dir ein C-Buch und sieh zu dass du mit Pointern warm wirst. Ohne 
sie kommst du nicht mehr weiter.

struct Menu;  // forward Deklaration

struct MenuEntry
{
  const char*  Text;
  struct Menu* SubMenu;
};

struct Menu
{
  const char*       Title;
  int               NrEntries;
  struct MenuEntry* Entries;
}


struct MenuEntry LedEntries[] =
{
  { "Aus",    NULL },
  { "Dunkel", NULL },
  { "Mittel", NULL },
  { "Hell",   NULL }
};

struct Menu LedMenu = 
{
  "LED",
  sizeof( LedEntries ) / sizueof( LedEntries[0] ),
  LedEntries
};


struct MenuEntry MotorEntries[] =
{
  { "Aus", NULL },
  { "Ein", NULL }
};

struct Menu MotorMenu =
{
  "Motor",
  sizeof( MotorEntries) / sizueof( MotorEntries[0] ),
  MotorEntries
};


struct SetupEntries[] =
{
  { "LED-Einstellungn", LedMenu },
  { "Motor-Eintellungen, MotorMenu }
};

struct Menu SetupMenu =
{
  "Einstellungen",
  sizeof( SetupEntries) / sizueof( SetupEntries[0] ),
  SetupEntries
};


Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst es so machen, wie kbuchegg geschrieben hat, also mit sizeof 
arbeiten. Einfacher finde ich aber, jeweils mit NULL am Ende zu 
kennzeichnen, daß das das letzte Element war.

Generell finde ich die Idee das Menü per deklarativen Ansatz in einer 
Struktur zu definieren, gut. Dein Code sieht mir aber etwas verworren 
aus und man kann auch nicht beliebig tiefe Menüstrukturen definieren, 
daher habe ich das eben mal selbst programmiert. Für Microcontroller 
wichtig kann auch sein, daß man die Struktur möglichst so anlegt, daß 
die aus dem Flash gelesen werden kann. Wenn du dort auch die 
selektierten Einträge speicherst, dann geht das wahrscheinlich nicht. 
Ich habe daher die gewählte Konfiguration selbst in einem extra Array 
(g_configs) abgelegt, was auch das komplette laden und speichern sehr 
vereinfacht.

Zum Testen von sowas ist es übrigens immer viel einfacher, das auf dem 
PC zu simulieren. Wenn du unter Windows arbeitest, dann kann ich Visual 
Studio Express empfehlen, ist kostenlos. Unter Linux ist KDevelop eine 
gute Idee. Die Hardwareschicht solltest du davon dann abstrahieren, 
sodaß du mit demselben Quelltext einmal eine Simulation für PC 
compilieren kannst und einmal für dein Microcontroller-Target.
#include <stdio.h>
#include <conio.h>

enum Config {
  LED_CONFIG,
  MOTOR_CONFIG,
  LAST_ENTRY
};

enum LedIntensity {
  LED_AUS,
  LED_DUNKEL,
  LED_MITTEL,
  LED_HELL
};

enum MotorState {
  MOTOR_AUS,
  MOTOR_AN
};

typedef void(*Callback)(void);

typedef struct MenuItem MenuItem;
struct MenuItem {
  const char* name;
  const int configIndex;
  const MenuItem* subMenus;
  const char** menuValues;
  const Callback function;
};

int g_configs[LAST_ENTRY];

void onFactoryDefaults(void)
{
  int i;
  for (i = 0; i < LAST_ENTRY; i++) g_configs[i] = 0;
  g_configs[LED_CONFIG] = LED_MITTEL;
  g_configs[MOTOR_CONFIG] = MOTOR_AUS;
  printf("Werkseinstellungen wiederhergestellt\n");
}

const char* g_ledConfigs[] = { "Aus", "Dunkel", "Mittel", "Hell", NULL };
const char* g_motorConfigs[] = { "Aus", "Ein", NULL };
const MenuItem g_configMenu[] =
{
  { "LED", LED_CONFIG, NULL, g_ledConfigs, NULL },
  { "Motor", MOTOR_CONFIG, NULL, g_motorConfigs, NULL },
  NULL
};

const MenuItem g_menu[] =
{
    { "Einstellungen", 0, g_configMenu, NULL, NULL },
    { "Werkseinstellung", 0, NULL, NULL, &onFactoryDefaults },
    NULL
};

const MenuItem g_menuRoot = { "", 0, g_menu, NULL, NULL };

void showMenu(const MenuItem* menu, int pos)
{
  while (1) {
    int c;
    if (menu->subMenus) {
      printf("%s\n", menu->subMenus[pos].name);
    } else if (menu->menuValues) {
      if (g_configs[menu->configIndex] == pos) printf("* ");
      printf("%s\n", menu->menuValues[pos]);
    }
    c = _getch();
    switch (c) {
      case 'l':
        printf("L pressed\n");
        if (pos > 0) pos--;
        break;
      case 'u':
        printf("U pressed\n");
        return;
      case 'd':
        printf("D pressed\n");
        if (menu->subMenus) {
          Callback fun = menu->subMenus[pos].function;
          if (fun) {
            fun();
          } else {
            showMenu(&menu->subMenus[pos], 0);
          }
        } else if (menu->menuValues) {
          g_configs[menu->configIndex] = pos;
        }
        break;
      case 'r':
        printf("R pressed\n");
        if (menu->subMenus) {
          if (menu->subMenus[pos + 1].name) pos++;
        } else if (menu->menuValues) {
          if (menu->menuValues[pos + 1]) pos++;
        }
        break;
    }
  }
}

int main(void)
{
  printf("menu enter\n");
  showMenu(&g_menuRoot, 0);
  printf("menu exit\n");
}

Beispielanwendung:
menu enter
Einstellungen
R pressed
Werkseinstellung
R pressed
Werkseinstellung
D pressed
Werkseinstellungen wiederhergestellt
Werkseinstellung
L pressed
Einstellungen
D pressed
LED
D pressed
Aus
R pressed
Dunkel
R pressed
* Mittel
R pressed
Hell
D pressed
* Hell
L pressed
Mittel
R pressed
* Hell
U pressed
LED
R pressed
Motor
D pressed
* Aus
R pressed
Ein
D pressed
* Ein
U pressed
Motor
U pressed
Einstellungen
U pressed
menu exit

PS: In C vergleicht man per "==" nicht per "=". Der Compiler sollte auch 
eine Warnung ausgeben. Am besten immer alle Warnungen beachten.

Autor: weinbauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab mir mal n "Universalmenü" zusammengestrickt für beliebige Tiefe, 
allerdings nicht in C, das lief so.

Im Prinzip hatte ich 2 Menüarten, Einstellungsmenü und Navigationsmenü.

Die menüs hatten folgende Struktur:

Menüadresse
Menüart (0= Navi, 1= Einstellung)

dann gings auseinander, bei Navimenü kamen darunter die Untermenüs

"einstellung Uhr" Sprungadresse1
"Einstellung Parameter 1" Sprungadresse2
"Einstellung Parameter 2" Sprungadresse3
"Exit Menü" 0
-Ende Menü-

Bei Einstellmenüs kam stattdessen

Parameternummer
Maximalwert
Minimalwert
Anzahl Stufen
Anzahl Dezimalstellen
Aussprungziel

So konnte ich beliebig Menüs aneinander Reihen, z.B. verschiedene
Einstellungen per Aussprungadresse aufreihen oder per Auswahl an
beliebige Einstellungen springen.
Für die Anzeige der Menüs gabs dann entsprechend 2 Programmteile,
die alle Menüs auf LCD oder LED-Anzeige schrieben je nach Menüart.

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey danke für die Hilfe, hat mir wirklich weiter geholfen!

Und wegen dem C-Buch.... das sollte doch auch gehen oder?
http://openbook.galileocomputing.de/c_von_a_bis_z/...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.