countdown can not be more then 3 minutes

Hi everybody,

thanks to this forum I have almost got the sketch exactly how I want it.

It is a countdown sketch used for working out.
You can choose 3, 4 or 5 minutes. After every workout 1 minute break

I'm only stuck on 1 point. If I put in the code for the 5 minutes workout 300 seconds then it count down from 44 seconds.

The 180 and 240 seconds, (3 and 4 minutes) works fine.
It is on line 73 where the 300 seconds are set.

#include <LiquidCrystal.h>
#include "ScrollableMenu.h"
#include "notes.h"

#define uchar unsigned char

/********* Main Program Defines **********/
/*****************************************/
#define TIMER_MODE_COUNTDOWN 1
#define TIMER_MODE_DISABLED 0

#define REGIME_MENU     1
#define REGIME_WORKOUT  0

#define MENUS_COUNT 3
#define WARNING_SIGNAL_LIMIT_SECONDS 10

#define MUSIC_WARN   1
#define MUSIC_SWITCH 2
#define MUSIC_END    3
/*****************************************/

/********** LCD Keypad Defines ***********/
/*****************************************/
#define KEYPAD_NONE -1
#define KEYPAD_RIGHT 0
#define KEYPAD_UP 1
#define KEYPAD_DOWN 2
#define KEYPAD_LEFT 3
#define KEYPAD_SELECT 4
/*****************************************/

/************** Classes ******************/
/*****************************************/

class LCDKeypad: public LiquidCrystal {
  public:
    LCDKeypad();
    int button();
};

/*****************************************/

class WorkoutInterval {
  public:
    char *name;
    uchar duration;
    
    WorkoutInterval(char *n, uchar d);
};

/*****************************************/

class Workout {
  public:
    char *name;
    uchar countOfIntrvals;
    uchar currentInterval;
    WorkoutInterval *intervals;
    uchar cycle;  //if == 0 - do not loop (end at intervals)
  
    Workout(char *n, uchar cnt, uchar c, WorkoutInterval *intvrls);
    void incCurrInterval();
    WorkoutInterval getCurrInterval();
};

/*****************************************/

WorkoutInterval restInterval = WorkoutInterval("Break",   60);
WorkoutInterval time3min       = WorkoutInterval("Training 3min", 180);
WorkoutInterval time4min       = WorkoutInterval("Training 4min", 240);
WorkoutInterval time5min       = WorkoutInterval("Training 5min", 300);



WorkoutInterval boxingIntervals1[] =        {restInterval, time3min};
WorkoutInterval boxingIntervals2[] =        {restInterval, time4min};
WorkoutInterval boxingIntervals3[] =        {restInterval, time5min};


Workout workouts[MENUS_COUNT] = {
  Workout("3m Golden Glory Gym", 2, 1, boxingIntervals1),
  Workout("4m Golden Glory Gym", 6, 1, boxingIntervals2),
  Workout("5m Golden Glory Gym", 8, 1, boxingIntervals3)
  
};
char currentWorkout = 0;

char timerMode = TIMER_MODE_DISABLED;
char regime = REGIME_MENU;
unsigned int seconds = 0;

LCDKeypad lcd;
ScrollableMenu scrollableMenu(2, MENUS_COUNT, drawMenu);

/************ Class' Methods *************/
/*****************************************/

LCDKeypad::LCDKeypad() : LiquidCrystal(8, 9, 4, 5, 6, 7){}

int LCDKeypad::button(){
  static int NUM_KEYS=5;
  static int adc_key_val[5] ={30, 150, 360, 535, 760};
  int k, input;
  input=analogRead(0);
  for (k = 0; k < NUM_KEYS; k++){
    if (input < adc_key_val[k]){
      return k;
    }
  }
  if (k >= NUM_KEYS){
    k = -1;     // No valid key pressed
  }
  return k;
}

/*****************************************/

Workout::Workout(char *n, uchar cnt, uchar c, WorkoutInterval *intvrls) {
  name = n;
  countOfIntrvals = cnt;
  intervals = intvrls;
  cycle = c;
  currentInterval = 0;
}

void Workout::incCurrInterval() {
  ++currentInterval;
  if(currentInterval >= countOfIntrvals){
    currentInterval = 0;
  }
}

WorkoutInterval Workout::getCurrInterval() {
  return intervals[currentInterval];
}

/*****************************************/

WorkoutInterval::WorkoutInterval(char *n, uchar d) {
  name = n;
  duration = d;
}

/*****************************************/

/************ Main Routines **************/
/*****************************************/

void drawMenu(int menuItem, int row, char isActive){
  clearRow(row); 
  lcd.setCursor(0, row);
  if(isActive) {
    lcd.print(">");
  } else {
    lcd.print(" ");
  }
  lcd.print(workouts[menuItem].name);
}

