Project tutorial
GymGeneral - A Sports Interval Timer

GymGeneral - A Sports Interval Timer © GPL3+

Easy setup via .txt file.

  • 2,293 views
  • 0 comments
  • 6 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
TTP223B capacitive touch switch
×2
Serial I2C LCD Backpack
×1
2*16 LCD display
×1
Piezo sounder
×1
Deek robot data logging shield v1.0
×1

Apps and online services

About this project

Interval training consists of timed bursts of exercise interspersed with timed rest periods. A variety of regimens have been created, probably the best known is Tabata[1] which consists of 20 seconds intense work followed by 10 seconds rest for a total of 8 repetitions – so 4 minutes total.

Using a stopwatch for intervals is somewhat error prone so a number of timers have appeared on the market to fill this niche.

The catch with the interval timers I have seen is that you are entering your intervals into a little box using only a few keys, a frustrating and error prone method.

My solution, store the interval data as a .txt file on an SD card where it can be easily edited using standard software e.g. Notepad, you then pop it into GymGeneral, select the file you want and run it.

Connections:

Data logging shield (SD card) attached to SPI bus as follows:

MOSI - pin 11

MISO - pin 12

CLK - pin 1

CS - pin 10

Touch sensors:

Power to positive and ground, signal wires to Arduino external interrupt pins 2 and 3.

LCD backpack:

Power to positive and ground, SDA to Arduino SDA and SCL to Arduino SCL.

Piezo sounder:

Positive to Arduino PWM pin 9, negative to ground.

Software description:

The software was an exercise in code reuse.

The display backpack uses the NewLiquidCrystal library and I also used the setup code from the same page [2] for my display, please note that my display is one of the weird ones that use address 0x3F most use 0x27 so if you don’t see anything locate and modify this number first.

I had not used an SD card with the Arduino so I played around with the Arduino ReadWrite tutorial [3] to work out how to read the data from the SD card.

My next step was to play around with the Arduino Listfiles tutorial [4] code to work out how to navigate through the files on an SD card.

I copied large blocks of code from the above examples into my project and made a few minor modifications of my own; I added code so that after the last filename is read we loop back to the first and altered the way the files are displayed.

The display routine is based along the lines of model, view controller. The idea of this is to decouple the display and controls form the body of the program. The downside is the use of global variables as a means of communication between the different blocks of code.

I used hardware PWM to generate the tones from a small piezo sounder element. The sounder is attached to pin 9, the frequency of the PWM output of this pin is controlled by timer 1, I chose this pin as I could alter the PWM frequency without affecting the delay() function which runs using timer 0 [5].

The delays are handled using Arduino delay() I think this is acceptable for accuracy in this context [6]. I accept that for long routines the timings will become increasingly skewed due to the file reads and the loop code, I have made no attempts to quantify this.

The data for the intervals in the text file is taken as blocks of 4 comma separated integer values [7].

The format of the data:

<Repeats>,<Tone>,<On time in tenth seconds>,<Off time in tenth seconds>,

Tone uses 1 for low frequency and 2 for the high frequency.

Example:

20,2,1,9, = 20 repeats of high frequency, on for 1 tenth second, off for 9 tenths second.

So for the Tabata regimen the text file will contain the following:

20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,10,1,1,9,20,2,1,9,

You may want to add a small delay at the start to allow yourself to get set; I normally give myself 15 seconds e.g. 15,1,1,9, .

I also tend to add a longer beep at the end to mark the completion of the workout e.g. 3,1,10,0, (a low tone of 3 seconds)

Operation:

Set up on or more interval files on the SD card.

Cycle down through the available files using the touch sensor attached to Arduino pin 2 until the name of the file you want is displayed.

The other touch sensor acts as the enter key, when it is pressed the intervals will start to play.

There is no stop function.

Notes:

The circuit layout shows a different SD card reader than the one I used and listed above.

On the name GymGeneral I did a UK Intellectual Property Office trademark search and USA trademark electronic search (TESS) and found nothing remotely similar. (7/Sept/2017)

In the context of my project I have taken interval training to be a synonym for high intensity interval training (HIIT) whereas in reality much longer regimens can also be categorized in this way e.g. the first week of Couch to 5K consists of 8*1 minute runs interspersed with 90 second rest periods [8].

References:

[1] https://en.wikipedia.org/wiki/High-intensity_interval_training#Tabata_regimen (retrieved 7/Sept/2017)

[2] https://arduino-info.wikispaces.com/LCD-Blue-I2C (retrieved 5/Sept/2017)

[3] https://www.arduino.cc/en/Tutorial/ReadWrite (retrieved 24/Aug/2017)

[4] https://www.arduino.cc/en/Tutorial/listfiles (retrieved 24/Aug/2017)

[5] https://playground.arduino.cc/Main/TimerPWMCheatsheet (retrieved 8/Sept/2017)

[6] https://forum.arduino.cc/index.php?topic=53579.0 Topic: Accuracy of Arduino delay() command (retrieved 5/Sept/2017)

[7] http://forum.arduino.cc/index.php?topic=277648.0 Topic: Reading SD card with CSV format into chars and ints (retrieved 8/Sept/2017)

[8] http://www.nhs.uk/Livewell/c25k/Pages/couch-to-5k-plan.aspx (retrieved 11/Sept/2017)

Code

GymGeneral codeC/C++
/*
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 10 -> for deek robot data shield v1.0
 */
#include <SPI.h>
#include <SD.h>

const int chipSelect=10;

//my_aliases
const int down_switch=3;
const int enter_switch=2;

