Function to cycle through an array for Alarm Clock

I'm trying to develop a weekly alarm clock using an RTC, LCD Keypad Shield, and an Arduino Uno. Right now the code works to set the time, set an alarm, and execute the alarm. Where I'm having issues is the last function which will allow me to cycle through the various days of the week and add the selected day of the week to the alarm parameters. I'm not sure if it's convention but I would like to say that this is not originally my code and was sampled from a public source code. I'm unfamiliar with using arrays in general and have been banging my head against the wall with this one for quite some time. This is a part of a group project for school and I just got handed this with a Monday deadline. Gotta love group projects. :0 Any help is greatly appreciated, thank you all in advance. And, oh by the way, I'm new here. Hello all :D :D

-Code will be posted in comments as length requires

Main Body

#include <Wire.h>  // Required by RTClib
#include <LiquidCrystal.h>  // Required by LCDKeypad
#include <LCDKeypad.h>
#include "RTClib.h"

#define TIME_OUT 5  // One of the system's FSM transitions
#define ALARM_TIME_MET 6  // One of the system's FSM transitions

#define ALARM_PIN 3  // Output PWM pin for the buzzer
#define SNOOZE 10  // Minutes to snooze

// The different states of the system
enum states
{
    SHOW_TIME,           // Displays the time and date
    SHOW_TIME_ALARM_ON,  // Displays the time and date, and alarm is on
    SHOW_ALARM_TIME,     // Displays the alarm time and goes back to time and date after 3 seconds
    SET_ALARM_HOUR,      // Option for setting the alarm hours. If provided, it moves on to alarm minutes.
                         //   Otherwise, it times out after 5 seconds and returns to time and date
    SET_ALARM_MINUTES,   // Option for setting the alarm minutes. If provided, it mooves on to alarm DOW.
                         //   Otherwise, it times out after 5 seconds and returns to time and date
    SET_ALARM_DOW,       // Option for setting the alarm doy of the week. If provided, it finally sets the alarm time and alarm.
                         //   Otherwise, it times out after 5 seconds and returns to time and date                     
    ALARM_ON            // Displays the time and date, and alarm is on (alarm time met)
};

// Creates an LCDKeypad instance
// It handles the LCD screen and buttons on the shield
LCDKeypad lcd;

// Creates an RTC_DS1307 instance
// It handles the DS1307 Real-Time Clock
RTC_DS1307 RTC;

states state;  // Holds the current state of the system
int8_t button;  // Holds the current button pressed
uint8_t alarmHours = 0, alarmMinutes = 0, alarmDow = 0;  // Holds the current alarm time
uint8_t tmpHours;
boolean alarm = false;  // Holds the current state of the alarm
unsigned long timeRef;
DateTime now;  // Holds the current date and time information


void setup()
{
    pinMode(ALARM_PIN, OUTPUT);  // Buzzer pin

    // Initializes the LCD and RTC instances
    lcd.begin(16, 2);
    Wire.begin();
    RTC.begin();

    state = SHOW_TIME;  // Initial state of the FSM
 
    //Uncomment this to set the current time on the RTC module
     RTC.adjust(DateTime(__DATE__, __TIME__));
}

// Has the main control of the FSM (1Hz refresh rate)
void loop()
{
    timeRef = millis();

    // Uses the current state to decide what to process
    switch (state)
    {
        case SHOW_TIME:
            showTime();
            break;
        case SHOW_TIME_ALARM_ON:
            showTime();
            checkAlarmTime();
            break;
        case SHOW_ALARM_TIME:
            showAlarmTime();
            break;
        case SET_ALARM_HOUR:
            setAlarmHours();
            if ( state != SET_ALARM_MINUTES ) break;
        case SET_ALARM_MINUTES:
            setAlarmMinutes();
            if ( state != SET_ALARM_DOW )
            break;
        case SET_ALARM_DOW:
            setAlarmDOW();
            break;    
        case ALARM_ON:
            showTime();
            break;
    }

    // Waits about 1 sec for events (button presses)
    // If a button is pressed, it blocks until the button is released
    // and then it performs the applicable state transition
    while ( (unsigned long)(millis() - timeRef) < 970 )
    {
        if ( (button = lcd.button()) != KEYPAD_NONE )
        {
            while ( lcd.button() != KEYPAD_NONE ) ;
            transition(button);
            break;
        }
    }
}

