Teil 2
Code:
//=====================================================================================
// set default net patterns
//=====================================================================================
void SetNetDefaultPatterns(){
    float _ibuf[NMAXIN+1], _obuf[NMAXOUT+1];   
       
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=0; _ibuf[2]=0; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=1; 
    _obuf[1]=1; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=1; _ibuf[2]=0; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=1; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=0; _ibuf[2]=1; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=1; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
   _ibuf[1]=1; _ibuf[2]=1; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=1; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=0; _ibuf[2]=0; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=1; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=1; _ibuf[2]=0; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=1; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );
    _ibuf[1]=0; _ibuf[2]=1; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=1; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
 
    memset( _ibuf, 0, sizeof(_ibuf) );   memset( _obuf, 0, sizeof(_obuf) );   
    _ibuf[1]=1; _ibuf[2]=1; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
    _obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=1; _obuf[9]=0; _obuf[10]=0;
    SetNewPattern( _ibuf, _obuf);
   
}





//=====================================================================================
// Backpropagation Learning
//=====================================================================================
// Backpropagation-C-Implementierung:  nn.c   1.0 (C) JOHN BULLINARIA  2004 
// verändert und portiert auf Arduino Sketch C: HELMUT WUNDER ("HaWe") 2015 
//=====================================================================================
int16_t  TrainNet() {
    char     sbuf[128];  // output string
    int16_t  i, j, o, p, np, op, ranpat[NumPattern+1], result=0, ri, rj, ro, rp;
    int32_t  offset=0;
    const    float    minerr=(1E-4)*(NMAXHID+NMAXOUT);
    
    float    SumH[NMAXPAT+1][NMAXHID+1];
    float    SumO[NMAXPAT+1][NMAXOUT+1];
    float    HidOut[NMAXPAT+1][NMAXHID+1];
    float    SumDOW[NMAXHID+1];
    float    DeltaO[NMAXOUT+1], DeltaH[NMAXHID+1];
    float    DeltaWeightLIn[NMAXIN+1][NMAXHID+1], DeltaWeightLOut[NMAXHID+1][NMAXOUT+1];
    
    float    derror, oerror, oderror,
             eta = 0.6,         // gradient descent contribution
             alpha = 0.8,       // 'momentum' term which effectively keeps a moving average
                                // of the gradient descent weight change contributions...
             smallwt = 0.5;     // smallwt is the maximum absolute size of your initial weights
         
    /*  The weight changes DeltaWeightIH and DeltaWeightHO are each made up of two components.
    First, the eta component that is the gradient descent contribution.
    Second, the alpha component that is a 'momentum' term which effectively keeps a moving average
    of the gradient descent weight change contributions, and thus smoothes out the overall weight changes.
    Fixing good values of the learning parameters eta and alpha is usually a matter of trial and error.
    Certainly alpha must be in the range 0 to 1, and a non-zero value does usually speed up learning.
    Finding a good value for eta will depend on the problem, and also on the value chosen for alpha.
    If it is set too low, the training will be unnecessarily slow.
    Having it too large will cause the weight changes to oscillate wildly, and can slow down or
    even prevent learning altogether.
    (I generally start by trying eta = 0.1 and explore the effects of repeatedly doubling or halving it.
    */

    // # DEBUG
    memtest(70, "memtest: TrainBPNet");
    delay(1000);
   
    lcdcls();
    Serial.println(); Serial.println();   
    sprintf(sbuf, "NET TRAINING started") ;  Serial.println(sbuf);
    Serial.println();
    myGLCD.print(sbuf, 0, 10);
   
    uint32_t TimeStamp=TimerMS();

    for( j = 1 ; j <= NumHidden ; j++ ) {    /* initialize WeightLIn and DeltaWeightLIn */
        for( i = 0 ; i <= NumInput ; i++ ) {
            DeltaWeightLIn[i][j] = 0.0 ;
            WeightLIn[i][j] = 2.0 * ( rando() - 0.5 ) * smallwt ;
        }
    }
    for( o = 1 ; o <= NumOutput ; o ++ ) {    /* initialize WeightLOut and DeltaWeightLOut */
        for( j = 0 ; j <= NumHidden ; j++ ) {
            DeltaWeightLOut[j][o] = 0.0 ;
            WeightLOut[j][o] = 2.0 * ( rando() - 0.5 ) * smallwt ;
        }
    }

    for( epoch = 0 ; epoch <= 30000 ; epoch++) {    /* iterate weight updates */
        for( p = 1 ; p <= NumPattern ; p++ ) {    /* randomize order of individuals */
            ranpat[p] = p ;
        }
        for( p = 1 ; p <= NumPattern ; p++) {
            np = p + rando() * ( NumPattern + 1 - p ) ;
            op = ranpat[p] ; ranpat[p] = ranpat[np] ; ranpat[np] = op ;
        }
        Error = 0.0 ;
        for( np = 1 ; np <= NumPattern ; np++ ) {    /* repeat for all the training patterns */
            p = ranpat[np];
            
            
           
            for( j = 1 ; j <= NumHidden ; j++ ) {    /* compute hidden unit activations */
                SumH[p][j] = WeightLIn[0][j] ;
                for( i = 1 ; i <= NumInput ; i++ ) {
                    SumH[p][j] += Input[p][i] * WeightLIn[i][j] ;
                }
                HidOut[p][j] = 1.0/(1.0 + exp(-SumH[p][j])) ;               
                
            }
            
            
            
            for( o = 1 ; o <= NumOutput ; o++ ) {    /* compute output unit activations and errors */
                SumO[p][o] = WeightLOut[0][o] ;
                for( j = 1 ; j <= NumHidden ; j++ ) {
                    SumO[p][o] += HidOut[p][j] * WeightLOut[j][o] ;
                }
                Output[p][o] = 1.0/(1.0 + exp(-SumO[p][o])) ;   /* Sigmoidal Outputs */
                
                
               
                oerror = Error;                     
                Error += 0.5 * (Target[p][o] - Output[p][o]) * (Target[p][o] - Output[p][o]) ;   /* SSE */
               
               
               
               
                oderror = derror;                               // stalling ?
                derror  = Error-oerror;
                if ( (epoch <= 10000) && (Error>=0.5) && ((epoch-offset)>1000)
                     && (abs(derror-oderror)<(minerr/1000) )  ) {
                   offset=epoch;
                   for( o = 1 ; o <= NumOutput ; o ++ ) {    /* initialize WeightLOut and DeltaWeightLOut */
                      for( j = 0 ; j <= NumHidden ; j++ ) {
                        DeltaWeightLOut[j][o] = 0.0 ;
                        WeightLOut[j][o] = 2.0 * ( rando() - 0.5 ) * smallwt ;
                      }
                   }
                   
                   if( (epoch-offset)%3000==0) {
                     for( j = 1 ; j <= NumHidden ; j++ ) {    
                       for( i = 0 ; i <= NumInput ; i++ ) {
                          DeltaWeightLIn[i][j] = 0.0 ;
                          WeightLIn[i][j] = 2.0 * ( rando() - 0.5 ) * smallwt ;
                       }
                     }  
                   }
                   
                   
                   
                   
                   
                }   
                DeltaO[o] = (Target[p][o] - Output[p][o]) * Output[p][o] * (1.0 - Output[p][o]) ;   /* Sigmoidal Outputs, SSE */
            }
            for( j = 1 ; j <= NumHidden ; j++ ) {    /* 'back-propagate' errors to hidden layer */
                SumDOW[j] = 0.0 ;
                for( o = 1 ; o <= NumOutput ; o++ ) {
                    SumDOW[j] += WeightLOut[j][o] * DeltaO[o] ;
                }
                DeltaH[j] = SumDOW[j] * HidOut[p][j] * (1.0 - HidOut[p][j]) ;
            }
            for( j = 1 ; j <= NumHidden ; j++ ) {     /* update weights WeightLIn */
                DeltaWeightLIn[0][j] = eta * DeltaH[j] + alpha * DeltaWeightLIn[0][j] ;
                WeightLIn[0][j] += DeltaWeightLIn[0][j] ;
               
                for( i = 1 ; i <= NumInput ; i++ ) {
                    DeltaWeightLIn[i][j] = eta * Input[p][i] * DeltaH[j] + alpha * DeltaWeightLIn[i][j];
                    WeightLIn[i][j] += DeltaWeightLIn[i][j] ;
                }
            }
            for( o = 1 ; o <= NumOutput ; o ++ ) {    /* update weights WeightLOut */
                DeltaWeightLOut[0][o] = eta * DeltaO[o] + alpha * DeltaWeightLOut[0][o] ;
                WeightLOut[0][o] += DeltaWeightLOut[0][o] ;
                for( j = 1 ; j <= NumHidden ; j++ ) {
                    DeltaWeightLOut[j][o] = eta * HidOut[p][j] * DeltaO[o] + alpha * DeltaWeightLOut[j][o] ;
                    WeightLOut[j][o] += DeltaWeightLOut[j][o] ;
                }
            }
        }
        if( epoch % 10 == 0 )
        {
           sprintf(sbuf, "%-6ld:  Err= %9.7f", epoch, Error) ;
           Serial.print("Epoch "); Serial.println(sbuf);
           myGLCD.print(sbuf, 0, 20);
        }

        if(Error < minerr) {result=1; break;}                          // stop learning when 'near enough'
        if(pbtn(PIN_ESC)){delay(10); while(pbtn(PIN_ESC)); result=2; break;} // stop after Btn press-and-release
    }


       
    BPTime = TimerMS() - TimeStamp;
    return result ;
}












