Forum: Mikrocontroller und Digitale Elektronik Simpeles Menü - Denkfehler


von Stefan (Gast)


Lesenswert?

Hallo Mikrocontroller Freunde,

ich weiss, dass es schon hunderte von Threads zu Menüs usw. gibt, aber 
anscheinend bin ich zu doof dafür und darum, hab ich mehr selbst was 
mehr oder weniger schlaues überlegt oder zumindest versucht, weil ich 
mit den Funktionspointern (noch) nicht klarkomme.

Jedoch hab ich immer das Problem, dass ich aus dem Menü rauslaufe und 
demnach Unerwünschte Dinge auftreten.

Es wird ein 2x16 Display verwendet, mit einem ATMega32.

Hier die relevanten Code-Stellen :
1
...
2
3
unsigned int menu_size=5;
4
5
...
6
  while(1)
7
  {
8
    // Entertaste zur Menüaktivierung bzw. bzw Ausfürung der  Funktion
9
    if(debounce(&IO_PIN, IO_B_ENTER))
10
    {
11
      if(!menuOnScreen)
12
      {
13
        menuOnScreen=1;
14
        show_menu(menu_index);
15
      }
16
      else
17
      {
18
        exec_function(menu_index);
19
        menuOnScreen=0;
20
        menu_index=0;
21
      }
22
    }
23
    if(debounce(&IO_PIN, IO_B_DOWN) && menuOnScreen)
24
    {
25
      if(menu_index<menu_size)
26
      menu_index++;
27
    }
28
    if(debounce(&IO_PIN, IO_B_UP) && menuOnScreen)
29
    {
30
      if(menu_index>0)
31
      menu_index--;
32
    }
33
    if(menuOnScreen && !(menu_tmp==menu_index))
34
    {
35
      show_menu(menu_index);
36
    }
37
  }
38
39
40
----------------------
41
42
volatile char menu_text[6][16] = {"Spuelen", "Spueldauer", "Test2", "Test3", "Exit", " "};
43
44
45
46
void show_menu(uint8_t menu_index)
47
{
48
  lcd_write((char*)menu_text[menu_index],0,1);
49
  lcd_write((char*)menu_text[menu_index+1],0,2);
50
}

Ich hoffe jemand kann mir weiterhelfen.
Vielen Dank schomal im Voraus, für alle die sich Mühe geben werden mir 
zu helfen :-)

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:

> Hier die relevanten Code-Stellen :

Ohne den Code grossartig analysiert zu haben


>     if(debounce(&IO_PIN, IO_B_DOWN) && menuOnScreen)
>     {
>       if(menu_index<menu_size)
>       menu_index++;
>     }

Hier muss es
       if(menu_index<menu_size-1)
       menu_index++;

heissen.
Du darfst nur dann zum nächsten INdex gehen, wenn auch noch einer 
existiert.

Probiers mit Zahlen aus
Dein Menü besteht aus 5 Einträgen
D.h. der letzte gültige hat die Nummer 4.
Daraus folgt, dass du den Index noch erhöhen darfst, wenn der Index 3 
ist. Ist er bereits 4, darf nicht mehr erhöht werden.

menu_size ist also 5
menu_index sei bereits 4    -> darf nicht mehr erhöht werden
                               menu_index < menu_size würde das aber
                               erlauben

>     if(debounce(&IO_PIN, IO_B_UP) && menuOnScreen)
>     {
>       if(menu_index>0)
>       menu_index--;
>     }

... aus dem gleichen Grund hast du ja hier auch > 0 benutzt und nicht == 
0


PS: überleg dir mal, ob
1
       if( menu_index < menu_size-1 )
2
         menu_index++;

nicht einfacher zu lesen ist, als
1
       if(menu_index<menu_size-1)
2
       menu_index++;

Du hast seit Kindesbeinen gelernt, dass zwischen den Wörtern mindestens 
ein Leerzeichen kommt. Das ist auch 
gutso,dennansonstenistdieserSatznämlichziemlichschwerzulesen.

Dein Gehirn ist darauf trainiert, einzelne Wörter anhand dieser 
Leerzeichen zu erkennen. Nutze das, und schreib nicht alles in einer 
Wurscht dahin, so dass du 20 Sekunden brauchst um in
1
       if(menu_index<menu_size-1)
erst mal die einzelnen Wörter und wie sie zusammenhängen erkennen zu 
können. Einige strategisch platzierte Leerezeichen können eine Menge 
ausmachen. Unter anderem den Unterschied zwischen nicht wartbarem Code 
und Code der eine Freude zu lesen ist.

von Stefan (Gast)


Lesenswert?

Hallo Karl Heinz,

Danke erstmal für die Anregungen mit dem Leerzeichen, du hast natürlich 
recht, was die Lesbarkeit angeht und ich gelobe Besserung :-)

Mit dem "menu_size - 1", hast du glaube ich aber nicht recht, da ich 6 
Felder habe ( das letzte ist leer ):
1
volatile char menu_text[6][16] = {"Spuelen", "Spueldauer", "Test2", "Test3", "Exit", " "};

Aus diesem Grund verstehe ich ja auch nicht, warum er aus dort 
rauslaufen kann. Bei den Tests gestern konnte ich auch nicht auf den 1. 
Eintrag zurückgehen, wenn ich mal von diesem weg war.

Danke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> a ich 6 Felder habe ( das letzte ist leer ):
Ja, von 0 bis 5   ;-)
Also kann dein Menüpointer menu_index die Werte 0-5 annehmen.
Und dann das:
1
lcd_write((char*)menu_text[menu_index+1],0,2);
Yeah, hinter das Array gegriffen...

von Stefan (Gast)


Lesenswert?

Hallo Lothar,