void showTime(){
  lcd.clear();
  unsigned int localSec = seconds;
  lcd.setCursor(0, 0);
  lcd.print(workouts[currentWorkout].name);
  if(workouts[currentWorkout].getCurrInterval().name != 0){
    lcd.print(" (");
    lcd.print(workouts[currentWorkout].getCurrInterval().name);
    lcd.print(")");
  }
  lcd.setCursor(0, 1);
  lcd.print((int)(localSec / 60));
  lcd.print(":");
  if(localSec % 60 < 10) {
    lcd.print("0");
  }
  lcd.print(localSec % 60);
}

void clearRow(int row) {
  lcd.setCursor(0, row);
  lcd.print("                ");
}

void sound(int type){
  switch(type) {
    case MUSIC_WARN:
      tone(3, NOTE_B4, 1000);
      break;
    case MUSIC_SWITCH:
      tone(3, NOTE_CS6, 3000);
      break;
    case MUSIC_END:
      tone(3, NOTE_GS3, 5000);
      break;
    
  }
}

void initTimer1(int seconds){
    // initialize timer1 
    noInterrupts();           // disable all interrupts
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;

    // Set timerVal to the correct value for our interrupt interval
    //16MHz / prescaller / wanted_frequency
    int timerVal = (F_CPU / 1024) * seconds;
    if(timerVal > 65535) {  //if more than maximum, than set to maximum
        timerVal = 65535;
    }
    
    OCR1A = timerVal;                       //compare register
    TCCR1B |= (1 << WGM12);                 // CTC moge
    TCCR1B |= (1 << CS12) | (1 << CS10);    // 65535 prescaler 
    TIMSK1 |= (1 << OCIE1A);                // enable timer compare interrupt
    interrupts();                           // enable all interrupts
}

ISR(TIMER1_COMPA_vect) {        // interrupt service routine 
    if(timerMode != TIMER_MODE_DISABLED){
        //countdown seconds
        if(seconds > 0){
          seconds--;
        } else {
          //disableTimer1Interrupts();
          int currInterval = workouts[currentWorkout].currentInterval;
          int soundToPlay = MUSIC_SWITCH;
          if(workouts[currentWorkout].cycle == 0 && workouts[currentWorkout].countOfIntrvals == currInterval + 1) {
            soundToPlay = MUSIC_END;
            timerMode = TIMER_MODE_DISABLED;
          } else {
            workouts[currentWorkout].incCurrInterval();
            seconds = workouts[currentWorkout].getCurrInterval().duration;
          }
          sound(soundToPlay);
          //enableTimer1Interrupts();
        }
        
        if(seconds == WARNING_SIGNAL_LIMIT_SECONDS){
          //sound warning
          //disableTimer1Interrupts();
          sound(MUSIC_WARN);
          //enableTimer1Interrupts();
        }
    }
    if(regime != REGIME_MENU) {
      showTime();
    }
}

/*void enableTimer1Interrupts() {
  noInterrupts();
  TIMSK1 |= (1 << OCIE1A);
  interrupts();
}

void disableTimer1Interrupts() {
  noInterrupts();
  TIMSK1 = 0;
  interrupts();
}*/

void setup() {
    lcd.begin(16, 2);
    scrollableMenu.draw();
    initTimer1(1);
}

void loop() {
   int key = KEYPAD_NONE, prevKey = KEYPAD_NONE;
   while(1) {
     key = lcd.button();
     if(key != KEYPAD_NONE && key != prevKey){
       if(regime == REGIME_WORKOUT) {
         regime = REGIME_MENU;
         scrollableMenu.draw();
       } else {
         switch(key) {
           case KEYPAD_UP:
              scrollableMenu.keyUp();
              scrollableMenu.draw();
              break;
          case KEYPAD_DOWN:
              scrollableMenu.keyDown();
              scrollableMenu.draw();
              break;
          case KEYPAD_LEFT:  //quit menu
              regime = REGIME_WORKOUT;
              showTime();
              break;
          case KEYPAD_RIGHT:
          case KEYPAD_SELECT:
              timerMode = TIMER_MODE_DISABLED;
              currentWorkout = scrollableMenu.getCurrent();
              workouts[currentWorkout].currentInterval = 0;
              seconds = workouts[currentWorkout].intervals[0].duration;
              regime = REGIME_WORKOUT;
              timerMode = TIMER_MODE_COUNTDOWN;
              showTime();
              break;
         }
       }
     }
     prevKey = key;
     delay(50);
   }
}

300 won't fit in an unsigned char. Duration should be an int:

    uchar duration;

wildbill:
300 won't fit in an unsigned char. Duration should be an int:

    uchar duration;

Thanks a lot Wildbill,

I'm very new with rduino and this sketch was not written by me but edited to work the way I need it.

Is it an easy fix?

Can you point me a direction what to read to get me to understand it?

As a filthy, dirty hack, you might try replacing this:

#define uchar unsigned char

with this:

#define uchar unsigned int

If it works, go back and change it to:

#define uint unsigned int

That will give you a gazzilion compile errors but a find and replace of uchar with uint will allow you to kill them off. Verify the changes, don't let your editor do it blindly.

Look at the data type section of Arduino Reference or any basic C tutorial

wildbill:
As a filthy, dirty hack, you might try replacing this:

You are the best :slight_smile:

it works perfect now.

Thanks a lot Wildbill