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
Lesezeichen