[Reaction Time Test] Struct?!

Hi, I'm a 20 year old girl and a complete newbie in the Arduino world. This is an assignment for school (due tomorrow hehe), and I have made a Reaction Time Tester. I still need to include struct, pointer, "call by reference", "call by value" and string compare.

The current code works fine, but I want to make the players' name and average score (avg) "stick to" each player, so it's possible to review the score after the test (case 3 in void loop(); //review data). I think I should be able to use struct for this, but I'm not completely familiar with how to use it.

I did make some kind of
struct player{
String name;
int avg; //average score
}

but I can't figure out how to refer to that in void reactTest();

I would be very grateful if you could look at it and help me figure out how to add this struct.

~ Heidi

String name;       //Player's name
unsigned long startTime, stopTime;
int reactTime[5];
int dif;
int sum;
int avg;            //Average reacttime
int players;
int p;
int i;
int a;
#define tr 5        //Amount of tries
  
void welcome()
{
  Serial.println("Welcome to the reaction-time test - what would you like to do?");
  Serial.println("Enter 1 to view instructions. Enter 2 to take the test. Enter 3 to review data.");
  Serial.println();
}

void instructions()
{
  Serial.println();
  Serial.println("Reaction-time test instructions:");
  delay(1000);
  Serial.println("When the LED turns on, you press the button as fast as you can.");
  Serial.print("But no cheating... "); 
  Serial.println("You always have to let go of the button between tries!");
  delay(2000);
  Serial.println("There are three seconds between each try.");
  Serial.println("Each player gets five tries, and the average is his/her score.");
  delay(5000);
}

void countdown()
{
  delay(7000);
  Serial.println("3");
  delay(1000);
  Serial.println("2");
  delay(1000);
  Serial.println("1");
  delay(1000);
}

void reactTest()
{
  Serial.println("How many players are there?");
  while (Serial.available()==0){
  }
  players = Serial.parseInt();
  for (int p = 0; p < players; p++)
  {
    Serial.println();
    Serial.print("Player #");
    Serial.print(p+1);
    Serial.println(", write your name");
    while (Serial.available()==0){
    }
    name = Serial.readString();
    delay(1000);

    Serial.print("Get ready ");
    Serial.print(name);
    Serial.println(", the test starts in 10 seconds:");
    countdown();

    for (int i = 0; i < tr; i++)
    {  
      delay (random(1000, 5000));   //random delay between 1-5 seconds
      startTime = millis();
      digitalWrite(13, HIGH);       //let there be light
      while (digitalRead(9) == HIGH){ //do nothing - just wait
      }
      //now button is pressed
      digitalWrite(13, LOW); //turn off LED
      stopTime = millis();
      dif = stopTime - startTime;
      if (dif==0)
      {
        Serial.print("Cheater cheater pumpkin eater - You get punishment-points: ");
        reactTime[i] = 5000;      
        Serial.println(reactTime[i]);
      }
      else
      {
        Serial.print("Your reactiontime in milliseconds is: ");
        Serial.println(dif);
        reactTime[i] = dif;
      }
      delay(500);
      if(tr-1-i==1 ){
        Serial.print("  You have ");
        Serial.print(tr-1-i);
        Serial.println(" try left");
      }
      else if(tr-1-i==0){
        Serial.println("  Test is complete!");
      }   
      else{
        Serial.print("  You have ");
        Serial.print(tr-1-i);
        Serial.println(" tries left");
      }
      delay(3000);
    }  
        int sum = 0;
      for(i = 0; i < tr; i++)
      {
        sum = sum + reactTime[i];
      }
      avg = sum/tr;
      Serial.println();
      Serial.print(name);
      Serial.print(", your average reactiontime is: ");
      Serial.println(avg);  
  }
  delay(5000);
}

void testResults()
{
 /* possible High Score, otherwise something like:
 Player #1 Name, Average RT
 Player #2 Name, Average RT etc.
 */
}

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  pinMode(9, INPUT_PULLUP); //connect wires to GND and 9
}  

void loop()
{
  boolean tests = false;
  welcome();
  while (Serial.available()==0){
  }
  a = Serial.parseInt();
  switch (a){
  case 1:
    instructions();
    break;
  case 2:
    reactTest();
    tests = true;
    break;
  case 3:
  // FIX CASE 3 !!!
  if (tests){
      testResults();
    }
    else{
      Serial.println("Someone has to take the test to begin with...");
      Serial.println();
    }
    break;
  }
  Serial.println("---------------------------------------------------------------------------");
  Serial.println();
}

P.s. This is my first topic so I don't know how to add the code, but I attached it both as .txt and as .ino Update: I figured this out :slight_smile:

1001.txt (3.88 KB)

_1001.ino (3.73 KB)

Interesting project ... reminds me of this:

This is a simple tool to measure your reaction time

Attaching the files is OK, however code can be added by selecting it, then clicking this

Thank you, you're right - it's very similar :smiley:

Can you help me with the struct though?

~Heidi

Sorry, I haven't used them (yet). The Arduino playground has lots of various examples ...
perhaps something here could help: Data Structures & Algorithms

First, I'd quit using the String class...it just has too much overhead. As to your structure, how about:

struct Players {
   char name[21];   // Max 20 with one for null termination character
   unsigned long average;
} myPlayers[10];

Now you can have up to 10 players. To access a member:

   int charsRead;
   int thisPlayer = 0;    // The index for the current player...

   // Serial read code...

      charsRead = Serial.readBytesUntil('\n', myPlayers[thisPlayer].name, 20);
      myPlayers[thisPlayer].name[charsRead] = '\0';   // make it a string
  
   // more code to reaction time...
     myPlayers[thisPlayer].average = avr;

I can't test this out right now, but it may help you look in the right direction.

Thank you so much! This definitely helps!

I will try to figure the rest out, but if you have time later tonight or tomorrow, I would be very grateful if you could help me a bit more... I am very new to this haha :slight_smile:

If not, no problem - thanks again!

~Heidi

Okay... I have nooooo idea how, but I made this work. At first I changesd String to char like econjack reccomended, but then I got another Error so I changed it back.

All of sudden, this just worked. I have no idea why, but here is the code at least:

String name;
unsigned long avg;
unsigned long startTime, stopTime;
int reactTime[5];
int dif;
int sum;
int players;
int p;
int i;
int a;
#define tr 5        //Amount of tries

struct players{
  String name; //Max 20 characters, 1 for null termination character
  unsigned long avg;
}; 
struct players myPlayers[10];

void welcome()
{
  Serial.println("Welcome to the reaction-time test - what would you like to do?");
  Serial.println("Enter 1 to view instructions. Enter 2 to take the test. Enter 3 to review data.");
  Serial.println();
}

void instructions()
{
  Serial.println();
  Serial.println("Reaction-time test instructions:");
  delay(1000);
  Serial.println("When the LED turns on, you press the button as fast as you can.");
  Serial.print("But no cheating... "); 
  Serial.println("You always have to let go of the button between tries!");
  delay(2000);
  Serial.println("There are three seconds between each try.");
  Serial.println("Each player gets five tries, and the average is his/her score.");
  delay(5000);
}

void countdown()
{
  delay(7000);
  Serial.println("3");
  delay(1000);
  Serial.println("2");
  delay(1000);
  Serial.println("1");
  delay(1000);
}

void reactTest()
{
  Serial.println("How many players are there?");
  while (Serial.available()==0){
  }
  players = Serial.parseInt();
  for (int p = 0; p < players; p++)
  {
    String n;
    int charsRead;
    int thisPlayer = 0; //The index for the current player
 
    Serial.println();
    Serial.print("Player #");
    Serial.print(p+1);
    Serial.println(", write your name");
    while (Serial.available()==0){
    }
    myPlayers[p].name = Serial.readString();
  
    delay(1000);

    Serial.print("Get ready ");
    Serial.print(myPlayers[p].name);
    Serial.println(", the test starts in 10 seconds:");
    countdown();

    for (int i = 0; i < tr; i++)
    {  
      delay (random(1000, 5000));   //random delay between 1-5 seconds
      startTime = millis();
      digitalWrite(13, HIGH);       //let there be light
      while (digitalRead(9) == HIGH){ //do nothing - just wait
      }
      //now button is pressed
      digitalWrite(13, LOW); //turn off LED
      stopTime = millis();
      dif = stopTime - startTime;
      if (dif==0)
      {
        Serial.print("Cheater cheater pumpkin eater - You get punishment-points: ");
        reactTime[i] = 5000;      
        Serial.println(reactTime[i]);
      }
      else
      {
        Serial.print("Your reactiontime in milliseconds is: ");
        Serial.println(dif);
        reactTime[i] = dif;
      }
      delay(500);
      if(tr-1-i==1 ){
        Serial.print("  You have ");
        Serial.print(tr-1-i);
        Serial.println(" try left");
      }
      else if(tr-1-i==0){
        Serial.println("  Test is complete!");
      }   
      else{
        Serial.print("  You have ");
        Serial.print(tr-1-i);
        Serial.println(" tries left");
      }
      delay(3000);
    }  
    int sum = 0;
    for(i = 0; i < tr; i++)
    {
      sum = sum + reactTime[i];
    }
    myPlayers[p].avg = sum/tr;
    Serial.println();
    Serial.print(myPlayers[p].name);
    Serial.print(", your average reactiontime is: ");
    Serial.println(myPlayers[p].avg);  
  }
  delay(5000);
}

