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);
}
}