//=====================================================================================
// REPETITIVE LOOP ()
//=====================================================================================
void loop() {
   int16_t  result, quit=0;
   int32_t  choice, btn;
   char     sbuf[128], spatt[20];  // output string
   
   msg_userctrl();   
   Serial.println();

   while(!quit) {

      RefreshInputs();             // polls inputs and stores values to currIn[] array
      
      
      //***********************************
                  //*******************************************************************************
      // debug: test different input sets
       currIn[1]=1; //currIn[2]=0; currIn[3]=1; //currIn[4]=0; currIn[5]=0; currIn[6]=0; currIn[7]=0;
                  //*******************************************************************************    
      //***********************************                
            
      
      ComputeMatrix();         // applies inputs to net and computes outputs to currOut[] array
  
      
      curxy(0,  LCDmaxY - fonthi*(6+NMAXOUT/20) );
      LCDInvers();
      lcdprint("12345678901234567890"); 
      LCDNormal();
      curlf();  
      for (int16_t  o=1; o<=20; ++o) { 
            int16_t ibuf = round(currOut[o]);
            sprintf(sbuf, "%1d", ibuf);
            lcdprint(sbuf);             
            if (o%20==0) {             
               curlf();  
            } 
      }
      

      
      result=CheckTestPattern(currIn);
      sprintf(spatt,"det.inpatt=%3d", result);                 
      myGLCD.print( spatt, 0, (LCDmaxY)-(3*fonthi) );      
     
     
      choice=0;   
     
      // check for btn press
     
      if (btnpressed()) {
         btn=getbtn();
      }
      else btn=-1;           
           
      // action for button press
     
      if( btn==PIN_LE )   {                         // flash current inputs into buffer for processing
         memcpy ( inbuf, currIn, sizeof(currIn) );
         setIOpattern(-1);
      }       
      else   
      if( btn==PIN_OK )  {                          // menu: set net input->target output pattern           
         choice = menu_setinpattern("Menu: Set Inputs");  // define net input pattern
         if (choice != -1)  setIOpattern(-1);             // set related net target output pattern 
      }           
      else
      if( btn==PIN_RI )   {                         // train net         
         result=TrainNet();
         DisplayNetTrainingIOs(result);
         msg_userctrl();
      }
      else
      if( btn==PIN_ESC )  clrnetbuf();              // clear buffers
     
      else
      if( btn==PIN_UP )  {                          // main menu
         choice = menu_0("menu (N/A)");          
      }
      
      else 
      if( btn==PIN_DN )  {                          // # DEBUG 
      for (int i=1; i <= NMAXIN; ++i) { 
             sprintf(sbuf, " %003d", i); Serial.print(sbuf);
         }
         Serial.println();
         for (int i=1; i <= NMAXIN; ++i) {
             sprintf(sbuf, "%4.1f", currIn[i]); Serial.print(sbuf);
         }     
         Serial.println(); Serial.println();
         for (int o=1; o <= NMAXOUT; ++o) {
             sprintf(sbuf, "%4.1f", currOut[o]); Serial.print(sbuf);
         }     
         Serial.println(); 
         Serial.println(spatt);
         Serial.println(); Serial.println();
      }
     
      if( btn >=0 ) {
         Serial.print("choice="); Serial.println(choice);   // # DEBUG
         msg_userctrl();   
      }
   }

   sprintf(sbuf, "\n\nGoodbye!\n\n") ;  Serial.print(sbuf);
   while(true);
   
}


// OK: check pattern, add new pattern, patch old pattern
// OK: learn converging and escape stalling (local min)

//=====================================================================================
//=====================================================================================


/*


M           M  EEEEEEEEEEE  NN          N  U           U
MM         MM  E            N N         N  U           U
M M       M M  E            N  N        N  U           U
M  M     M  M  E            N   N       N  U           U
M   M   M   M  E            N    N      N  U           U
M    M M    M  EEEEEEE      N     N     N  U           U
M     M     M  E            N      N    N  U           U
M           M  E            N       N   N  U           U
M           M  E            N        N  N   U         U
M           M  E            N         N N    U       U
M           M  EEEEEEEEEEE  N          NN     UUUUUUU  


*/

//=====================================================================================
// bottom line user control menu
//=====================================================================================
void msg_userctrl() {
   char     sbuf[128];  // output string   
 
   Serial.println();
   LCDYellowBlue();
   sprintf(sbuf, "Menu:UP clr:ESC learn:RIGHT");
   Serial.println(sbuf);
   myGLCD.print(sbuf, 0, LCDmaxY-20);

   sprintf(sbuf, "inp.patt.set:OK  read:LEFT ");
   Serial.println(sbuf);
   myGLCD.print(sbuf, 0, LCDmaxY-10);   
   
   LCDNormal();   
}




//=====================================================================================
// LCD-TFT menu system
//=====================================================================================

int32_t  menu_0(char caption[] ) {          // main menu               
  const   int16_t MAXMSIZE = 8;                // number of maximum useable menu options
  const   char LSIZE=20;
 
  char    astr[MAXMSIZE][LSIZE+1],               // all options by all inscription string
          opbuf[LSIZE+1],                        // option buffer 
          numbuf[LSIZE+1],                       // num buffer
          last[LSIZE+1] ,  // end of line buffer
          more[LSIZE+1] ,  // next line buffer
          space[LSIZE+1] , // empty line buffer         
          bobross=0;                             // if to paint a beautiful new menu by beautiful colors ;)

         
         
  static   int16_t  ch=0, maxframe=8, minframe=0; // static for re-entering the menu;
  int16_t  btn, i, j, lch, MAXVOPT=8;
  int16_t  val=0, lval=0, hval=3;
 
 
  memset(last, '-', LSIZE );  last[LSIZE]='\0';
  memset(more, '+', LSIZE );  more[LSIZE]='\0';
  memset(space, ' ', LSIZE ); space[LSIZE]='\0';
 
  for (i=0; i<MAXMSIZE; ++i) {
     strcpy(astr[i], space );   
     sprintf(opbuf, "%3d", i);
     strinsert(astr[i], opbuf, 0);
  }
 
 
  strinsert(astr[ 0], "File load  ->  0", 4);
  strinsert(astr[ 1], "File safe  ->  0", 4);
  strinsert(astr[ 2], "show patt. ->  0", 4);
  strinsert(astr[ 3], "erase patt.->  0", 4);
  strinsert(astr[ 4], "option  e ", 4);
  strinsert(astr[ 5], "option  f ", 4);
  strinsert(astr[ 6], "option  g ", 4);
  strinsert(astr[ 7], "option  h ", 4);

  strinsert(astr[MAXMSIZE-1], "option:last ", 4);

  if (ch<0) ch=0;
  if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }
 
  lcdcls();
  LCDWhiteRed();
  myGLCD.print(space, 0, 0);             
  myGLCD.print(caption, (20-strlen(caption))*8/2, 0);
 
  LCDNormal();
  for (i=minframe; i<maxframe; ++i) {
     myGLCD.print(astr[i], 0, (i+1-minframe)*10);
  }     
 
  LCDRedBlack();
  if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10);
  else myGLCD.print(last, 0, (MAXVOPT+1)*10);
 
  LCDInvers();
  myGLCD.print(astr[ch], 0, (ch+1-minframe)*10);
  LCDNormal();

  do {
    lch=ch;
    btn=getbtn();       
   
    if ( ch < 2 )    { lval=0; hval=3;}
    else if ( ch==2) { lval=0; hval=NumPattern;}  // 0 == show all
    else if ( ch==3) { lval=0; hval=NumPattern;}  // 0 == VOID (for safety unerase)
    else { lval=0; hval=0;}
       
       
    if ( (btn==PIN_DN ) ||  (btn==PIN_UP ) ) {   
      val=lval;   
      if (btn==PIN_DN )
      {   
         if(ch<MAXMSIZE-1)  ch++; 
         else {
             ch=0;
             minframe=0;
             maxframe=MAXVOPT;
             if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
          }   
          if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;}       
       }   
       else
       if (btn==PIN_UP ) {
          if (ch > 0)  ch--; 
          else {
             ch=MAXMSIZE-1;
             maxframe=MAXMSIZE;
             minframe=maxframe-MAXVOPT;
             if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
          }
          if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;}
       }
   newbob:   
       LCDNormal();
       if(bobross) {
           for (i=minframe; i<maxframe; ++i) {
              myGLCD.print(astr[ch], 0, (i+1-minframe)*10);
           }               
           bobross=0;
       }   
       else
       {
          myGLCD.print(astr[lch], 0, (lch+1-minframe)*10);
       }
       LCDRedBlack();
       if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10);
       else myGLCD.print(last, 0, (MAXVOPT+1)*10);       
       
       LCDInvers();
       myGLCD.print(astr[ch], 0, (ch+1-minframe)*10);
       LCDNormal();
    }   

    if ( (btn==PIN_RI) || (btn==PIN_LE) ) {                 // change input buffer value
       
       if (ch < 4) {                                        // toggle through sub menu options       
          if (btn==PIN_RI) val=toggleup(lval, hval, val);
          if (btn==PIN_LE) val=toggledn(lval, hval, val);
          sprintf(numbuf, "%3d", val);
          strcpy(opbuf, astr[ch]);
          strinsert(opbuf, numbuf, LSIZE-3);
          LCDInvers();
          myGLCD.print(opbuf, 0, (ch+1-minframe)*10);       // write line buffer = serial number + option
          LCDNormal();
       }
    }

  } while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;

  lcdcls();
  if (btn==PIN_ESC) { return -1; }

  if (ch==0) { ;}  // File load  ->  val
  else
  if (ch==1) { ;}  // File safe  ->  val
  else
  if (ch==2) { displayMatrix(val) ;}  // show patt. ->  val
  else
  if (ch==3) { ;}  // erase patt.->  val
 
  return val+(ch*10000);      // return number of suboption + 10000* option
 
}


//=====================================================================================
// menu: set target outputs manually 
//=====================================================================================
int8_t  menu_setouttargets(char caption[]) {     // set targets
  const   int16_t MAXMSIZE = NMAXOUT;            // number of maximum useable menu options
  const   char LSIZE=17;                         // string length of line for option inscriptions

  char    astr[MAXMSIZE+1][LSIZE+1],             // all options by all inscription string
          opbuf[LSIZE+1],                        // option buffer
          buf[LSIZE+5] ="                     ", // line buffer = serial number + option inscription
          lbuf[LSIZE+5]="---------------------", // end of line buffer (-> last element)
          more[LSIZE+5]="+ + + + + + + + + + +", // next line buffer (-> more elements)
          bobross=0;                             // if to paint a beautiful new menu by beautiful colors ;)


  int8_t  btn, i, lch, MAXVOPT=10;
  int8_t  ch=0, maxframe=MAXVOPT, minframe=1;      // static for re-entering the menu;


  memcpy(outbuf, currOut, sizeof(outbuf) );
  for (i=1; i<=MAXMSIZE; ++i) {                   // initialize all lines in inscription array
     sprintf(opbuf, "Output%3d= %.0f    ", i, outbuf[i] );
     strcpy(astr[i], opbuf );                     // inscription = option + outbuf value
  }

  if (ch<1) ch=1;
  if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }

  lcdcls();
  LCDWhiteRed();
  myGLCD.print(buf, 0, 0);
  myGLCD.print(caption, (20-strlen(caption))*8/2, 0);

  LCDNormal();
  for (i=minframe; i<=maxframe; ++i) {
     sprintf(buf, "%3d %s", i, astr[i]);        // build line buffer = serial number + inscription
     myGLCD.print(buf, 0, (i+1-minframe)*10);
  }
  LCDRedBlack();
  if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (i+1-minframe)*10);
  else myGLCD.print(lbuf, 0, (i+1-minframe)*10);

  LCDInvers();
  sprintf(buf, "%3d %s", ch, astr[ch]);
  myGLCD.print(buf, 0, (ch+1-minframe)*10);
  LCDNormal();

  do {
    lch=ch;
    btn=getbtn();
    if ( (btn==PIN_DN ) ||  (btn==PIN_UP ) ) {                   // btn up/dn: dec/inc current option
      if (btn==PIN_DN ) {
          if(ch < MAXMSIZE)  ch++;  
          else {
             ch=1;
             minframe=1;
             maxframe=MAXVOPT;
             if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
          }
          if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;}   // adjust visible frame
       }
       else
       if (btn==PIN_UP ) {
          if (ch > 1)  ch--;  
          else {
             ch=MAXMSIZE;
             maxframe=MAXMSIZE;
             minframe=maxframe-MAXVOPT+1;
             if ( minframe != 1) { bobross=1; goto newbob; }
          }
          if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;}    // adjust visible frame
       }
   newbob:                                      // if frame has changed: move frame, paint anew
       LCDNormal();
       if(bobross) {
           for (i=minframe; i<=maxframe; ++i) {
              sprintf(buf, "%3d %s", i, astr[i]);
              myGLCD.print(buf, 0, (i+1-minframe)*10);  // write all visible complete line buffers
           }
           bobross=0;
       }
       else
       {
          sprintf(buf, "%3d %s", lch, astr[lch]);
          myGLCD.print(buf, 0, (lch+1-minframe)*10);    // write old line buffer (normal)
       }
       LCDRedBlack();
       if(maxframe<MAXMSIZE) {                          // write line for "more elements"
          myGLCD.print(more, 0, (i+1-minframe)*10);
       }
       else myGLCD.print(lbuf, 0, (i+1-minframe)*10);   // write line "last element"

       LCDInvers();
       sprintf(buf, "%3d %s", ch, astr[ch]);
       myGLCD.print(buf, 0, (ch+1-minframe)*10);        // write current line buffer (invers)
       LCDNormal();
    }
    if ( (btn==PIN_RI) || (btn==PIN_LE) ) {             // change input buffer value
       if (btn==PIN_RI) outbuf[ch]=1;
       if (btn==PIN_LE) outbuf[ch]=0;
       sprintf(opbuf, "Output%3d= %.0f    ", ch, outbuf[ch] );
       strcpy(astr[ch], opbuf );
       sprintf(buf, "%3d %s", ch, astr[ch]);            // update inscription: option + outbuf value
       LCDInvers();
       myGLCD.print(buf, 0, (ch+1-minframe)*10);        // write line buffer = serial number + inscription
       LCDNormal();
    }

  } while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;


  if (btn==PIN_ESC) { lcdcls();  return -1; }
  

  lcdcls();
  return ch;
}

      


//=====================================================================================
// menu: set inputs manually
//=====================================================================================
int16_t  menu_setinpattern(char caption[]) {      // set inputs             
  const   int16_t MAXMSIZE = NMAXIN;             // number of maximum useable menu options
  const   char LSIZE=17;                         // string length of line for option inscriptions
 
  char    astr[MAXMSIZE+1][LSIZE+1],             // all options by all inscription string
          opbuf[LSIZE+1],                        // option buffer         
          buf[LSIZE+5] ="                     ", // line buffer = serial number + option inscription
          lbuf[LSIZE+5]="---------------------", // end of line buffer (-> last element)
          more[LSIZE+5]="+ + + + + + + + + + +", // next line buffer (-> more elements)         
          bobross=0;                             // if to paint a beautiful new menu by beautiful colors ;)
 
         
  int16_t  btn, i, lch, MAXVOPT=10;
  static   int16_t  ch=0, maxframe=MAXVOPT, minframe=1;      // static for re-entering the menu;
   
  strcpy(astr[0], "static  0" );
  for (i=1; i<=MAXMSIZE; ++i) {                   // initialize all lines in inscription array
     sprintf(opbuf, "Input%3d = %.0f    ", i, inbuf[i] );
     strcpy(astr[i], opbuf );                     // inscription = option + inbuf value
  }

  if (ch<1) ch=1;
  if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }
 
  lcdcls();
  LCDWhiteRed();
  myGLCD.print(buf, 0, 0);             
  myGLCD.print(caption, (20-strlen(caption))*8/2, 0);
 
  LCDNormal();
  for (i=minframe; i<=maxframe; ++i) {
     sprintf(buf, "%3d %s", i, astr[i]);        // build line buffer = serial number + inscription
     myGLCD.print(buf, 0, (i+1-minframe)*10);
  }     
  LCDRedBlack();
  if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10 );
  else myGLCD.print(lbuf, 0, (MAXVOPT+1)*10 );
 
  LCDInvers();
  sprintf(buf, "%3d %s", ch, astr[ch]);
  myGLCD.print(buf, 0, (ch+1-minframe)*10);
  LCDNormal();

  do {
    lch=ch;
    btn=getbtn();       
    if ( (btn==PIN_DN ) ||  (btn==PIN_UP ) ) {                   // btn up/dn: dec/inc current option
      if (btn==PIN_DN ) {
          if(ch < MAXMSIZE)  ch++; 
          else {
             ch=1;
             minframe=1;
             maxframe=MAXVOPT;
             if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
          }
          if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;}   // adjust visible frame
       }
       else
       if (btn==PIN_UP ) {
          if (ch > 1)  ch--; 
          else {
             ch=MAXMSIZE;
             maxframe=MAXMSIZE;
             minframe=maxframe-MAXVOPT+1;
             if ( minframe != 1) { bobross=1; goto newbob; }
          }
          if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;}    // adjust visible frame
       }
   newbob:                                      // if frame has changed: move frame, paint anew
       LCDNormal();
       if(bobross) {
           for (i=minframe; i<=maxframe; ++i) {
              sprintf(buf, "%3d %s", i, astr[i]);
              myGLCD.print(buf, 0, (i+1-minframe)*10);  // write all visible complete line buffers
           }               
           bobross=0;
       }   
       else
       {
          sprintf(buf, "%3d %s", lch, astr[lch]);
          myGLCD.print(buf, 0, (lch+1-minframe)*10);    // write old line buffer (normal)
       }
       LCDRedBlack();
       if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10 );
       else myGLCD.print(lbuf, 0, (MAXVOPT+1)*10 );
       
       LCDInvers();
       sprintf(buf, "%3d %s", ch, astr[ch]);
       myGLCD.print(buf, 0, (ch+1-minframe)*10);        // write current line buffer (invers)
       LCDNormal();
    }   
    if ( (btn==PIN_RI) || (btn==PIN_LE) ) {             // change input buffer value
       if (btn==PIN_RI) inbuf[ch]=1;
       if (btn==PIN_LE) inbuf[ch]=0;
       sprintf(opbuf, "Input%3d = %.0f    ", ch, inbuf[ch] );
       strcpy(astr[ch], opbuf );
       sprintf(buf, "%3d %s", ch, astr[ch]);            // update inscription: option + inbuf value         
       LCDInvers();
       myGLCD.print(buf, 0, (ch+1-minframe)*10);        // write line buffer = serial number + inscription
       LCDNormal();       
    }
   
  } while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;             

  lcdcls();
  if (btn==PIN_ESC) { return -1; }
  return ch;
}                                     


//=====================================================================================
//=====================================================================================




// end of file
- - - Aktualisiert - - -

PS,
der Code aus dem RobotC Forum stammt auch von mir, allerdings war RobotC damals dermaßen unglaublich verbugged (und dann auch noch recht teuer), dass ich anschließend zu NXC gewechselt bin.