Go Down

Topic: Program causing Arduino to reset? (Read 467 times) previous topic - next topic

ajb

Jun 12, 2009, 07:42 pm Last Edit: Jun 12, 2009, 07:45 pm by ajb Reason: 1
I'm working on a menu system for a project, and for some reason hitting the "back" button which causes a menu screen handler to return a reference to a parent menu causes the Arduino to jump back to the setup function.  I'm not sure if it's doing a full reset because when I added an LED that's turned on right before the return statement, that LED stays on until I actually hit the reset button.  I've pretty much ruled out a hardware issue with the button, so I must be missing something in software.

Any insight is appreciated.

The problem occurs at the indicated line at the end of DataScreen.maintain()

Code: [Select]
/*******************************************************************************************************
/  CLASS MenuItem
/  base class for all of the various menu screens so that the currentItem pointer may point to any
/  of the sketch's menus.
/
/******************************************************************************************************/

class MenuItem {
 public:
   char descript[16];
   MenuItem* parent;
   virtual void display(){};
   virtual MenuItem* handleButton( int button ){};
   virtual MenuItem* maintain(){}; //do any required maintenance, ie-poll sensors to update screen data
};

/*******************************************************************************************************
/  CLASS DataScreen
/  for displaying sensor data
/
/******************************************************************************************************/

class SensorScreen : public MenuItem {
 protected:
   unsigned int currentDatum; //current datum that should be displayed
   unsigned long lastPoll; //time of last sensor data update
   boolean refresh; // flag indicates if screen needs to be refreshed
 
 public:
   SensorScreen(char desc[], MenuItem *par ) {
     parent = par;
     strcpy(descript, desc);
     currentDatum=0;
     lastPoll=0;
     refresh=true;
   }
    void display() {
      Serial.println("display");
     lcd.clear();
     lcd.home();
     lcd.print(valueNames[currentDatum]);
     lcd.setCursor(0,1);
     lcd.print(currentDatum);
     lcd.print(":");
     lcd.print(sensorData[currentDatum]);
   }
   MenuItem* maintain() {
      //Serial.println("maintain");
     if( millis() - lastPoll > pollInterval ) {
       //poll sensors again;
     }
     if( up.changed && up.pressed ) {
       currentDatum = ( currentDatum < 66 ? currentDatum + 1 : 0 );
       refresh=true;
     }
     if( dn.changed && dn.pressed ) {
       currentDatum = ( currentDatum > 0 ? currentDatum - 1 : 66 );
       refresh=true;
     }

     if( back.changed && back.pressed ) {
       digitalWrite(12, HIGH); //troubleshooting LED
       return parent; //this is where things go bad
     }
     else {
       if(refresh){
         display();
         refresh=false;
       }
       return this;
     }
   }
};

/*******************************************************************************************************
/  CLASS SelectScreen
/  base class for all of the various menu screens so that the currentItem pointer may point to any
/  of the sketch's menus.
/
/******************************************************************************************************/

class SelectScreen : public MenuItem {
 protected:
   int currentSelection;
   boolean refresh;
 public:
   MenuItem *options[1];
   SelectScreen( char desc[] ) {
     strcpy(descript, desc);
     currentSelection=0;
     refresh=true;
     parent = this;
   }
   void display() {
     lcd.clear();
     lcd.print(options[currentSelection]->descript);
   }
   MenuItem * maintain() {
     if( enter.changed && enter.pressed ) {
       return options[currentSelection];
     }
     else return this;
   }
};


MenuItem *currentItem;
SelectScreen mainMenu("Main Menu");

SensorScreen sensorScreen("View sensor data", &mainMenu);

void setup() {
 mainMenu.options[0] = &sensorScreen ;
 Serial.begin(9600);
 lcd.clear();
 lcd.print("hello!");
 currentItem = &mainMenu;
 delay(1000);
 currentItem->display();
 pinMode(12, OUTPUT);

}

void loop(){
 up.refresh();
 dn.refresh();
 back.refresh();
 enter.refresh();
 
 currentItem = currentItem->maintain();  
}

ajb

