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


von Alex (Gast)


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?




1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
#include <avr/pgmspace.h>
4
5
#define ungueltig   0
6
#define L      1
7
#define up      2
8
#define down    3
9
#define  R      4
10
#define true    1
11
#define false    0
12
13
14
int input;                  //Eingabevariable
15
16
17
/*    Menüstruktur  */
18
19
typedef struct SubMenue {
20
  const char SubText;            //Name des Untermenüs
21
  int data_size;              //Größe des Auswahlarrays
22
  int data[data_size];          //Auswahlarray              Wenn nicht aus einer bestimmten Anzahl an Auswahlmöglichkeiten gewählt werden soll
23
  int data_select;            //Ausgewähltes Arrayglied        kann data[] und data_size auf NULL gesetzt werden. Es wird dann data_select einfach hoch gezählt
24
}                      
25
26
struct Menue {
27
   const char Text;            //Name des Menüs
28
  int sub_size;              //Anzahl der Untermenüs
29
  struct SubMenue sm[sub_size];      //Untermenüarray
30
  int sub_select;              //Ausgewähltes Untermenü
31
}
32
33
void writeMenue(struct Menue *pointer)    //Schreibt das Menü auf das Display
34
{
35
  lcd_clear();
36
  lcd_home();
37
  lcd_data( (*pointer).Text );
38
  lcd_setcursor(2,5);
39
  lcd_data( (*pointer).sm[sub_select].SubText );
40
}
41
42
void writeSubMenue(struct SubMenue *pointer)  //Schreibt das Untermenü auf das Display
43
{
44
  lcd_clear();
45
  lcd_home();
46
  lcd_data( (*pointer).SubText );
47
  lcd_setcursor(2,5);
48
  if ( (*pointer).data[sub_select]= true)
49
  {
50
    lcd_data( (*pointer).data[sub_select] );
51
  }
52
  else
53
  {
54
    lcd_data( (*pointer).data_select );
55
  }
56
}
57
58
void lower(int *selected, int *size)        //lower und rais zählen mit der Grenze size einen int hoch oder runter
59
{
60
  if(selected=0)
61
  {
62
    selected=size;
63
  }
64
  else
65
  {
66
    selected--;
67
  }
68
}
69
70
void rais(int *selected, int *size)
71
{
72
  if(selected=size)
73
  {
74
    selected=0;
75
  }
76
  else
77
  {
78
    selected++;
79
  }
80
}
81
82
int getinput(int *input)            //getinput soll der Variable input den dem Tastendruck entsprechende Zahl zuweisen
83
{
84
85
}
86
87
88
89
void EnterSubMenue(struct SubMenue *pointer)          
90
{
91
  writeSubMenue(&(*pointer));
92
  getinput(input);
93
  do
94
  {
95
  switch(input)
96
  {
97
          case L:
98
              
99
              if(data[0]=true)
100
              {
101
                lower(&(*pointer).data_select , &(*pointer).data_size);
102
              }
103
              else if((*pointer).data=false)                    //Wenn data[] Null ist soll einfach hochgezählt werden
104
              {                                  //die Daten befinden sich dann nicht in dem von data[data_select]
105
                break;                              //sondern in data_select selbst
106
              }
107
              else
108
              {
109
                (*pointer).data_select--;
110
              }
111
              break;
112
            
113
          case R:
114
              
115
              if(data=true)
116
              {
117
                rais(&(*pointer).data_select , &(*pointer).data_size);
118
              }
119
              else
120
              {
121
                (*pointer).data_select++;
122
              }
123
              break;
124
            
125
          case up:
126
                      
127
              EnterMenue(&(*pointer));
128
              break;
129
            
130
          case down:
131
            
132
              break;
133
  }
134
            
135
  }
136
  while(input = down );
137
}
138
          
139
140
141
void EnterMenue(struct Menue *Mpointer)          //Funktion um in das Einstellungsmenü zu kommen
142
{
143
  writeMenue(&(*Mpointer));
144
  getinput(&input);
145
  do
146
  {
147
  switch(input)
148
  {
149
          case L:
150
              
151
              lower(&(*Mpointer).sub_select,&(*Mpointer).sub_size);
152
              break;
153
            
154
          case R:
155
              
156
              rais(&(*Mpointer).sub_select,&(*Mpointer).sub_size);
157
              break;
158
            
159
          case up:
160
            
161
              break;
162
            
163
          case down:
164
            
165
              EnterSubMenue(&(*Mpointer).sm[&(*Mpointer).sub_select]);
166
              break;
167
  }
168
            
169
  }
170
  while(input = up );
171
}
172
173
174
void Main (void)
175
{
176
  struct Menue Haupt =
177
  {
178
    "Einstellunge:", 2 ,
179
    {"Led-einstellungen", 4 ,{"Aus","Dunkel","Mittel","Hell"},0},
180
    {"Motor-einstellungen",2,{"Aus","Ein"},0}
181
    ,0
182
  };
183
  while(1)
184
  {
185
  init_lcd();
186
  EnterMenue(&Haupt);
187
  }
188
}