Danke, jetz hab sogar ich das verstanden :D

Ich war irgendwie der festen Überzeugung, dass menu_index nicht 5 werden 
kann ... nach genauerer Überlegung geht es aber doch :)

von Karl H. (kbuchegg)


Lesenswert?

PS

Wenn du das so formulierst
1
const char * menu_text[]=
2
     { "Spuelen", "Spueldauer", "Test2", "Test3", "Exit", " "};
3
4
#defien MENU_SIZE  ( sizeof(menu_text) / sizeof(*menu_text) )

Dann brauchst du dir auch nicht den Wolf zählen, wieviele Einträge du 
wirklich hast. Das erledigt dann der Compiler für dich.

Versuch immer, Wissen aus deinem Kopf in das Programm einzubauen.
Im Moment musstest du wissen, dass menu_size immer um 1 weniger ist, als 
du Einträge im Menü hast. Das ist nicht gut, denn in 3 Wochen weißt du 
das nicht mehr. Diese Information ist aber wichtig, wenn du weitere 
Menüpunkte einbaust.

-> Lass den Compiler abzählen, wieviele Menüpunkte du hast und schreib 
dein Programm so, dass sich ausgehend von dieser Anzahl alles weitere 
von selbst im Programm regelt.

Auch die Sache mit dem letzten, leeren, Einträg fällt in diese 
Kategorie. Wenn der letzte Eintrag sowieso immer leer ist, dann kann ihn 
sich das Programm auch bei Bedarf selber generieren.

von Karl H. (kbuchegg)


Lesenswert?

Wenn du zb das ganze so formulierst ...

(Warnung: ungetesteter Code)
1
const char * menu_text[]=
2
     { "Spuelen", "Spueldauer", "Test2", "Test3", "Exit" };
3
4
#define MENU_SIZE  ( sizeof(menu_text) / sizeof(*menu_text) )
5
6
7
#ifndef TRUE
8
#define TRUE 1
9
#define FALSE 0
10
#endif
11
12
....
13
14
  menu_index   = 0;
15
  menu_tmp     = 100;
16
  menuOnScreen = TRUE;
17
18
  while(1)
19
  {
20
    // Entertaste zur Menüaktivierung bzw. bzw Ausfürung der  Funktion
21
    if(debounce(&IO_PIN, IO_B_ENTER))
22
    {
23
      if( !menuOnScreen )
24
      {
25
        menuOnScreen = TRUE;
26
        show_menu( menu_index );
27
      }
28
      else
29
      {
30
        exec_function( menu_index );
31
        menuOnScreen = FALSE;
32
        menu_index = 0;
33
      }
34
    }
35
36
    if( debounce(&IO_PIN, IO_B_DOWN) && menuOnScreen )
37
    {
38
      if( menu_index < MENU_SIZE - 2 )
39
        menu_index++;
40
    }
41
    if( debounce(&IO_PIN, IO_B_UP) && menuOnScreen )
42
    {
43
      if( menu_index > 0 )
44
        menu_index--;
45
    }
46
47
    if( menuOnScreen && ( menu_tmp != menu_index ) )
48
    {
49
      show_menu( menu_index );
50
      menu_tmp = menu_index;
51
    }
52
  }
53
54
 ...
55
56
void show_menu( uint8_t menu_index )
57
{
58
  lcd_write( menu_text[ menu_index++ ], 0, 1 );
59
60
  if( menu_index < MENU_SIZE )
61
    lcd_write( menu_text[menu_index], 0, 2 );
62
  else
63
    lcd_write( "               ", 0, 2 );
64
}

dann kümmert sich der Code ganz von alleine um etwaige Änderungen im 
Menü. Willst du einen Menüpunkt mehr im Programm. zb "Setup"
1
const char * menu_text[]=
2
     { "Spuelen", "Spueldauer", "Test2", "Test3", "Setup", "Exit" };

dann fügst du einfach nur diesen neuen Punkt ein, und alles weitere 
regelt sich von selbst.

von gast (Gast)


Lesenswert?

hmm ohne jetz weiter auf dein menü einzugehen
aber ich würde vlt versuchen  dein menü anders aufzubauen

wenn du nun ein paar texte mehr machst ist dein RAM voll und derµC 
stürzt ständig weg  weil der stack überläuft

sinnvoller ist es texte in den flash zu legen

ebenso ist ein 2dim. array für texte auch nicht schön
da du dort speicher verbrennst ohne das du ihn nutzt
dein 6tes " "  verbraucht trotzdem 17 byte

vlt sowas :

// hier texte definieren
const char text_1[] ROGMEM = " blih";
const char text_2[] ROGMEM = " blah";
const char text_3[] ROGMEM = " blubb";
const char text_4[] ROGMEM = " blubberdiblub";

// array von zeigern auf die texte erstellen
const char *message[] PROGMEM =
{
text_1,
text_2,
text_3,
text_4
};


deine lcd_write kopierst du und nennst sie zb  lcd_write_P
in dieser funktion holst du das byte vorher aus dem flash
pgm_read_byte( ...)
und schreibst das dann zum LCD


wenn du nun einen text schreiben willst

lcd_write_P ( (const char*) pgm_read_word( &message[i]) );

i ist hierbei eine variable wie man mit dem menüindex koppeln kann


man kann auch ohne dem zeigerarray arbeiten und einfach

lcd_write_P(text_1); schreiben

oder

lcd_write_P( PSTR(" blubbblubb") );


typisch für lcd_write ist ja :

lcd_write( char *string)
{
  while(*string)
    lcd_data( *string++);
}

die P ist etwas anders
lcd_write_P(const char *string)
{
  char data;
  while( (data = pgm_read_byte(string++)) != '\0')
    lcd_data( data);
}


so ganz grob ...

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.