// Looks at the provided trigger (event) 
// and performs the appropriate state transition
// If necessary, sets secondary variables
void transition(uint8_t trigger)
{
    switch (state)
    {
        case SHOW_TIME:
            if ( trigger == KEYPAD_LEFT ) state = SHOW_ALARM_TIME;
            else if ( trigger == KEYPAD_RIGHT ) { alarm = true; state = SHOW_TIME_ALARM_ON; }
            else if ( trigger == KEYPAD_SELECT ) state = SET_ALARM_HOUR;
            break;
        case SHOW_TIME_ALARM_ON:
            if ( trigger == KEYPAD_LEFT ) state = SHOW_ALARM_TIME;
            else if ( trigger == KEYPAD_RIGHT ) { alarm = false; state = SHOW_TIME; }
            else if ( trigger == KEYPAD_SELECT ) state = SET_ALARM_HOUR;
            else if ( trigger == ALARM_TIME_MET ) { analogWrite(ALARM_PIN, 220); state = ALARM_ON; }
            break;
        case SHOW_ALARM_TIME:
            if ( trigger == TIME_OUT ) { if ( !alarm ) state = SHOW_TIME;
                                         else state = SHOW_TIME_ALARM_ON; }
            break;
        case SET_ALARM_HOUR:
            if ( trigger == KEYPAD_SELECT ) state = SET_ALARM_MINUTES;
            else if ( trigger == TIME_OUT ) { if ( !alarm ) state = SHOW_TIME;
                                              else state = SHOW_TIME_ALARM_ON; }
            break;
        case SET_ALARM_MINUTES:
            if ( trigger == KEYPAD_SELECT ) { alarm = true; state = SHOW_TIME_ALARM_ON; }
            else if ( trigger == TIME_OUT ) { if ( !alarm ) state = SHOW_TIME;
                                              else state = SHOW_TIME_ALARM_ON; }
            break;
        case ALARM_ON:
            if ( trigger == KEYPAD_UP || trigger == KEYPAD_DOWN ) { analogWrite(ALARM_PIN, 0); 
                                                                    snooze(); state = SHOW_TIME_ALARM_ON; }
            if ( trigger == KEYPAD_SELECT || trigger == KEYPAD_LEFT ) { analogWrite(ALARM_PIN, 0); 
                                                                       alarm = false; state = SHOW_TIME; }
            break;
    }
}