von Karl H. (kbuchegg)


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.
1
struct Menu;  // forward Deklaration
2
3
struct MenuEntry
4
{
5
  const char*  Text;
6
  struct Menu* SubMenu;
7
};
8
9
struct Menu
10
{
11
  const char*       Title;
12
  int               NrEntries;
13
  struct MenuEntry* Entries;
14
}
15
16
17
struct MenuEntry LedEntries[] =
18
{
19
  { "Aus",    NULL },
20
  { "Dunkel", NULL },
21
  { "Mittel", NULL },
22
  { "Hell",   NULL }
23
};
24
25
struct Menu LedMenu = 
26
{
27
  "LED",
28
  sizeof( LedEntries ) / sizueof( LedEntries[0] ),
29
  LedEntries
30
};
31
32
33
struct MenuEntry MotorEntries[] =
34
{
35
  { "Aus", NULL },
36
  { "Ein", NULL }
37
};
38
39
struct Menu MotorMenu =
40
{
41
  "Motor",
42
  sizeof( MotorEntries) / sizueof( MotorEntries[0] ),
43
  MotorEntries
44
};
45
46
47
struct SetupEntries[] =
48
{
49
  { "LED-Einstellungn", LedMenu },
50
  { "Motor-Eintellungen, MotorMenu }
51
};
52
53
struct Menu SetupMenu =
54
{
55
  "Einstellungen",
56
  sizeof( SetupEntries) / sizueof( SetupEntries[0] ),
57
  SetupEntries
58
};

von Frank B. (foobar)


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.
1
#include <stdio.h>
2
#include <conio.h>
3
4
enum Config {
5
  LED_CONFIG,
6
  MOTOR_CONFIG,
7
  LAST_ENTRY
8
};
9
10
enum LedIntensity {
11
  LED_AUS,
12
  LED_DUNKEL,
13
  LED_MITTEL,
14
  LED_HELL
15
};
16
17
enum MotorState {
18
  MOTOR_AUS,
19
  MOTOR_AN
20
};
21
22
typedef void(*Callback)(void);
23
24
typedef struct MenuItem MenuItem;
25
struct MenuItem {
26
  const char* name;
27
  const int configIndex;
28
  const MenuItem* subMenus;
29
  const char** menuValues;
30
  const Callback function;
31
};
32
33
int g_configs[LAST_ENTRY];
34
35
void onFactoryDefaults(void)
36
{
37
  int i;
38
  for (i = 0; i < LAST_ENTRY; i++) g_configs[i] = 0;
39
  g_configs[LED_CONFIG] = LED_MITTEL;
40
  g_configs[MOTOR_CONFIG] = MOTOR_AUS;
41
  printf("Werkseinstellungen wiederhergestellt\n");
42
}
43
44
const char* g_ledConfigs[] = { "Aus", "Dunkel", "Mittel", "Hell", NULL };
45
const char* g_motorConfigs[] = { "Aus", "Ein", NULL };
46
const MenuItem g_configMenu[] =
47
{
48
  { "LED", LED_CONFIG, NULL, g_ledConfigs, NULL },
49
  { "Motor", MOTOR_CONFIG, NULL, g_motorConfigs, NULL },
50
  NULL
51
};
52
53
const MenuItem g_menu[] =
54
{
55
    { "Einstellungen", 0, g_configMenu, NULL, NULL },
56
    { "Werkseinstellung", 0, NULL, NULL, &onFactoryDefaults },
57
    NULL
58
};
59
60
const MenuItem g_menuRoot = { "", 0, g_menu, NULL, NULL };
61
62
void showMenu(const MenuItem* menu, int pos)
63
{
64
  while (1) {
65
    int c;
66
    if (menu->subMenus) {
67
      printf("%s\n", menu->subMenus[pos].name);
68
    } else if (menu->menuValues) {
69
      if (g_configs[menu->configIndex] == pos) printf("* ");
70
      printf("%s\n", menu->menuValues[pos]);
71
    }
72
    c = _getch();
73
    switch (c) {
74
      case 'l':
75
        printf("L pressed\n");
76
        if (pos > 0) pos--;
77
        break;
78
      case 'u':
79
        printf("U pressed\n");
80
        return;
81
      case 'd':
82
        printf("D pressed\n");
83
        if (menu->subMenus) {
84
          Callback fun = menu->subMenus[pos].function;
85
          if (fun) {
86
            fun();
87
          } else {
88
            showMenu(&menu->subMenus[pos], 0);
89
          }
90
        } else if (menu->menuValues) {
91
          g_configs[menu->configIndex] = pos;
92
        }
93
        break;
94
      case 'r':
95
        printf("R pressed\n");
96
        if (menu->subMenus) {
97
          if (menu->subMenus[pos + 1].name) pos++;
98
        } else if (menu->menuValues) {
99
          if (menu->menuValues[pos + 1]) pos++;
100
        }
101
        break;
102
    }
103
  }
104
}
105
106
int main(void)
107
{
108
  printf("menu enter\n");
109
  showMenu(&g_menuRoot, 0);
110
  printf("menu exit\n");
111
}

Beispielanwendung:
1
menu enter
2
Einstellungen
3
R pressed
4
Werkseinstellung
5
R pressed
6
Werkseinstellung
7
D pressed
8
Werkseinstellungen wiederhergestellt
9
Werkseinstellung
10
L pressed
11
Einstellungen
12
D pressed
13
LED
14
D pressed
15
Aus
16
R pressed
17
Dunkel
18
R pressed
19
* Mittel
20
R pressed
21
Hell
22
D pressed
23
* Hell
24
L pressed
25
Mittel
26
R pressed
27
* Hell
28
U pressed
29
LED
30
R pressed
31
Motor
32
D pressed
33
* Aus
34
R pressed
35
Ein
36
D pressed
37
* Ein
38
U pressed
39
Motor
40
U pressed
41
Einstellungen
42
U pressed
43
menu exit

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

von weinbauer (Gast)


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.

von Alex (Gast)


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/000_c_vorwort_001.htm#mj764cb3fd439d3b95d1843e7c7d17f235

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.