C Menüstruktur erstellen (speziell für LCD´s)

Dieses Thema im Forum "Software" wurde erstellt von Janiiix3, 25. Januar 2018.

  1. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Hallo liebe Mitglieder,

    im Moment bin Ich ja wirklich schwer dabei mich tiefer in "C" zu bohren.
    Dabei habe ich mir mein "Hardware Enwicklungsboard" wieder aus meiner Bastelkiste raus gekramt.

    Nun habe ich damals ja schön ein "paar" Menüs auf einem LCD erstellt mit ein paar Untermenüs.
    Das war für den Anfang schon ziemlich "Tricky"... Auf der Suche im Web, bin ich auf folgenden Lösungsvorschlag gekstoßen..



    CodeBox C und C++
    static const char menu_string0[] PROGMEM = "Highpass";
    static const char menu_string1[] PROGMEM = "Bandpass";
    static const char menu_string2[] PROGMEM = "Lowpass";
    
    typedef struct MENU {
      const unsigned char *text;
      int8_t previous;
      int8_t next;
      void ( *fp )( void );
    } MENU_ENTRY;
    
    const MENU_ENTRY menue[] PROGMEM= {
      { menu_string0, 2, 1, highpass },
      { menu_string1, 0, 2, bandpass },
      { menu_string2, 1, 0, lowpass }
      };
    


    Auf meinem (G)LCD würde Ich nun ein vill. übersichtlicheres / strukturiertes Menü erstellen wollen.
    Da kommen die "structs" ja schon ziemlich gut oder?

    Desweiten möchte Ich gerne den aktuellen "Menüpunkt" mit einem Pfeil hervorheben "->"..

    ->Einstellungen
    Ausschalten
    Neustarten
    Exit
    ---

    Das man quasi mit dem Pfeil erkennen kann wo man gerade überhaupt ist.

    Habt Ihr da noch Ideen, Anregungen?
     
  2. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.979
    Zustimmungen:
    45
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Das mit dem Pfeil wird einfacher, wenn er vor dem Text erscheint (also der selektierte Text nicht rüberrutschen muß). Gehen tut natürlich beides.
    Zu structs usw kann ich nichts sagen.
    Zur allgemeinen Handhabung von Menus gabs (im BASCOM-Bereich) mal'n recht interessantes Konzept.
    Die Idee war, jede Menu-Seite(?) zu sowas wie 'nem Objekt (in Form von Speicheradressen im Flash) zu machen, mit Eigenschaften (was soll wo angezeigt werden) und Methoden (was soll geschehen wenn Taster X betätigt wird).
    Der Zustandsautomat hinter dem Menü greift dann immer auf die Adressen der gerade aktiven Menu-Seite zu.
    Sowas läßt sich (logischerweise) grundsätzlich auch in anderen Sprachen realisieren, und in beliebiger Komplexität...
     
  3. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C
    An sowas habe ich auch schon gedacht.
    Das Beispiel oben ist ja schon gar nicht so schnlecht.



    CodeBox C und C++
    typedef struct MENU
    {
      const unsigned char *text;
      int8_t previous;
      int8_t next;
      void ( *fp )( void );
    } MENU_ENTRY;
    




    CodeBox C und C++
    const MENU_ENTRY menue[] =
    {
      {"Einstellungen"   , 0   , 1   , openSettings    },
      {"Beenden"       , 1   , 2   , NULL           },
      {"Exit"           , 2   , 0   , NULL            }
    };
    
    


    Und dann halt in einer Funktion den aktuellen betätigten Taster auswerte (Taster = Index)



    CodeBox C und C++
    openMenue(uint8_t index)
    {
         for(uint8_t i = 0 ; i < SIZE_OF_ENTRYS : i++)
         {
              if(index == i)
              {
                   strcpy(buffer,"->");
                   strcat(buffer,menue[index].text);
              }
              else
              {
                   strcpy(buffer,menue[index].text);
              }
              glcdGotoXY(index,0);
              glcdPuts(buffer);
         }
    }
    


    Ich hatte diese Funktion schon geschrieben, damit werden mir meine ganzen Menüeintrage auf das Display geworfen und wenn "index == i" also ein Taster gedrückt wurde oder eben mit nem Drehencoder die Position gewählt wurde, würde da halt der "Cursor" in Form eines "->" vor stehen.
     
  4. achim S.

    achim S. Mitglied

    Registriert seit:
    16. Januar 2010
    Beiträge:
    380
    Zustimmungen:
    6
    Punkte für Erfolge:
    18
    Sprachen:
    C
    Habe vielleicht was für dich. Es besteht aus einem Atmega, einem Drehgeber an einem Port und einem Display über den I2C Bus. Der Drehgeber kann links und rechts unterscheiden und mit dem Druckkopf im Drehgeber gibt es noch einen Einknopfbedieneng mit kurz oder landdrücken dazu. Anzeige erfolgt auf dem Display mit einem Pfeil und können mehrere Untermenues gebaut werden. Vielleicht kannst du es gebrauchen.
    achim
     
  5. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Hallo @achim S.
    Anschauen kann Ich es mir ja mal.
     
  6. achim S.

    achim S. Mitglied

    Registriert seit:
    16. Januar 2010
    Beiträge:
    380
    Zustimmungen:
    6
    Punkte für Erfolge:
    18
    Sprachen:
    C
    Sieh es dir mal an:


    CodeBox C und C++
    /* ATB_Enc_Menue_Prg_1.c
     * Created: 14.12.2016 12:21:55 Author : AS */
    
    //#define F_CPU 16000000           // CPU clock in Hz
    #include <stdbool.h>
    #include <avr/pgmspace.h>
    #include "main.h"
    #include <util/delay.h>
    #include "i2clcd.h"
    #include "i2cmaster.h"
    #include "avr/io.h"
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include <stdint.h>
    //#include "encoder.h" !!!!!!!!
    //#include "encoder.c"
    
    
    
    volatile uint8_t wait;
    volatile uint8_t key_state;
    volatile uint8_t key_press;
    volatile uint8_t key_rpt;
    
    volatile int16_t led1=0;
    volatile int8_t Anz=0;
    volatile int8_t zeile=2;
    volatile int8_t lauf=0;
    int8_t Menue;
    
    
    #define KEY_DDR    DDRA                        // Datenrichtung A
    #define KEY_PORT   PORTA                        // Angabe Port A
    #define KEY_PIN    PINA                         // Angabe PIN A
    #define KEY_1       7                           // PA 3
    #define KEY_2       6                           // PA 5
    #define KEY_3       5                           // PA 7
    #define KEY_4       3                           // PA 6
    #define ALL_KEYS (1<<KEY_1|1<<KEY_2|1<<KEY_3|1<<KEY_4)
    #define REPEAT_MASK (1<<KEY_1|1<<KEY_2|1<<KEY_3)
    #define REPEAT_START 80                          // after 500ms  50
    #define REPEAT_NEXT 40                           // every 200ms  50
    
    #define PHASE_A     (PINA & 1<<PA0)       // Eingang Encoder A  P98
    #define PHASE_B     (PINA & 1<<PA1)       // Eingang Encoder B  P98
    
    //#define PHASE_A     (PINA & 1<<PA2)       // Eingang Encoder A  P32
    //#define PHASE_B     (PINA & 1<<PA1)       // Eingang Encoder B  P32
    
    #define LEDS_DDR    DDRB               // Ausgang LED
    #define LEDS        PORTB               //
    
    volatile int8_t enc_delta;               // -128 ... 127
    static int8_t last;
    
    char Buffer[20];
    int8_t dreh1 = 4;
    //int8_t dreh1u = 2;
    
    // ATmega 1284p auf Board 1, 16 MHz, Drehgeber auf P98 auf Port A, NT2, 8x LED auf P20 am Port B
    
    //***********************************************************************                                                                   
    //                      Reading rotary encoder                                                                                         
    //              Author: Peter Dannegger                                                                                                     
    //************************************************************************
    
    void encode_init( void )
      {
       int8_t new;
       new = 0;
       if( PHASE_A ) new = 3;   //3
       if( PHASE_B ) new ^= 1;               // convert gray to binary
       last = new;                           // power on state
       enc_delta = 0;
      }  
    /////////////////////////////////////////////
    ISR (TIMER0_COMPA_vect)                   // ISR mit 1 ms
      {
        int8_t new, diff;                   // ab hier Encoder
       new = 0;
       if( PHASE_A ) new = 3;
       if( PHASE_B ) new ^= 1;               // convert gray to binary
       diff = last - new;                   // difference last - new
       if( diff & 1 )
         {                                   // bit 0 = value (1)
           last = new;                       // store new as next last
           enc_delta += (diff & 2) - 1;   // bit 1 = direction (+/-)
         }
       static uint8_t ct0=0xFF, ct1=0xFF, rpt;       // ab hier Tasten
       uint8_t i;
       if(wait<=9)                                // bei 9 sind es 10ms
       {
            wait++;
         }                      // erhöht
       else                    // wenn dann ...
         {
           wait=0;                  // setzt wait auf 0
           i=key_state ^ KEY_PIN;       // nach +5V
           //i=key_state ^~KEY_PIN;   // nach GND
           ct0=~(ct0&i);
           ct1=ct0^(ct1&i);
           i&=ct0&ct1;
           key_state^=i;
           key_press|=key_state&i;
           if((key_state & REPEAT_MASK)==0)
           rpt=REPEAT_START;
           if(--rpt==0)
             {
               rpt=REPEAT_NEXT;
               key_rpt|=key_state & REPEAT_MASK;
             }
         }
       }   
     //////////////////////////////////////////////////////////
    int8_t encode_read1( void )               // lesen einzel Schritt Encoder = schnell
      {
       int8_t val;
       cli();
       val = enc_delta;
       enc_delta = 0;
       sei();
       return val;                   // counts since last call
      }
    int8_t encode_read2( void )               // lesen zwei Schritt Encoder = mittel
      {
       int8_t val;
       cli();
       val = enc_delta;
       enc_delta = val & 1;
       sei();
       return val >> 1;
      }
    int8_t encode_read4( void )               // lesen vier Schritt Encoder = langsam
      {
       int8_t val;
       cli();
       val = enc_delta;
       enc_delta = val & 3;
       sei();
       return val >> 2;
      }
    ////////////////////////////////////////////////////////////////////  
    void timer_init()
      {
       //TCCR0A = (1<<WGM01);
       TCCR0A = 0;
       TCCR0B = (1<<WGM01)|(1<<CS01)|(1<<CS00);
       TCNT0=1;
       OCR0A = 249;
       TIMSK0 |=(1<<OCIE0A);
      }
    //////////////////////////////////////////////////////
    uint8_t get_key_press(uint8_t key_mask)
      {
       cli();
       key_mask &=key_press;
       key_press^=key_mask;
       sei();
       return key_mask;
      }
    /////////////////////////////////////////
    uint8_t get_key_rpt(uint8_t key_mask)
      {
       cli();
       key_mask &=key_rpt;
       key_rpt^=key_mask;
       sei();
       return key_mask;
      }
    ///////////////////////////////////////////////////////
    uint8_t get_key_short(uint8_t key_mask)
      {
       return get_key_press(~key_state & key_mask);
      }
    ///////////////////////////////////////////////////////
    uint8_t get_key_long(uint8_t key_mask)
      {
       return get_key_press(get_key_rpt(key_mask));
      }   
    ///////////////////////////////////////////////////////////////////
    void led_blinken1()
      {
       led1++;
       if(led1==500)
         {
           PORTA &= ~(1<<PA5);        // Schaltet Pin
         }
       else
         {
           if(led1==1000)
             {
               PORTA |= (1<<PA5);      // Schaltet Pin
               led1=0;
             }
         }
      }
    /////////////////////////////////////////////////////////////////  
    void Startanzeige()
      {   
        lcd_printlc(1,3,"Enc-Menue 1");                // Text Zeile 1
        lcd_printlc(2,2,"**************");           // Text Zeile 2
        lcd_printlc(3,1,"Encoder Menue 1");       // Text Zeile 3
        lcd_printlc(4,2,"(by achim S.)");           // Text Zeile 4
      }
    ///////////////////////////////////////////////////////////  
    void Bedienung()
      {
       lcd_printlc(1,1,"Bedienung-Menue");                // Text Zeile 1
       lcd_printlc(2,3,"< + > Auswahl");           // Text Zeile 2
       lcd_printlc(3,3,"kurz - Start");       // Text Zeile 3
       lcd_printlc(4,3,"lang - Reset");           // Text Zeile 4
      }  
    ///////////////////////////////////////////////////
    void Anzeige(int8_t valk)
      {
        Anz++;
        if (Anz==50)
          {
           lcd_printlc(1,3,"Enc-Menue 1");                // Text Zeile 1
           lcd_printlc(2,2,"**************");           // Text Zeile 2
           lcd_printlc(3,2,"Werte Encoder:");       // Text Zeile 3
           itoa(valk,Buffer,10);
            lcd_printlc(4,4,Buffer);
            Anz=0;
          }
      }
    //////////////////////////////////////////////////////////////////
    void Menue1(int8_t zeile)            //
      {
       lauf++;
       if(lauf==100)
         {
           //lcd_command(LCD_CLEAR);                       // Leere Display
           //_delay_ms(2);
             
           lcd_printlc(1,2,"Menue 1 - I2C");
           lcd_printlc(2,4,"Menue 1-1");
           lcd_printlc(3,4,"Menue 1-2 ");
           lcd_printlc(4,4,"Menue 1-3");
           lcd_printlc(2,1,"  ");
           lcd_printlc(3,1,"  ");
           lcd_printlc(4,1,"  ");
           lcd_printlc(zeile,1,">>");
           lauf=0;
         }
      }  
    ///////////////////////////////////////////////////////////////////////  
    void Menue11()
      {
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);
       lcd_printlc(1,1,"Bedienung-Menue");                // Text Zeile 1
       //lcd_printlc(2,3,"< + > Auswahl");           // Text Zeile 2
       lcd_printlc(3,3,"Menue 1-1");       // Text Zeile 3
       lcd_printlc(4,3,"lang - Reset");           // Text Zeile 4
      }  
    ///////////////////////////////////////////////////////////////////////
    void Menue12()
    {
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);
       lcd_printlc(1,1,"Bedienung-Menue");                // Text Zeile 1
       //lcd_printlc(2,3,"< + > Auswahl");           // Text Zeile 2
       lcd_printlc(3,3,"Menue 1-2");       // Text Zeile 3
       lcd_printlc(4,3,"lang - Reset");           // Text Zeile 4
    }
    ///////////////////////////////////////////////////////////////////////
    void Menue13()
    {
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);
       lcd_printlc(1,1,"Bedienung-Menue");                // Text Zeile 1
       //lcd_printlc(2,3,"< + > Auswahl");           // Text Zeile 2
       lcd_printlc(3,3,"Menue 1-3");       // Text Zeile 3
       lcd_printlc(4,3,"lang - Reset");           // Text Zeile 4
    }  
    /////////////////////////////////////////////////////////////////////  
    /////////   Hauptprogramm  
    /////////////////////////////////////////////////////////////////////
     
    int main( void )                               // Hauptschleife
      {
       timer_init();  
       i2c_init();                                   // Starte I2C Bus
       lcd_init();                                   // Starte I2CLCD
       lcd_light(0);                               // 0=Licht an, 1=Licht aus
       // Display Befehle
       lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGOFF);
       // Display ON/OFF / Cursor ON/OFF / Blinken ON/OFF
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);
                                       // warte 2ms
       Startanzeige();
       _delay_ms(3000);   
       
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);                               // warte 2ms
       
       Bedienung();
       _delay_ms(3000);
       
       lcd_command(LCD_CLEAR);                       // Leere Display
       _delay_ms(2);
       
       KEY_DDR&=~ALL_KEYS;
       KEY_PORT|=ALL_KEYS;
       
       DDRA |= 0b01111100 ;   // LED1+2 auf PA4 und PA5, alle auf Ausgang
       //PORTA = 0b00000000;       // alle LED auf aus bei 1
       PORTA |= (1<<PA5);   // LED Blau auf P98 Pin 5
       PORTA |= (1<<PA6);   // LED Blau auf P98 Pin 5
       int8_t val = 0;
       LEDS_DDR = 0xff;       
       encode_init();
       val=2;
       sei();
       while(1)
         {
           led_blinken1();                           // Aufruf Unterprogramm LED blinken
           
           val += encode_read4();                   // Aufruf Encoder 4 mit Rückgabe
           
           if (Menue==0)
            {
           
           
           Menue1(val);
         }
           // Auswertung Grundmenue 1 ////////////////////////////////////
           if (val>dreh1)                           // Begrenzung oben
             {
               val=2;
             }
           if (val<2)                               // Begrenzung unten
             {
               val=dreh1;
             }
           //////////////////////////////////////////////////////////////  
             
           //LEDS = val;
           //Anzeige(val);
           
           if (val==2)       // LED blau
             {
               PORTA &= ~(1<<PA4);   // LED auf P98  L3 ??
             }
           else
             {
               PORTA |= (1<<PA4);   // LED Blau auf P98 Pin 5 ??
             }
           if (val==4)       // LED grün
             {
               PORTA &= ~(1<<PA3);   // LED auf P98  L3   ???
             }
           else
             {
               PORTA |= (1<<PA3);   // LED Blau auf P98 Pin 5 ????
             }
           if (val==6)       // LED rot
             {
               PORTA &= ~(1<<PA2);   // LED auf P98  L3 ???
             }
           else
             {
               PORTA |= (1<<PA2);   // LED Blau auf P98 Pin 5 ???
             }
           if (val==8)
             {
               PORTA &= ~(1<<PA2);   // LED auf P98  L3
               PORTA &= ~(1<<PA3);   // LED auf P98  L3
               PORTA &= ~(1<<PA4);   // LED auf P98  L3   
             }
             
             /*
           else
             {
               PORTA |= (1<<PA2);   // LED Blau auf P98 Pin 5
               PORTA |= (1<<PA3);   // LED Blau auf P98 Pin 5
               PORTA |= (1<<PA4);   // LED Blau auf P98 Pin 5   
             }
           */
           
           if(get_key_short(1<<KEY_1))       // schaltet kurz
             {
               PORTA &= ~(1<<PA6);   // LED auf P98  L3   
               if (val==2)       // LED rot
                 {
                   Menue=1;  
                   Menue11();
                 }
               if (val==3)       // LED rot
                 {
                   Menue=1;  
                   Menue12();
                 }
               if (val==4)       // LED rot
                 {
                   Menue=1;  
                   Menue13();
                 }   
             }
             
           if(get_key_long(1<<KEY_1))       // schaltet lang
             {
               Menue=0;
               PORTA |= (1<<PA6);   // LED Blau auf P98 Pin 5
               lcd_command(LCD_CLEAR);                       // Leere Display
               _delay_ms(2);   
             }
           //PORTA |= (1<<PA3);   // LED Grün auf P98 Pin 4
           //PORTA |= (1<<PA2);   // LED Rot auf P98 Pin 3  
         }
        }
    
     
  7. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C


    CodeBox C und C++
    typedef struct
    {
       char *Name;
       void (*fp)           (void);
       void (*setCursor)   (int8_t *cursor, int8_t pos);
    }menue_t;
    


    Kann Ich es irgendwie anstellen, dass ich auch andere Funktionsparameter übergeben kann bzw. keine?!
    Aktuell besteht die Struktur ja aus..

    char *Name = Menüname
    void (*fp) (void)
    void (*setCursor)(int8_t *, int8_t)

    Leider ist man ja nun an die Parameter gebunden und kann nicht "einfach" andere Funktionen "verlinken / zuweisen".
    Hoffentlich versteht mich einer:D

    Gibt es da eine Lösung?



    CodeBox C und C++
    menue_t mainMenue[]=
    {
       {"  ++HeschDevBoard++ "   ,menueSetMainMenue       ,menueSetCursor       },
       {"Uhrzeit stellen"       ,menueSetTime           ,menueSetCursor       },
       {"Datum stellen"       ,menueSetDate           ,menueSetCursor       },
       {"Helligkeit"           ,menueBrightness       ,menueSetCursor       },
       {"Kontrast"               ,menueContrast           ,menueSetCursor       },
       {"Seriennummer"           ,menueDispSerNr           ,menueSetCursor       },
       {"Admin Login"           ,menuePassword           ,menueSetCursor       },
       {"Bluetooth"           ,menueSetBluetoothMenue   ,menueSetCursorHome   },
       {"Relais"               ,menueSetRelais           ,menueSetCursor       },
       {"Hardware Info"       ,menueHardwareInfo       ,menueSetCursor       },
       {"Neustart"               ,menueRestart           ,menueSetCursor       },
       {"Verlassen"           ,menueError               ,menueSetCursor       },
    };
    
     
  8. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.979
    Zustimmungen:
    45
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    In Deinem Beispiel/Deiner Vorlage aus #1 werden generell Funktionen ohne Parameter (Argumente?) verwendet, oder? Du müßtest also auf Parameter verzichten, oder die anders übergeben. Insbesondere kannst Du dann auch eine leere Funktion implementieren/zuweisen.
     
  9. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Muss ich nicht. Das ist jetzt halt auch eine Frage. Mache Ich die ganzen Variablen global so das ich von jeder Funktion drauf zugreifen kann oder gibt es doch eine Möglichkeit verschiedene Funktionsparameter dort mit einzuarbeiten.

    Aktuell wie man in #7 sieht, habe ich zwei Funktionszeiger aufgenommen.
    1/ Ist ein "void" Funktionszeiger der keinen Übergabeparameter erwartet.
    2/ ist ein "void" Funktionszeiger der einen "int8_t *" Zeiger erwaret und der zweite erwartet einen "int8_t" Werr.

    Den zweiten Funktionspointer nutze Ich aktuell dafür, dass ich einen Cursor flexibel in einer Funktion immer auf eine bestimmte Position setzen kann.
     
  10. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.979
    Zustimmungen:
    45
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    ???
    Wenn Du mehrere Funktionspointer (mit unterschiedlich vielen Parametern) in der Struktur festlegst mußt Du doch auch in jeder erzeugten Instantz (?) für jeden Funktionspointer 'ne Zuweisung vornehmen, oder nicht?
    Das hattest Du ja in #7 schon. Wie ist da die Frage zu verstehen?
     
  11. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.278
    Zustimmungen:
    8
    Punkte für Erfolge:
    38
    Sprachen:
    C
    In dieser Struktur habe ich zwei Funktionspointer. Wenn ich jetzt eine "Instanz" erstelle, gibt es für diese folgendes..


    CodeBox C und C++
    Name, Funktionszeiger(keine Rückgabe, keine Übergabe), Funktionszeiger(int8_t *,int8_t value)
    

    Aktuell hat eine "Instanz" oder wie Ich es gerade bei Mir nenne "Menüpunkt" diese Inhalte.

    Natürlich kann ich z.B


    CodeBox C und C++
    void rufDieseFunktionJetztAuf(void)
    {
         hierDieEigentlicheFunktionDieAufgerufenWerdenSollte(char *buff)
         {
              ...
         }
    }
    

    Für eine Funktion, die andere Parameter erwartet wieder eine Funktion erstellen. Nur das bläht den Kode zu sehr auf. Dafür muss es doch noch eine bessere Lösung geben.
     
  12. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.979
    Zustimmungen:
    45
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Natürlich!
    Wie stellst Du Dir das vor?
    Wenn die Funktion aufgerufen wird, wird ihre Adresse im Flash angesprungen (mit einem Call, ob nun direkt oder indirekt bleibt sich gleich). Insbesondere wird dabei die Rücksprungadresse auf den Stack gepackt (genaugenommen druntergeheftet).
    Die Parameter müssen aber auch irgendwie übergeben werden, und zwar indem sie vorher irgendwo abgelegt werden. Je nach Anzahl und/oder Typ (und ob es sich um tatsächliche Werte (values) oder Adressen (Referenzen) handelt) sind das unterschiedlich viele Speicherzellen (Bytes), die benötigt werden, und die Konstellation beim Aufruf muß eben zur Funktion an der tatsächlich angesprungenen Adresse passen.
    Du brauchst also für jede mögliche Konstellation ein "Muster" der Funktion (weil beim tatsächlichen Aufruf genau dort das ablegen der Parameter abgearbeitet wird).
    Mit Deiner Struktur hast Du Dir jetzt einen zusammengesetzten Datentypen erschaffen, der eben auch Funktionsaufrufe enthält, und aufgrund der unterschiedlichen Parameter eben mehrere (alle möglichen verwendeten "Muster").
    Für jede Instanz dieses zusammengesetzten Datentypen müssen natürlich auch alle darin enthaltenen Sub-Datentypen miterzeugt werden.

    In einer Hochsprache kümmert sich ebendiese um das korrekte übergeben der Parameter - sie nimmt es Dir ab, Du mußt Dich an entsprechende Regeln bei der Syntax und Verwendung halten. Wenn Du stattdessen völlige Kontrolle haben willst, mußt Du eine weniger hohe Sprache verwenden...

    P.S.: auf Rückgabewerte bin ich nicht weiter eingegangen - quasi dasselbe wie ein Parameter, nur eben beim Rücksprung...
     
  13. TommyB

    TommyB Premium Benutzer

    Registriert seit:
    17. Mai 2010
    Beiträge:
    1.703
    Zustimmungen:
    57
    Punkte für Erfolge:
    48
    Sprachen:
    Assembler, LunaAVR, VB.Net, Python, C#
    Ist ja schon n Rattenschwanz geworden hier...

    Nur zur Info, weißt du eigentlich auch selber - in der PC Entwicklung gibt es Events wie OnClick, OnKeyDown, ...
    Diese haben als Parameter immer sender (Object) und e (EventArgs). Also eine einheitliche Struktur für sämtliche Funktionen die aufgerufen werden, sollte dieses Ereignis eintreten. EventArgs ist die Basisklasse, die aber erweitert werden kann (KeyDownEventArgs als Beispiel). sender brauchen wir hier strenggenommen nicht, e ist eine Structure oder Klasse die sämtliche Daten beinhaltet, ggf. ein- wie auch ausgehend. Da du den Kram selber entwickelst* weißt du ja auch welche Funktion welche Parameter hin und her gibt. kA ob es in C auch Klassen und Vererbung gibt, im Endeffekt sind es eh nur Pointer. Ganz früher, teilweise auch noch heute, waren die Aufrufe zum Betriebssystem was die Parameter angeht auch nichts Anderes als TLV. Siehe dazu deinem anderen Thread,

    * musste mir ein hüsteln verkneifen. Hat grad noch so geklappt.
     
  • Über uns

    Unsere immer weiter wachsende Community beschäftigt sich mit Themenbereichen rund um Mikrocontroller- und Kleinstrechnersysteme. Neben den Themen Design von Schaltungen, Layout und Software, beschäftigen wir uns auch mit der herkömmlichen Elektrotechnik.

    Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  • Coffee Time

    Unser makerconnect-Team arbeitet hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und unser eigener makerconnekt-Server regelmäßig gewartet wird. Wir nehmen das Thema Datensicherung und Datenschutz sehr ernst und sind hier sehr aktiv, auch sorgen wir uns darum, dass alles Drumherum stimmt!

    Dir gefällt das Forum und die Arbeit unseres Teams und du möchtest es unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft, unser Team freut sich auch über eine Spende für die Kaffeekasse :-)
    Vielen Dank!
    Dein makerconnect-Team

    Spende uns! (Paypal)
  1. Diese Seite verwendet Cookies, um Inhalte zu personalisieren und die Seite optimal für dich anzupassen. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden