A-Level Project - Help Needed Please!

I am writing a program to run a project I am doing for my Electronics A-Level. It involves telling the user to press a certain button (via and LCD screen, working!), then timing between the command and the button press. This needs to then be shown on the LCD screen.

I can work out how to time between the command and button press. But I am confused as to how I would loop it back to just timing if the button is not pressed at a certain point.

Here's the code:

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

unsigned long timeBegin; // A variable for the start time of a timer
long randomTimer; // A variable for the length of a timer
long timerLength; // The length of time the timer ran
int minTimer = 500; // The minimum timer length
int maxTimer = 3000; // The maximum timer length
#define redB 1
#define blueB 2
#define yellowB 3
#define greenB 4

void setup(){
}

void loop(){
}

unsigned int testTime(){
lcd.print("Press Button X, "); // Print a textual command
timeBegin = millis(); // Set the start time of the timer
randomTimer = random(3minTimer, maxTimer); // Set a random timer length
if(digitalRead(redB) == 1) { // If the button is pressed
timerLength = (millis() - timeBegin); // Work out the time it took
}
else { // If the button is not pressed
timeBegin = millis(); // Set the start time of the timer
}
}

As you can see it's not finished, but I don't know where to go!

I have had some help from a mate that programs in C,

So far I have:

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

unsigned long timeBegin; // A variable for the start time of a timer
long randomTimer; // A variable for the length of a timer
long timerLength; // The length of time the timer ran
float timeSec; // timerLength in seconds (decimal)
char timeSecString; // String to PRINT timeSec
int minTimer = 500; // The minimum timer length
int maxTimer = 3000; // The maximum timer length
int randomButton; // Variable to store randomly selected button
#define X 1 // Pin of RED button
#define Y 2 // Pin of BLUE button
#define A 3 // Pin of YELLOW button
#define B 4 // Pin of GREEN button
#define B1 5 // Pin of Bumper 1
#define B2 6 // Pin of Bumper 2
#define B3 7 // Pin of Bumper 3
#define B4 8 // Pin of Bumper 4
char buttonNames[] = {
'X','Y','A','B','B1','B2','B3','B4'}; // array of button names

void setup(){
// Set inputs for buttons!
}

void loop(){
randomButton = random(0,7); // Randomly select a button
testButton(buttonNames[randomButton]); // Run the testButton code
delay(1000); // on the randomly selected program
}

unsigned int testButton(char buttonName)
{
lcd.print("Press Button "); // Print a textual command
lcd.print(buttonName); // Print name of button
lcd.print(", "); // Print a textual command
timeBegin = millis(); // Set the start time of the timer
while(checkButtonPress(buttonName)){
// This will only be executed if the button has been pressed
timerLength = (millis() - timeBegin); // Work out the time it took
lcd.home();
delay(50);
lcd.print("That took,");
calcTime();
lcd.print(timeSec);
lcd.setCursor(0,1);
lcd.print(" Good! ");
}
}

bool checkButtonPress(int buttonCode)
{
if(digitalRead(buttonCode) == 1) { // Check status of PIN (HIGH)
return true; // If true return true
}
return false; // If false return false
}

void calcTime() {
timeSec = (timerLength / 1000.0);
}

I think this will work, but i'm not sure about the looping if the button is NOT pressed, but I think it will!

Have a look at the pulseIn function : http://www.arduino.cc/en/Reference/PulseIn

You can call that with the pin number of the button and it will tell you how many microseconds it took for the pulse to go high or low.

Also, it looks you are using #define to convert pin names to pin numbers.

The usual way to do this is to have an array of names and an array of pin numbers.
char buttonNames[] = {'X','Y','A','B','B1','B2','B3','B4'}; // array of button names
char buttonPins[] = {2,3,4 etc

(BTW don't use pin 1 if you use the Serial port.)

then buttonName will be on buttonPin

Ah ok, this seems like a much simpler solution!

I only put in the pin numbers as default. I'm going to configure them to fit my PCB layout later on.

Cheers! :slight_smile:

This is the revised code I have developed thanks to mem:

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

long randomTimer; // A variable for the length of a timer
unsigned long timerLength; // The length of time the timer ran
float timeSec; // timerLength in seconds (decimal)
char timeSecString; // String to PRINT timeSec
int minTimer = 500; // The minimum timer length
int maxTimer = 3000; // The maximum timer length
int randomButton; // Variable to store randomly selected button
char buttonPin[] = { // Define button pin-numbers
1,2,3,4,5,6,7,8};
char buttonNames[] = { // Define button names
'X','Y','A','B','B1','B2','B3','B4'};

void setup(){
for(int i=0; i<8; i++){
pinMode(buttonPin*, INPUT);*

  • }*
    }
    void loop(){
  • randomButton = random(0,7); // Randomly select a button*
  • testButton(buttonNames[randomButton]); // Run the testButton code*
  • delay(1000); // on the randomly selected program*
    }
    unsigned int testButton(char buttonName)
    {
  • lcd.print("Press Button "); // Print a textual command*
  • lcd.print(buttonName); // Print name of button*
  • lcd.print(", "); // Print a textual command*
  • timerLength = pulseIn(buttonPin[randomButton], HIGH); // Time untill the button is pressed*
  • while(checkButtonPress(buttonPin[randomButton])){*
  • // This will only be executed if the button has been pressed*
  • lcd.home();*
  • delay(50);*
  • lcd.print("That took,");*
  • calcTime();*
  • lcd.print(timeSec);*
  • lcd.setCursor(0,1);*
  • lcd.print(" Good! "); *
  • }*
    }
    bool checkButtonPress(int buttonCode)
    {
  • if(digitalRead(buttonCode) == 1) { // Check status of PIN (HIGH)*
  • return true; // If true return true*
  • }*
  • return false; // If false return false*
    }
    void calcTime() {
  • timeSec = (timerLength / 1000.0);*
    }[/quote]

I just played around with your code. Maybe something good came out of it...

[UNTESTED CODE]

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

#define TIMEOUT 1000 //press before a second has elapsed or it will pick another button

byte timeSec; // timerLength in seconds (decimal)

byte randomButton; // Variable to store randomly selected button

char buttonPins[] = { 9,10,11,12,13,14,15,16,17}; // Define button pin-numbers 14-17 is analog pins 0-3

char* buttonNames[] = {"X","Y","A","B","B1","B2","B3","B4"}; // Define button names

void setup(){
for(int i=0; i<8; i++){
pinMode(buttonPins*, INPUT);*

  • }*
    }
    void loop(){

  • randomButton = random(0,7); // Randomly select a button*

  • testButton(buttonNames[randomButton]); // Run the testButton code*

  • delay(1000); // on the randomly selected program*
    }
    unsigned int testButton(char* buttonName)
    {

  • lcd.print("Press Button "); // Print a textual command*

  • lcd.print(buttonName); // Print name of button*

  • lcd.print(", "); // Print a textual command*

  • timeSec = pulseIn( buttonPins[randomButton],HIGH , TIMEOUT ) / 1000000; // Time untill the button is pressed*

  • lcd.home();*

  • delay(10);*

  • lcd.print("That took,");*

  • lcd.print(timeSec);*

  • lcd.setCursor(0,1);*

  • lcd.print(" Good! "); *
    }
    [/quote]

Nice work AlphaBeta, I hope you get some credit for the OP's A level grade. :wink:

The sketch can be further simplified by removing the pinMode call in setup, pulseIn sets the pinMode implicitly.

BTW, perhaps timeout needs to be longer, I think it was supposed to be 3 seconds in the first sketch

Ok thanks for helping me so far! Simplified that operation, but now I have some more!

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);

#define TIMEOUT 3000 //press before a second has elapsed or it will pick another button
byte timeSec; // timerLength in seconds (decimal)
byte randomButton; // Variable to store randomly selected button
byte gamesNum = 5;
char buttonPins[] = {
9,10,11,12,13,14,15,16,17,18}; // Define button pin-numbers 14-17 is analog pins 0-3
char* buttonNames[] = {
"X","Y","A","B","B1","B2","B3","B4","BK","SRT"}; // Define button names

void setup(){
}

void loop(){
displayStart(); // Display the start menu
selectGames(); // Let the user select the amount of games
playGame(); // Start game loop up to all games
}

void playGame(){ // Loop through all the games
for(int i=0; i<gamesNum; i++){
randomButton = random(0,9);
testButton(randomButton);
}
}

void selectGames(){ // Allow the user to choose the number of games
lcd.clear();
delay(100);
lcd.print(" Games: ");
lcd.print(gamesNum);
lcd.setCursor(0,1);
lcd.print(" -X A+ ");
while(!checkButtonPress(buttonPins[2])){
while(checkButtonPress(buttonPins[3])){
gamesNum--;
}
while(checkButtonPress(buttonPins[8])){
break;
}
gamesNum++;
selectGames(); // Re-run loop to refresh number
}
}

void displayStart(){ // Show a welcome screen
lcd.clear(); // Clear screen and reset cursor
delay(100);
lcd.print(" Welcome! ");
lcd.setCursor(0,1);
lcd.print(" Made by Ben D ");
delay(5000);
lcd.clear();
delay(100);
lcd.print("Ready to start? ");
lcd.setCursor(0,1);
lcd.print(" ...press start!");
delay(500);
while(!checkButtonPress(buttonPins[8])){
} // Wait for a START button press
}

unsigned int testButton(byte buttonSelected) // Test for the right button input
{
lcd.print("Press Button "); // Print a textual command
lcd.print(buttonNames[buttonSelected]); // Print name of button
lcd.print(", "); // Print a textual command

timeSec = pulseIn(buttonPins[buttonSelected], HIGH, TIMEOUT)/1000000; // Time untill the button is pressed

lcd.home();
delay(10);
lcd.print("That took,");
lcd.print(timeSec);
lcd.setCursor(0,1);
lcd.print(" Good! ");
}

bool checkButtonPress(int buttonCode)
{
if(digitalRead(buttonCode) == 1) { // Check status of PIN (HIGH)
return true; // If true return true
}
return false; // If false return false
}

I hope I haven't commited anymore coding-faux pas!

Does it do what you want it to do?

while(checkButtonPress(buttonPins[3])){

gamesNum--;
  }

That looks a bit scary. If the check evaluates true, gamesNum will decrement extremely fast.

I think you should change the while to an if. [maybe]

Ah yes, I think an 'if' would be fine within the 'while' loop.

Thanks again AlphaBeta!

Because timeSec is a byte, does that mean that timeSec will be rounded to the nearest second?

If this is true, how can I use modulo to print the decimal after? Would I have to evaluate how the number was rounded and then decide to print the remainder after or take one second off and then add it?

timeSec is rounded down to the nearest second because pulseIn returns microseconds ant his value is divided by a million.

If you want the time in milliseconds, create a new variable timeMS

int timeMS;
timeMS = pulseIn(buttonPins[buttonSelected], HIGH, TIMEOUT)/1000;

If you want to the value as a floating point number, you can do this:

float timeSec = pulseIn(buttonPins[buttonSelected], HIGH, TIMEOUT)/1000000.0;

OK ill be going for the:

float timeSec = pulseIn(buttonPins[buttonSelected], HIGH, TIMEOUT)/1000000.0;

method.

The question I should have asked is will the LCD screen be able to print this number as a decimal? And if so to how many D.P. or S.F?

LiquidCrystal will print the value to two decimal places

Ah thankyou. This is just right for what I need.

I'll be posting details and a link to a blog on the project as it nears completion in the next two weeks if anyone is interested: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238020762