const int start_screen=1;
const int initialization_screen=2;
const int file_menu_screen=3;
const int file_wont_open_screen=4;

//my_boolean variables
volatile bool count_updated=true;
volatile bool enter_pressed=false;
volatile bool beep_file_contents=false;
volatile bool do_update=true;

File root;
File myFile;

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here: 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>

// set the LCD address to 0x27 for a 16 chars 2 line display
// A FEW use address 0x3F ------------------------> like mine!
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//my_global_variables
int screen_number=start_screen;
bool initialization_fail=false;
bool file_exists=false;
static String my_filename="";

const int sounder_pin=9;// the pin we attach our sounder to
const int duty_cycle=128;//50% duty cycle for analogWrite()

void setup() {

//initial lcd setup
  lcd.begin(16,2);    // initialize the lcd for 16 chars 2 lines
  lcd.backlight();    //turn on backlight    
  lcd.clear();

  update_display();
  delay(5000);
  screen_number=initialization_screen;

//try to initialize sd card
  if (!SD.begin(chipSelect)) {
    initialization_fail=true;
    update_display();
    return;
  }
  initialization_fail=false;
  update_display();
  delay(5000);
  
//for switches
  pinMode(down_switch, INPUT);// sets the digital pin as input
  pinMode(enter_switch, INPUT);// sets the digital pin as input
  attachInterrupt(digitalPinToInterrupt(down_switch), enter_button, RISING);
  attachInterrupt(digitalPinToInterrupt(enter_switch), increment_down, RISING);

  // initialize digital pin as an output.
  pinMode(sounder_pin, OUTPUT);

}/*end of setup*/

void loop() {
  
  root = SD.open("/");

  int repeats=0;
  int frequency=0;
  int on_time=0;
  int off_time=0;
  int index=0;
 
while(1){

  if (do_update){do_update=false;update_display();}
  
  if (count_updated){


  //cycle through the existing files on the SD card
  count_updated=false;

  File entry =  root.openNextFile();
    if (! entry) {
      // no more files -> so go back to beginning
      entry.close();
      root.rewindDirectory();
      my_filename="No more";
      update_display();   
    }else
    {
    my_filename=entry.name(); 
    screen_number=file_menu_screen;
    update_display();
    entry.close();}                   
                    }

//beep out the intervals from the chosed file
if (beep_file_contents){
  
  beep_file_contents=false;

  if (SD.exists(my_filename)) {file_exists=true;}else{file_exists=false;}
  
  update_display();

  //read data from file
  // re-open the file for reading:
  myFile = SD.open(my_filename, FILE_READ);
  if (myFile) {

    // read from the file until there's nothing else in it:
    while (myFile.available()) 
    {
      repeats=myFile.parseInt();
      frequency=myFile.parseInt();
      on_time=myFile.parseInt();
      off_time=myFile.parseInt();

      for (index=0;index<repeats;index++)
      {
        if (frequency==1){TCCR1B = (TCCR1B & 0b11111000) | 0x04;}else{TCCR1B = (TCCR1B & 0b11111000) | 0x02;}
        analogWrite(sounder_pin, duty_cycle);
        delay(on_time*100);
        analogWrite(sounder_pin,0);
        delay(off_time*100);
        }     
    }

    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    screen_number=file_wont_open_screen;
    update_display();
  }

}//end beep out file
                    
}
  
}/*end of loop*/

//my_functions

//my_isr_functions
void enter_button(void)//enter button
{   switch(screen_number){case file_menu_screen:beep_file_contents=true;break;
                          case file_wont_open_screen:screen_number=file_menu_screen;do_update=true;break;}
}

void increment_down()//down button
{if (screen_number==file_menu_screen){count_updated=true;}}

//my_screen_functions
void update_display(void)
{
  switch (screen_number)
  {
    case start_screen:lcd.clear();
                      lcd.setCursor(3,0);
                      lcd.print("GymGeneral");
                      lcd.setCursor(3,1);
                      lcd.print("Gym timer");
                      break;    
    case initialization_screen:lcd.clear();
                               lcd.setCursor(0,0);
                               lcd.print("Init SD...");
                               if (!initialization_fail){lcd.print("done.");}else{lcd.print("fail!");}
                               break;
    case file_menu_screen:lcd.clear();
                          lcd.setCursor(2,0);
                          lcd.print("Select file");
                          lcd.setCursor(2,1);
                          lcd.print("            ");//clear any previous filename (8.3 character format, so 12 spaces)
                          lcd.setCursor(2,1);
                          lcd.print(my_filename);
                          break;                        
    case file_wont_open_screen:lcd.clear();
                               lcd.print("Can't open file");
                               break;          
    }
  }

Schematics

Diagram of connections
Gymgeneral layout tktfzma6rd

Comments

Similar projects you might like

Simple LCD Timer With Arduino UNO

Project showcase by Hugo Blanc

  • 7,688 views
  • 7 comments
  • 24 respects

Arduino Mutitasking: Clock + Stopwatch + Timer

Project tutorial by LAGSILVA

  • 6,865 views
  • 10 comments
  • 43 respects

More than an Hour Timer

Project tutorial by Ian Cumming

  • 2,824 views
  • 1 comment
  • 4 respects

Arduino Kitchen Timer

Project tutorial by Team I and myself

  • 54,448 views
  • 37 comments
  • 77 respects

Reaction Timer

Project tutorial by Arduino_Scuola

  • 2,454 views
  • 1 comment
  • 2 respects

Jigsaw Puzzle Timer

Project tutorial by HomeMadeGarbage

  • 1,639 views
  • 1 comment
  • 4 respects
Add projectSign up / Login