// Displays the current date and time, and also an alarm indication
// e.g. SAT 04 JAN 2014, 22:59:10  ALARM
void showTime()
{
    now = RTC.now();
    const char* dayName[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
    const char* monthName[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
    
    lcd.clear();
    lcd.print(String(dayName[now.dayOfWeek()]) + " " +
              (now.day() < 10 ? "0" : "") + now.day() + " " +
              monthName[now.month()-1] + " " + now.year());
    lcd.setCursor(0,1);
    lcd.print((now.hour() < 10 ? "0" : "") + String(now.hour()) + ":" +
              (now.minute() < 10 ? "0" : "") + now.minute() + ":" +
              (now.second() < 10 ? "0" : "") + now.second() + (alarm ? "  ALARM" : ""));
}

// Displays the current alarm time and transitions back to show 
// date and time after 2 sec (+ 1 sec delay from inside the loop function)
// e.g. Alarm Time HOUR: 08 MIN: 20
void showAlarmTime()
{
    lcd.clear();
    lcd.print("Alarm Time");
    lcd.setCursor(0,1);
    lcd.print(String("HOUR: ") + ( alarmHours < 9 ? "0" : "" ) + alarmHours + 
                   " MIN: " + ( alarmMinutes < 9 ? "0" : "" ) + alarmMinutes);
    delay(2000);
    transition(TIME_OUT);
}

// Checks if the alarm time has been met, 
// and if so initiates a state transition
void checkAlarmTime()
{
    if ( now.hour() == alarmHours && now.minute() == alarmMinutes ) transition(ALARM_TIME_MET);
}

// When the buzzer is ringing, by pressing the UP or DOWN buttons, 
// a SNOOZE (default is 10) minutes delay on the alarm time happens
void snooze()
{
    alarmMinutes += SNOOZE;
    if ( alarmMinutes > 59 )
    {
        alarmHours += alarmMinutes / 60;
        alarmMinutes = alarmMinutes % 60;
    }
}

Alarm Functions: (Where I think the root of the trouble is)

// The first of a 3 part process for setting the alarm time
// Receives the alarm time hour. If not provided within 5 sec,
// times out and returns to a previous (time and date) state
void setAlarmHours()
{
    unsigned long timeRef;
    boolean timeOut = true;
    
    lcd.clear();
    lcd.print("Alarm Time");

    tmpHours = 0;
    timeRef = millis();
    lcd.setCursor(0,1);
    lcd.print("Set hours:  0");
    
    while ( (unsigned long)(millis() - timeRef) < 5000 )
    {
        uint8_t button = lcd.button();

        if ( button == KEYPAD_UP )
        {
            tmpHours = tmpHours < 23 ? tmpHours + 1 : tmpHours;
            lcd.setCursor(11,1);
            lcd.print("  ");
            lcd.setCursor(11,1);
            if ( tmpHours < 10 ) lcd.print(" ");
            lcd.print(tmpHours);
            timeRef = millis();
        }
        else if ( button == KEYPAD_DOWN )
        {
            tmpHours = tmpHours > 0 ? tmpHours - 1 : tmpHours;
            lcd.setCursor(11,1);
            lcd.print("  ");
            lcd.setCursor(11,1);
            if ( tmpHours < 10 ) lcd.print(" ");
            lcd.print(tmpHours);
            timeRef = millis();
        }
        else if ( button == KEYPAD_SELECT )
        {
            while ( lcd.button() != KEYPAD_NONE ) ;
            timeOut = false;
            break;
        }
        delay(150);
    }

    if ( !timeOut ) transition(KEYPAD_SELECT);
    else transition(TIME_OUT);
}

// The second of a 2 part process for setting the alarm time
// Receives the alarm time minutes. If not provided within 5 sec,
// times out and returns to a previous (time and date) state
// If minutes are provided, sets the alarm time and turns the alarm on
void setAlarmMinutes()
{
    unsigned long timeRef;
    boolean timeOut = true;
    uint8_t tmpMinutes = 0;
    
    lcd.clear();
    lcd.print("Alarm Time");

    timeRef = millis();
    lcd.setCursor(0,1);
    lcd.print("Set minutes:  0");
    
    while ( (unsigned long)(millis() - timeRef) < 5000 )
    {
        uint8_t button = lcd.button();
        
        if ( button == KEYPAD_UP )
        {
            tmpMinutes = tmpMinutes < 59 ? tmpMinutes + 1 : tmpMinutes;
            lcd.setCursor(13,1);
            lcd.print("  ");
            lcd.setCursor(13,1);
            if ( tmpMinutes < 10 ) lcd.print(" ");
            lcd.print(tmpMinutes);
            timeRef = millis();
        }
        else if ( button == KEYPAD_DOWN )
        {
            tmpMinutes = tmpMinutes > 0 ? tmpMinutes - 1 : tmpMinutes;
            lcd.setCursor(13,1);
            lcd.print("  ");
            lcd.setCursor(13,1);
            if ( tmpMinutes < 10 ) lcd.print(" ");
            lcd.print(tmpMinutes);
            timeRef = millis();
        }
        else if ( button == KEYPAD_SELECT )
        {
            while ( lcd.button() != KEYPAD_NONE ) ;
            timeOut = false;
            break;
        }
        delay(150);
    }

    if ( !timeOut )
    {
        alarmHours = tmpHours;
        alarmMinutes = tmpMinutes;
        transition(KEYPAD_SELECT);
    }
    else transition(TIME_OUT);
}
void setAlarmDOW()
{
  unsigned long timeRef;
  char* alarmDayName[7] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
  boolean timeOut = true;
  uint8_t tmpDOW = 0;
  
  lcd.clear();
  lcd.print("Alarm Time");
  
  lcd.setCursor (0,1);
  lcd.print("Set Day:  SUN");
  
  while ( (unsigned long)(millis() - timeRef) < 5000  )
  {
     uint8_t button = lcd.button();
     
     if ( button == KEYPAD_UP )
     {
       tmpDOW = tmpDOW < 8 ? tmpDOW + 1 : tmpDOW;
       lcd.setCursor(15,1);
       lcd.print("  ");
       lcd.setCursor(15,1);
       lcd.print(tmpDOW);
        }
        else if ( button == KEYPAD_DOWN )
        {
            tmpDOW = tmpDOW > 0 ? tmpDOW + 1 : tmpDOW;
            lcd.setCursor(15,1);
            lcd.print("  ");
            lcd.setCursor(15,1);
            if ( tmpDOW < 8 ) lcd.print(" ");
            lcd.print(tmpDOW);
        }
        else if ( button == KEYPAD_SELECT )
        {
         while ( lcd.button() != KEYPAD_NONE ) ;
            timeOut = false;
            break;
        }
        delay(150);
  }

    if ( !timeOut )
    {
        alarmHours = tmpHours;
        alarmMinutes = tmpMinutes;
        alarmDOW = tmpDOW;
        transition(KEYPAD_SELECT);
    }
    else transition(TIME_OUT);
}

To save me spending a long time studying your code can you tell me what data is needed to record a single alarm?

I don't immediately see any reference to arrays or to several separate alarm settings in the code you posted - but maybe that has yet to be added.

...R

Hi Accidental_Apoptosis

It looks like the objective is for the alarm to activate only on one day of the week, which the user specifies. Is that correct?

If so, I can see a function that checks if it is time for the alarm to activate ...

void checkAlarmTime()
{
    if ( now.hour() == alarmHours && now.minute() == alarmMinutes ) transition(ALARM_TIME_MET);
}

There is already a function called setAlarmDOW() which, after interacting with the user, assigns a value to the global variable alarmDOW.

Does setAlarmDOW() get called? Does it work correctly? You could add some print statements to test this.

If it does work, try adding && now.dayOfWeek()==alarmDOW to the conditional test in checkAlarmTime().

Regards

Ray