I added another derived class ModeScreen similar to DataScreen, and ModeScreen.maintain() does exactly what I want it to!  DataScreen.maintain() still fails.  I changed the way the value gets returned (changed "return parent;" to "return parent->display(); to ensure the new screen is displayed properly) as well.

Code: [Select]
/*******************************************************************************************************
/  CLASS MenuItem
/  base class for all of the various menu screens so that the currentItem pointer may point to any
/  of the sketch's menus.
/
/******************************************************************************************************/

class MenuItem {
 public:
   char descript[16];
   MenuItem* parent;
   virtual MenuItem* display(){};
   virtual MenuItem* maintain(){}; //do any required maintenance, ie-poll sensors to update screen data
};

/*******************************************************************************************************
/  CLASS DataScreen
/  for displaying sensor data
/
/******************************************************************************************************/

class SensorScreen : public MenuItem {
 protected:
   unsigned int currentDatum; //current datum that should be displayed
   unsigned long lastPoll; //time of last sensor data update
   boolean refresh; // flag indicates if screen needs to be refreshed
 
 public:
   SensorScreen(char desc[], MenuItem *par ) {
     parent = par;
     strcpy(descript, desc);
     currentDatum=0;
     lastPoll=0;
     refresh=true;
   }
   MenuItem * display() {
      Serial.println("display");
     lcd.clear();
     lcd.home();
     lcd.print(valueNames[currentDatum]);
     lcd.setCursor(0,1);
     lcd.print(currentDatum);
     lcd.print(":");
     lcd.print(sensorData[currentDatum]);
     return this;
   }
   MenuItem* maintain() {
      //Serial.println("maintain");
     if( millis() - lastPoll > pollInterval ) {
       //poll sensors again;
     }
     if( up.changed && up.pressed ) {
       currentDatum = ( currentDatum < 66 ? currentDatum + 1 : 0 );
       refresh=true;
     }
     if( dn.changed && dn.pressed ) {
       currentDatum = ( currentDatum > 0 ? currentDatum - 1 : 66 );
       refresh=true;
     }

     if( back.changed && back.pressed ) {
       digitalWrite(12, HIGH); //troubleshooting LED
       return parent->display(); //this is where things go bad
     }
     else {
       if(refresh){
         display();
         refresh=false;
       }
       return this;
     }
   }
};

/*******************************************************************************************************
/  CLASS SelectScreen
/  base class for all of the various menu screens so that the currentItem pointer may point to any
/  of the sketch's menus.
/
/******************************************************************************************************/

class SelectScreen : public MenuItem {
 protected:
   int currentSelection;
   boolean refresh;
 public:
   MenuItem *options[2];
   SelectScreen( char desc[] ) {
     strcpy(descript, desc);
     currentSelection=0;
     refresh=true;
     parent = this;
   }
   MenuItem * display() {
     lcd.clear();
     lcd.print(options[currentSelection]->descript);
     return this;
   }
   MenuItem * maintain() {
     if( up.changed && up.pressed ) {
       currentSelection = ( currentSelection < 1 ? currentSelection + 1 : 0 );
       refresh=true;
     }
     if( dn.changed && dn.pressed ) {
       currentSelection = ( currentSelection > 0 ? currentSelection - 1 : 1 );
       refresh=true;
     }
     if( enter.changed && enter.pressed ) {
       return options[currentSelection]->display();
     }
     else {
       if(refresh){
         display();
         refresh=false;
       }
       return this;
     }
   }
};


/*******************************************************************************************************
/  CLASS ModeScreen
/  issue mode to ECU
/
/******************************************************************************************************/

class ModeScreen : public MenuItem {
 protected:
   int currentSelection;
   boolean refresh;
   unsigned int modes;
     
     
 public:
   ModeScreen( char desc[], MenuItem *par ) {
     strcpy(descript, desc);
     currentSelection=0;
     refresh=true;
     parent = par;
     modes=9;

   }
   MenuItem * display() {
     lcd.clear();
     lcd.print(modeDesc[currentSelection][0]);
     lcd.setCursor(0,1);
     lcd.print(modeDesc[currentSelection][1]);
     return this;
   }
   MenuItem * maintain() {
     if( up.changed && up.pressed ) {
       currentSelection = ( currentSelection < 8 ? currentSelection + 1 : 0 );
       refresh=true;
     }
     if( dn.changed && dn.pressed ) {
       currentSelection = ( currentSelection > 0 ? currentSelection - 1 : 8 );
       refresh=true;
     }

     if( back.changed && back.pressed ) {
       return parent->display(); //And this one works fine?!?!
     }
     else {
       if(refresh){
         display();
         refresh=false;
       }
       return this;
     }
   }
};

MenuItem *currentItem;
SelectScreen mainMenu("Main Menu");

SensorScreen sensorScreen("View sensor data", &mainMenu);
ModeScreen modeScreen("Issue Mode", &mainMenu);

void setup() {
 mainMenu.options[0] = &sensorScreen;
 mainMenu.options[1] = &modeScreen;
 Serial.begin(9600);
 lcd.clear();
 lcd.print("hello!");
 currentItem = &mainMenu;
 delay(1000);
 currentItem->display();
 pinMode(12, OUTPUT);

}

void loop(){
 up.refresh();
 dn.refresh();
 back.refresh();
 enter.refresh();
 
 currentItem = currentItem->maintain();  
}

ajb

#2
Jun 12, 2009, 10:03 pm Last Edit: Jun 12, 2009, 10:04 pm by ajb Reason: 1
Problem resolved, although I don't understand why.

I moved the parent pointer assignment further down in the constructor for the SensorScreen class, and now it works  :confused

Basically changed this:

Code: [Select]
   SensorScreen(char desc[], MenuItem *par ) {
     parent = par;
     strcpy(descript, desc);
     currentDatum=0;
     lastPoll=0;
     refresh=true;
   }

to this:
Code: [Select]
   SensorScreen(char desc[], MenuItem *par ) {
     strcpy(descript, desc);
     currentDatum=0;
     lastPoll=0;
     refresh=true;
     parent = par;
   }

RuggedCircuits

char descript[16] isn't long enough. You need an extra byte to store the terminating 0 at the end of the string "View sensor data"

Go Up