void testResults()
{
  for (int i = 0; i < players; i++){
    Serial.print("Data for player #");
    Serial.println(i+1);
    Serial.print("Name: ");
    Serial.println(myPlayers[i].name);
    Serial.print("Score: ");
    Serial.println(myPlayers[i].avg);
    Serial.println();
  }
    /* possible High Score, otherwise something like:
   Player #1 Name, Average RT
   Player #2 Name, Average RT etc.
   */
}

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  pinMode(9, INPUT_PULLUP); //connect wires to GND and 9
}  

void loop()
{
  boolean tests = false;
  welcome();
  while (Serial.available()==0){
  }
  a = Serial.parseInt();
  switch (a){
  case 1:
    instructions();
    break;
  case 2:
    reactTest();
    tests = true;
    break;
  case 3:
    // FIX CASE 3 !!!
    if (tests = true){
      testResults();
    }
    else {
      Serial.println("Someone has to take the test to begin with...");
      Serial.println();
    }
    break;
  }
  Serial.println("---------------------------------------------------------------------------");
  Serial.println();
}

You're using an awful lot of RAM with all those constant strings.
Have a look at using the F() macro to make sure they stay in flash, where they belong.

AWOL:
You're using an awful lot of RAM with all those constant strings.
Have a look at using the F() macro to make sure they stay in flash, where they belong.

Okay, I may sound like an idiot... but when you say "all those constant strings" I get the feeling you are talking about the integers. Is int a string?

I began working with Arduino on Friday, so I am very very new to this. Still I am pretty proud of my code haha.

I will probably learn to use F() macro one day, thank you :slight_smile:

  Serial.println("Welcome to the reaction-time test - what would you like to do?");

The string in the quotes is what needs to be wrapped in the F() macro:
Serial.println(F("Welcome to the reaction-time test - what would you like to do?"));

Numeric data that do not have a fractional value are integers (i.e., whole numbers) and are usually defined with the byte, int, or long data type. Which one to choose depends upon the range of values you need to cover. Textual data, which often appears within double quotation marks, is called string data. Collectively, these data types are what your program manipulates.

Your Arduino (assume an Uno) has three types of memory: 1) Flash, about 32,000 bytes, and is where your program resides, 2) SRAM, 2,000 bytes, where all your variables must reside, and 3) EEPROM, 1,000 bytes. Usually, your program will run out of SRAM before it runs out of Flash memory. A problem is that everything you have in your current program that appears between double quotes (i.e., a string) is duplicated in Flash and SRAM. Paul's suggestion of using the F() macro prevents your strings from chewing up SRAM memory by using only Flash memory.

Also, there is a difference between String (note the capital S) and string (lowercase s). Using String data is a memory hog compared to using string data, which is why I suggested using strings created using char arrays.

Still, the fact that you got your code to work is great considering the short time you've been working on it.

econjack:
Numeric data that do.....

Wow, I actually understood a lot of what you said, and this makes sense. Thank you! :grin:

Interesting to learn about the F macro.
But annoying that it not mentioned in the language reference. Why is that?!

JAndersM:
Interesting to learn about the F macro.
But annoying that it not mentioned in the language reference. Why is that?!

Not mentioned?

OK, I stand corrected. It is mentioned.
But it is not fund under utilities nor when PROGMEM is discussed or under string.