menu structuur maken

trix

Golden Member

hallo, ik ben bezig met het maken van een menu structuur voor het bedienen van een machine, ik heb al wel iets wat werkt, maar het loopt niet vloeiend en soms springt hij naar onverwachte schermen enz. enz.
ik ben er in totaal al 3 dagen mee bezig, en ik begin sterk de indruk te krijgen dat ik de verkeerde methode gebruik.
ik heb hieronder een stukje van mijn code gepost om mijn benadering (methode) te laten zien, die naar mijn idee veel te omslachtig is.
in een ander deel kan ik ook een variabele selecteren b.v. speed (0-100 %). voor de rest is het een hele simpele menu structuur met mischien 20 verschillende schermen.
hoe kan ik dit he beste aanpakken ?

ik gebruik een display met een HD44780 en 4 drukknoppen.

reacties worden zeer gewardeerd.

c code:


if (manual_select_screen == 1)
{
	if (temp_manual_select_screen == 1)
	{
		Lcd4_Clear();
				
		Lcd4_Set_Cursor(1,2);
		Lcd4_Write_String("left side");
				
		Lcd4_Set_Cursor(2,2);
		Lcd4_Write_String("right side");
				
		Lcd4_Set_Cursor(1,18);  // line 3
		Lcd4_Write_String("others 1");
				
		Lcd4_Set_Cursor(2,18);  // line 3
		Lcd4_Write_String("others 2");
					
		temp_manual_select_screen = 0;
					
		_delay_ms(1000);
	}
				
		if  button_increase
		select_counter = select_counter + 1;
					
		if  button_decrease
		select_counter = select_counter - 1;
					
		if (select_counter > 4)   {select_counter = 1;}
		if (select_counter < 1)   {select_counter = 4;}
					
		if (select_counter == 1) // auto
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 2) // manual
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 3) // homing
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 4) // scanning
					{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char('*');
		}
					
		if ((select_counter == 1) & (button_enter))
		{						
			manual_left_screen = 1;
			manual_select_screen = 0;
		}
			
		if ((select_counter == 2) & (button_enter))
		{						
			manual_right_screen = 1;
			manual_select_screen = 0;
		}
					
  	        if ((select_counter == 3) & (button_enter))				 
                {						 
                        manual_others_1_screen = 1;
			manual_select_screen = 0;
		}
				
		if ((select_counter == 4) & (button_enter))
		{
			manual_others_2_screen = 1;
			manual_select_screen = 0;
		}
				
}
eigenwijs = ook wijs
buckfast_beekeeper

Golden Member

c code:


if (select_counter == 1) // auto
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 2) // manual
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 3) // homing
		{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char('*');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char(' ');
		}
					
		if (select_counter == 4) // scanning
					{
			Lcd4_Set_Cursor(1,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,0);
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(1,16); // line 3
			Lcd4_Write_Char(' ');
			Lcd4_Set_Cursor(2,16); // line 4
			Lcd4_Write_Char('*');
		}

Buiten select_counter is er geen enkel verschil tussen de 4 stukken code. Onzinnig om ze 4 keer op te nemen. Je hebt ook maar 4 mogelijkheden dus zal dezelfde code steeds uitgevoerd worden. (tenzij je select_counter nog ergens 0 maakt). Wat ook kan.

c code:


Lcd4_Set_Cursor(1,0);
select_counter==1? Lcd4_Write_Char('*') : Lcd4_Write_Char(' ');
Lcd4_set_Cursor(2,0);
select_counter==1? Lcd4_Write_Char('*') : Lcd4_Write_Char(' ');
........

Is een switch select geen properdere optie? Bijvoorbeeld voor het 2de deel van je code

c code:

if(button_enter){
    switch(select_counter){
        
        case 1:
            manual_left_screen = 1;
            break;
        case 2:
            manual_right_screen = 1;
            break;
        case n ..........
            break;
        default:
            // indien bovenstaande niet van toepassing voer dit uit

        
    }
    manual_select_screen= 0;

}

edit: iets te snel geweest. Er is wel verschil tussen de code.

Van Lambiek wordt goede geuze gemaakt.
trix

Golden Member

daar word de code korter van, maar de methode blijft mijn inziens gelijk.

eigenwijs = ook wijs
buckfast_beekeeper

Golden Member

Dat er naar onverwachte schermen wordt gesprongen kan alleen verklaart worden door variabelen die ergens wijzigen. Of de debounce van je schakelaar is niet OK.

Van Lambiek wordt goede geuze gemaakt.
trix

Golden Member

ik gebruik de debounce routine van peter dannegger, die op het internet als goed staat aan geschreven.
er gebeuren onverklaarbare dingen (voor mij dan), maar al debuggend en zoekend bekroop mij het gevoel dat dit toch niet de gangbare methode is.
er moet toch iets van een soort standaard zijn voor zoiets gangbaars wat al duizende keren is toegepast.

eigenwijs = ook wijs
buckfast_beekeeper

Golden Member

Een stukje van je display (voorlopig) voorbehouden voor debug info. Bijvoorbeeld in een hoekje de select_counter waarde. Zo zie je al direct dat deze waarde klopt met het scherm dat wordt getoond. Wijzigt dit, dan moet je op zoek waar dit kan gebeuren.

Van Lambiek wordt goede geuze gemaakt.
trix

Golden Member

die libary is van een arduino, ik weet niet of ik daar iets aan heb. maar ik zal eens kijken.

dat laatste kan inderdaad een goed hulpmiddel zijn bij het debuggen.

eigenwijs = ook wijs

Typisch geval van 'dubbele administratie'. Dat is altijd moeilijk om in sync te blijven.

Je hebt een select_counter die de waarde 1 t/m 4 kan hebben en daarmee aangeeft welk van de 4 schermen je wilt tonen.

En vervolgens heb je ook nog een 4-tal vlaggen die hetzelfde aangeven.
- manual_left_screen
- manual_right_screen
- manual_others_1_screen
- manual_others_2_screen

Erger nog: Als je een van die 4 vlaggen zet dan blijven de andere 3 staan dus na een tijdje heb je alle schermen tegelijk aan.

Dit soort problemen kun je het makkelijkste voorkomen door de 4 vlaggen weg te doen en alleen nog de select_counter te gebruiken, eventueel met defines:

code:


#define ManualLeftScreen    1
#define ManualRightScreen   2
#define ManualOthers1Screen 3
#define ManualOthers2Screen 4

Dan kun je verder testen op

code:


   if(select_counter == ManualLeftScreen)
   {  ...

Om het sterretje te zetten kun je deze funktie gebruiken:

code:


   Lcd4_Set_Cursor(1,0);
   Lcd4_Write_Char((select_counter == 1) ? '*' : ' ');
   Lcd4_Set_Cursor(2,0);
   Lcd4_Write_Char((select_counter == 2) ? '*' : ' ');
   Lcd4_Set_Cursor(1,16); // line 3
   Lcd4_Write_Char((select_counter == 3) ? '*' : ' ');
   Lcd4_Set_Cursor(2,16); // line 4
   Lcd4_Write_Char((select_counter == 4) ? '*' : ' ');

[Bericht gewijzigd door deKees op 19 maart 2020 22:51:21 (19%)

@Dekees heerlijk zoals je deze materie zo eenvoudig eruit kan laten zien ik leer er elke keer weer wat bij.

trix

Golden Member

inderdaad, benleentje was me net voor.
ik heb jou post als leidraad genomen, en heb nu een goed werkende display.
het is nog niet helemaal klaar, maar al wel zover dat ik alle mogelijkheden goed werkend heb.
met name die hint van de dubbele administratie.
dekees weer bedankt _/-\o_

eigenwijs = ook wijs
Lucky Luke

Special Member

Op 19 maart 2020 22:38:18 schreef deKees:

Dit soort problemen kun je het makkelijkste voorkomen door de 4 vlaggen weg te doen en alleen nog de select_counter te gebruiken, eventueel met defines:

code:


#define ManualLeftScreen    1
#define ManualRightScreen   2
#define ManualOthers1Screen 3
#define ManualOthers2Screen 4

Lijkt me iets dat heel mooi met een enum kan...
(En inderdaad een switch()-case lusje, althans, dat vind ik overzichtelijker dan een berg ifjes)

Eluke.nl | De mens onderscheid zich van (andere) dieren door o.a. complexe gereedschappen en bouwwerken te maken. Mens zijn is nerd zijn. Blijf Maken. (Of wordt, bijvoorbeeld, cultuurhistoricus)

Vraagje is #define Manualleft 1 niet hetzelfde als const byte Manualleft = 1 Ze worden beide toch in het programma vervangen door de waarde en gebruiken geen variabele?

Ja natuurlijk, een enum is hier wel op zijn plaats inderdaad.

code:


   const byte ManualLeft = 1;

Kan ook. De compiler maakt dan trouwens wel een variabele aan omdat de variabele ManualLeft nu ook voor andere modules in het project beschikbaar moet zijn. Dus de variabele moet zichtbaar zijn voor de linker. Als je dat niet wil dan moet je de variable static maken.

code:


   static const byte ManualLeft = 1;

Al zijn er wel subtiele verschillen.

Met een enum krijg je een nieuw type variabele en dan zou je dus ook select_counter als zodanig moeten declareren:

code:


enum ScreenNrType
{  ManualLeft = 1,
   ManualRight   ,
   ManualOthers1 ,
   ManualOthers2
};

ScreenNrType select_counter;

....
   switch (select_counter)
   {  case ManualLeft:
      ...

Maar
- Dat werkt alleen in C++. In C krijg je net een andere syntax met typedef.

En dan wordt het rekenen lastig, want dat gaat niet met een enum

code:


   select_counter += 1;  //< error message.

Met een #define en een const byte kun je wel rekenen.

Als je kunt debuggen dan is een enum in het voordeel omdat de debugger dan kan laten zien wat de waarde is (select_counter = ManualLeft), terwijl je bij #define en de const byte alleen de getalswaarde krijgt (select_counter = 1).