Over the past couple of weeks, I have been experimenting with BQ3287, a real time clock module from Taxes Instruments. My ultimate goal was to eventually create a full fledged control platform based on this RTC module (more on this later). But first and foremost, I would like to explore its capabilities as an accurate time keeper.

The BQ3287 model by itself is really easy to interface with MCUs. There is a nice tutorial on how to use BQ3287 with Arduino and some of the code I am using in this post is borrowed from that project. The main difficulty of turning BQ3287 into a full-fledged clock is that this RTC module uses up to 16 digital pins out of 20 usable pins an ATMega328p has, which leaves very few pins for display and control purposes. After toying with a few possible designs, I decided to use 13 out of the 16 pins so that no major functionality is sacrificed (MOT is left disconnected using Intel bus timing, RESET is tied to Vcc and CS is connected to ground).

Digital pin 0 and 1 (chip pin 1 and 2) are used for button input. Since these two pins are also used as serial RX TX pair when used with the Arduino (the FT232RL chip communicates to The ATmega328 via these two pins) board, I resorted to the ICSP method to program the chip without using the Arduino board.

With this setup, we have two additional pins (pin 27 and 28, these are analog pin 4 and 5 on the Arduino board) available. Since these two pin s are the SCL and SDA pins in TWI (I2C) communication, I am planning to use them to communicate to another ATmega328 chip to further expand the functionality of this clock in the future.

For now, I am using the two buttons to multiplex the following functions:

  • Display Time
  • Display Date
  • Display Year
  • Stop Watch
  • Change Time Setting
  • Change Date Setting
  • Change Year Setting

Please see the comment in the code section below to see how these functionalities are achieved.

Three pins are used to control the 4 7 segment display I made earlier. The display update is triggered by the interrupt signal generated from the SQW output pin of BQ3287, I set the interrupt frequency to 128 Hz (RS3 RS2 RS1 RS0 = 1001) to ensure the accuracy of the stop watch (0.1 second) while still maintain a reasonable overhead. The update code all resides in the interrupt handler (intr()).

As you can see in the code, dot between the hour and minute display is turned on and off on a half second interval and in change settings mode the values to be changed also flashes at a half second interval.

Here are some pictures showing the clock displaying in various modes. And the last picture shows the board setup: the front board houses the 4 7 segment display, the left side is the ATmega328 board, the middle one contains the BQ3287 module and the right side board is the voltage regulator board. I used a Taxes Instrument TL720M05 LDO linear voltage regulator, which is a nice LDO pin compatible replacement of the good old 7805.

Time
Time
Date
Date
Year
Year
Day of the Week (Thursday)
Day of the Week (Thursday)
Stop Watch
Stop Watch
The Setup
The Setup

And here’s the code listing for this project. As mentioned earlier, I am planing to use a separate ATmega328 board to communicate with this clock using TWI so that I can setup timers/alarms to control other electronics.

//define the bidirectional address-data bus
const int ad0 = 3; //chip pin 5
const int ad1 = 4; //chip pin 6
const int ad2 = 5; //chip pin 11
const int ad3 = 6; //chip pin 12
const int ad4 = 7; //chip pin 13
const int ad5 = 8; //chip pin 14
const int ad6 = 9; //chip pin 15
const int ad7 = 10; //chip pin 16

//ALE or address strobe (AS pin)
const int as = 11; //chip pin 17
//WR or (RW pin)
const int rw = 12; //chip pin 18
//RD or OE (DS pin )
const int ds = 13; //chip pin 19
//interrupt request
const int irq = 14; //chip pin 23

//7-seg display pins
const int clockPin = 15; //chip pin 24
const int latchPin = 16; //chip pin 25
const int dataPin = 17; //chip pin 26

//control button pins
//Note, since these are the rx/tx pins when using FT232RL
//you will either have to program the chip using a programmer (the method I used)
//or using the remaining two two analog data pins (18 and 19). But then you are
//lossing two pins to work with.
const int btnPin1 = 0; //chip pin 1
const int btnPin2 = 1; //chip pin 2

const int COMMON_ANODE = 1; //1 CA, 0 CC

//bq3287 registers
const int regA = 0x0A;
const int regB = 0x0B;

//RO registers C,D
const int regC = 0x0C;
const int regD = 0x0D;

const int ADDR_CUR_SEC = 0;
const int ADDR_ALM_SEC = 1;
const int ADDR_CUR_MIN = 2;
const int ADDR_ALM_MIN = 3;
const int ADDR_CUR_HOUR = 4;
const int ADDR_ALM_HOUR = 5;
const int ADDR_CUR_DOW = 6;
const int ADDR_CUR_DAY = 7;
const int ADDR_CUR_MON = 8;
const int ADDR_CUR_YEAR = 9;

//display modes
//button 1 has 4 modes
const int DM_TIME = 0; //display time
const int DM_DATE = 1; //display date
const int DM_YEAR = 2; //display year
const int DM_DOW = 3; //display day of the week
const int DM_STOP_WATCH = 4; //display stop watch

//button 2 has 7 modes
const int DM_ADJ_NONE = 0; //display the current time
const int DM_ADJ_HOUR = 1; //adjust hour
const int DM_ADJ_MIN = 2; //adjust minute
const int DM_ADJ_MONTH = 3; //adjust month
const int DM_ADJ_DAY = 4; //adjust day
const int DM_ADJ_YEAR = 5; //adjust year
const int DM_ADJ_DOW = 6; //adjust day of the week

/** global variables for storing button's current mode.
 * Button functions
 * When button 2 is not pressed (in DM_ADJ_NONE)
 * press button 1 will cycle through the following display modes:
 *      current time (default)
 *      current date
 *      current year
 *      stop watch
 * when in stop watch mode, button 1 is used to start/stop/reset the stop watch.
 *
 * while in display current time mode (button 1 mode equals DM_TIME)
 * press button 2 will cycle through the following adjustment modes:
 *      adjust hour
 *      adjust minute
 *      adjust month
 *      adjust day
 *      adjust year
 *      adjust day of week
 * when in adjustment mode, button 1 is used to increment the settings.
 */
int btnMode1 = 0;
int btnMode2 = 0;

boolean btn1Pressed = false;
boolean btn2Pressed = false;

//stop watch initialization indicator, if this is set to true
//the stop watch is stopped and displays 0.0
boolean stopWatchInit = true;
boolean stopWatchStarted = false;

/** 7seg character mapping char <-> code */
struct CharMap {
    char c;
    byte v;
};

//the length of the character map, it must match
//the cmap[] array lengh below
const int cmap_len = 41;

//defines the 7seg display characters
struct CharMap cmap[] = {
    {' ', 0},
    {'1', 96},
    {'2', 218},
    {'3', 242},
    {'4', 102},
    {'5', 182},
    {'6', 190},
    {'7', 224},
    {'8', 254},
    {'9', 246},
    {'0', 252},
    {'A', 238},
    {'b', 62},
    {'c', 26},
    {'C', 156},
    {'d', 122},
    {'e', 222},
    {'E', 158},
    {'F', 142},
    {'g', 246},
    {'H', 110},
    {'h', 46},
    {'I', 96},
    {'J', 120},
    {'L', 28},
    {'n', 42},
    {'o', 58},
    {'P', 206},
    {'q', 230},
    {'r', 10},
    {'S', 182},
    {'t', 30},
    {'u', 56},
    {'U', 124},
    {'y', 118},
    {'-', 2},
    {'~', 128},
    {'_', 16},
    {'.', 1},
    {'|', 108},
    {'=', 144}
};

//indicates whether the led on 7seg indicating the "seconds" is on
boolean secondIndLEDOn = false;

//arrays for date/time conversion
char hour[2], minute[2], seconds[6];
char year[2], month[2], day[2], dow[1];

//the 4 characters on the 7seg
char c1, c2, c3, c4;

//this counter is incremented whenever the SW output pin
//triggers the interrupt
int interruptConter = 0;

//this counter is used to keep track of time in stop watch mode
unsigned int stopWatchCounter = 0;

/** same as delay() but works with interrupts */
void delayMilliseconds(int ms) {
    for (int i = 0; i < ms; i++) {
        delayMicroseconds(1000);
    }
}

/** get the display code for a character
/* it looks through the charactor map and find a match that corresponds to c
/* if no match is found, it returns 2 (corresponding to character '-') */
byte getCharDisplayCode(char c) {
    byte r = 2;

    for (int i = 0; i < cmap_len; i++) {
        if (c == cmap[i].c) {
            r = cmap[i].v;
            break;
        }
    }

    return r;
}

/** initialize the display
/* when the 7seg display is initialized, display nothing */
void init7seg() {
    pinMode(latchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(dataPin, OUTPUT);

    disp(' ', false, ' ', false, ' ', false, ' ', false);
}

/** this essentially is the library function shiftOut, it can be customized if
/* it is needed.
/* it works with 74HC595 (serial in, parallel out) */
void shiftOut(uint8_t dataPin, uint8_t clockPin, byte val) {
    int i;

    for (i = 0; i < 8; i++) {
        digitalWrite(dataPin, (val & _BV(i)));
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
    }
}

/* display the characters on the 7seg
/* the boolean value between characters indicates whether to light up the
/* decimal point */
void disp(char c1, boolean dot1, char c2, boolean dot2, char c3, boolean dot3, char c4, boolean dot4) {
    byte b1 = getCharDisplayCode(c1);
    byte b2 = getCharDisplayCode(c2);
    byte b3 = getCharDisplayCode(c3);
    byte b4 = getCharDisplayCode(c4);

    if (dot1 == true) b1 += 1;
    if (dot2 == true) b2 += 1;
    if (dot3 == true) b3 += 1;
    if (dot4 == true) b4 += 1;

    if (COMMON_ANODE == 1) {
        b1 = 255 - b1;
        b2 = 255 - b2;
        b3 = 255 - b3;
        b4 = 255 - b4;
    }

    digitalWrite(latchPin, LOW);

    shiftOut(dataPin, clockPin, b4);
    shiftOut(dataPin, clockPin, b3);
    shiftOut(dataPin, clockPin, b2);
    shiftOut(dataPin, clockPin, b1);

    digitalWrite(latchPin, HIGH);
}

/** convert a number (maximum 2 digita) to a character array
/* returning the length of the converted char array
/* this is used to convert hour/minutes into characters for display */
int convertToCharAarray(byte num, char *dest) {
    sprintf(dest, "%d", num);

    if (num < 10) return 1;
    else if (num < 100 && num >= 10) return 2;
    else return -1;
}

/** displays the current time on 7seg,
/* the display mode is controlled by the states of the button states */
void dispCurrentTime() {
    if (!bitRead(readbyte(regA), 7)) {
        byte h = readbyte(ADDR_CUR_HOUR);
        byte m = readbyte(ADDR_CUR_MIN);

        byte l1 = convertToCharAarray(h, hour);
        byte l2 = convertToCharAarray(m, minute);

        if (l1 == 1) {
            c2 = ' ';
            c1 = hour[0];
        } else {
            c1 = hour[1];
            c2 = hour[0];
        }

        if (l2 == 1) {
            c4 = '0';
            c3 = minute[0];
        } else {
            c3 = minute[1];
            c4 = minute[0];
        }
    }

    disp(c2, false, c1, secondIndLEDOn, c4, false, c3, false);

    switch (btnMode2) {
        case DM_ADJ_NONE: //normal display mode, displays time
            disp(c2, false, c1, secondIndLEDOn, c4, false, c3, false);
            break;
        case DM_ADJ_HOUR: //if adjust hour, flash the hour digits
            if (secondIndLEDOn)
                disp(' ', false, ' ', true, c4, false, c3, false);
            else
                disp(c2, false, c1, true, c4, false, c3, false);
            break;
        case DM_ADJ_MIN: //if adjust minutes, flash the minute digits
            if (secondIndLEDOn)
                disp(c2, false, c1, true, ' ', false, ' ', false);
            else
                disp(c2, false, c1, true, c4, false, c3, false);
            break;
    }
}

/** displays in stop watch mode. */
void dispStopWatch() {
    for (int i = 0; i < 5; i++) seconds[i] = ' ';

    int i = (int) (((float) (stopWatchCounter) / 128.0) * 10.0 + 0.5);
    sprintf(seconds, "%6d", i);

    if (stopWatchInit) {
        disp(' ', false, ' ', false, '0', true, '0', false);
    } else {
        if (stopWatchCounter < 128) { //less than 1 second, displays the leading 0
            disp(seconds[2], false, seconds[3], false, '0', true, seconds[5], false);
        } else {
            disp(seconds[2], false, seconds[3], false, seconds[4], true, seconds[5], false);
        }
    }
}

/** displays current date */
void dispCurrentDate() {
    if (!bitRead(readbyte(regA), 7)) {
        byte m = readbyte(ADDR_CUR_MON);
        byte d = readbyte(ADDR_CUR_DAY);

        byte l1 = convertToCharAarray(m, month);
        byte l2 = convertToCharAarray(d, day);

        if (l1 == 1) {
            c2 = ' ';
            c1 = month[0];
        } else {
            c1 = month[1];
            c2 = month[0];
        }

        if (l2 == 1) {
            c4 = '0';
            c3 = day[0];
        } else {
            c3 = day[1];
            c4 = day[0];
        }
    }

    switch (btnMode2) {
        case DM_ADJ_NONE: //normal display mode, displays date
            disp(c2, false, c1, true, c4, false, c3, false);
            break;
        case DM_ADJ_MONTH: //if adjust month, flash the month digits
            if (secondIndLEDOn)
                disp(' ', false, ' ', true, c4, false, c3, false);
            else
                disp(c2, false, c1, true, c4, false, c3, false);
            break;
        case DM_ADJ_DAY: //if adjust day, flash the day digits
            if (secondIndLEDOn)
                disp(c2, false, c1, true, ' ', false, ' ', false);
            else
                disp(c2, false, c1, true, c4, false, c3, false);
            break;
        default:
            break;
    }

}

/** displays the current year (e.g. 2010) */
void dispCurrentYear() {
    if (!bitRead(readbyte(regA), 7)) {
        byte y = readbyte(ADDR_CUR_YEAR);

        byte l1 = convertToCharAarray(y, year);

        c2 = '2';
        c1 = '0';

        if (l1 == 1) {
            c4 = '0';
            c3 = year[0];
        } else {
            c3 = year[1];
            c4 = year[0];
        }
    }

    switch (btnMode2) {
        case DM_ADJ_NONE:
            disp(c2, false, c1, false, c4, false, c3, false);
            break;
        case DM_ADJ_YEAR:
            if (secondIndLEDOn)
                disp(c2, false, c1, false, ' ', false, ' ', false);
            else
                disp(c2, false, c1, false, c4, false, c3, false);
            break;
        default:
            break;
    }

}

/** displays the day of the week (e.g. day1 for Monday) */
void dispDayOfWeek() {
    if (!bitRead(readbyte(regA), 7)) {
        byte d = readbyte(ADDR_CUR_DOW);

        convertToCharAarray(d, dow);
    }

    switch (btnMode2) {
        case DM_ADJ_NONE: //normal display mode
            disp('d', false, 'A', false, 'y', false, dow[0], false);
            break;
        case DM_ADJ_DOW: //if adjust day of the week, flash the digit
            if (secondIndLEDOn)
                disp('d', false, 'A', false, 'y', false, ' ', false);
            else
                disp('d', false, 'A', false, 'y', false, dow[0], false);
            break;
    }
}

/** set the clock bus mode
/* INPUT or OUTPUT */
void setClkBusMode(int mode) {
    pinMode(ad0, mode);
    pinMode(ad1, mode);
    pinMode(ad2, mode);
    pinMode(ad3, mode);
    pinMode(ad4, mode);
    pinMode(ad5, mode);
    pinMode(ad6, mode);
    pinMode(ad7, mode);
}

/** read a byte from address */
byte readbyte(byte address) {
    byte readb = 0;

    //set address pins to output
    setClkBusMode(OUTPUT);
    //start READ cycle
    digitalWrite(rw, HIGH);
    //prepare to set address on bus
    digitalWrite(ds, HIGH);
    //delayMicroseconds(1);
    //set ALE high, on fall address latches
    digitalWrite(as, HIGH);

    //set address on bus
    digitalWrite(ad0, bitRead(address, 0));
    digitalWrite(ad1, bitRead(address, 1));
    digitalWrite(ad2, bitRead(address, 2));
    digitalWrite(ad3, bitRead(address, 3));
    digitalWrite(ad4, bitRead(address, 4));
    digitalWrite(ad5, bitRead(address, 5));
    digitalWrite(ad6, bitRead(address, 6));
    digitalWrite(ad7, bitRead(address, 7));

    //set ALE low, latch address
    digitalWrite(as, LOW);
    setClkBusMode(INPUT);
    //finish address setting
    digitalWrite(ds, LOW);
    //wait for data from address
    //set bus for input
    //start reading data
    readb = digitalRead(ad0) | (digitalRead(ad1) << 1) | (digitalRead(ad2) << 2) | (digitalRead(ad3) << 3) | (digitalRead(ad4) << 4) | (digitalRead(ad5) << 5) | (digitalRead(ad6) << 6) | (digitalRead(ad7) << 7);
    digitalWrite(ds, HIGH);

    return readb;
}

/** write a byte to address */
void writebyte(byte address, byte value) {
    //set address pins to output
    setClkBusMode(OUTPUT);
    //start READ cycle
    digitalWrite(rw, HIGH);
    //prepare to set address on bus
    digitalWrite(ds, HIGH);
    //set ALE high, on fall address latches
    digitalWrite(as, HIGH);
    //set address on bus
    digitalWrite(ad0, bitRead(address, 0));
    digitalWrite(ad1, bitRead(address, 1));
    digitalWrite(ad2, bitRead(address, 2));
    digitalWrite(ad3, bitRead(address, 3));
    digitalWrite(ad4, bitRead(address, 4));
    digitalWrite(ad5, bitRead(address, 5));
    digitalWrite(ad6, bitRead(address, 6));
    digitalWrite(ad7, bitRead(address, 7));
    digitalWrite(as, LOW);
    digitalWrite(rw, LOW);
    //set byte to write
    digitalWrite(ad0, bitRead(value, 0));
    digitalWrite(ad1, bitRead(value, 1));
    digitalWrite(ad2, bitRead(value, 2));
    digitalWrite(ad3, bitRead(value, 3));
    digitalWrite(ad4, bitRead(value, 4));
    digitalWrite(ad5, bitRead(value, 5));
    digitalWrite(ad6, bitRead(value, 6));
    digitalWrite(ad7, bitRead(value, 7));
    digitalWrite(rw, HIGH);
}

/** adjust a register value by 1*/
boolean adjust(byte address) {
    //read current value
    byte value = 0;
    byte b;
    if ((address < 0) || (address > 10)) return false;
    if (!bitRead(readbyte(regA), 7)) value = readbyte(address);
    b = readbyte(regB);
    //set SET bit of register B that will prevent double buffer update from internal buffer
    b = b | 0x80;
    writebyte(regB, b);

    if (bitRead(readbyte(regB), 7)) {
        switch (address) {
            case ADDR_CUR_SEC://seconds
                writebyte(address, 0); //reset
                break;
            case ADDR_ALM_SEC://seconds alarm
                writebyte(address, 0); //reset
                break;
            case ADDR_CUR_MIN://minutes
                if (value >= 59) {
                    writebyte(address, 0);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_ALM_MIN://minutes alarm
                if (value >= 59) {
                    writebyte(address, 0);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_CUR_HOUR://hours
                if (value >= 23) {
                    writebyte(address, 0);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_ALM_HOUR://hours alarm
                if (value >= 23) {
                    writebyte(address, 0);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_CUR_DOW://day of week
                if (value >= 7) {
                    writebyte(address, 1);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_CUR_DAY:
                if (value >= 31) {
                    writebyte(address, 1);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_CUR_MON://month
                if (value >= 12) {
                    writebyte(address, 1);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
            case ADDR_CUR_YEAR://year
                if (value == 99) {
                    writebyte(address, 0);
                } else {
                    value++;
                    writebyte(address, value);
                }
                break;
        }
    }

    //mask regA and clear SET bit
    b = b & 0x7F;
    writebyte(regB, b);
    return true;
}

/** interrupt handler routine */
void intr() {
    interruptConter++;

    if (stopWatchStarted) {
        stopWatchCounter++;
    }

    switch (btnMode1) {
        case DM_TIME:
            switch (btnMode2) {
                case DM_ADJ_NONE:
                    dispCurrentTime();
                    break;
                case DM_ADJ_HOUR:
                    dispCurrentTime();
                    break;
                case DM_ADJ_MIN:
                    dispCurrentTime();
                    break;
                case DM_ADJ_MONTH:
                    dispCurrentDate();
                    break;
                case DM_ADJ_DAY:
                    dispCurrentDate();
                    break;
                case DM_ADJ_YEAR:
                    dispCurrentYear();
                    break;
                case DM_ADJ_DOW:
                    dispDayOfWeek();
                    break;
            }
            break;
        case DM_DATE:
            dispCurrentDate();
            break;
        case DM_YEAR:
            dispCurrentYear();
            break;
        case DM_DOW:
            dispDayOfWeek();
            break;
        case DM_STOP_WATCH:
            dispStopWatch();
            break;
        default:
            break;
    }

    //flashes the second indicator (the dot) every half second
    if (interruptConter > 63) {
        interruptConter = 0;
        secondIndLEDOn = !secondIndLEDOn;
    }
}

/*********************
 * Arduino routines
 *********************/
void setup() {
    init7seg();
    pinMode(btnPin1, INPUT);
    pinMode(btnPin2, INPUT);
    digitalWrite(btnPin1, HIGH);
    digitalWrite(btnPin2, HIGH);

    pinMode(as, OUTPUT);
    pinMode(ds, OUTPUT);
    pinMode(rw, OUTPUT);

    //delay after power up to start-up
    digitalWrite(as, LOW);
    digitalWrite(ds, LOW);
    digitalWrite(rw, LOW);
    delayMicroseconds(200);

    // RS3 RS2 RS1 RS0 = 1001 set SQW output frequency to 128 Hz
    byte a = 41; 
    writebyte(regA, a);

    byte b = readbyte(regB);
    b = b | 0xF;
    writebyte(regB, b);

    attachInterrupt(0, intr, RISING);
    c1 = ' ';
    c2 = ' ';
    c3 = ' ';
    c4 = ' ';
}

void loop() {
    if (digitalRead(btnPin1) == LOW && !btn1Pressed) {//debouncing btn1
        delayMilliseconds(20);
        if (digitalRead(btnPin1) == LOW) { 
            switch (btnMode2) {
                case DM_ADJ_NONE:
                    btnMode1 = (btnMode1 + 1) % 5;
                    break;
                case DM_ADJ_HOUR:
                    adjust(ADDR_CUR_HOUR);
                    break;
                case DM_ADJ_MIN:
                    adjust(ADDR_CUR_MIN);
                    break;
                case DM_ADJ_MONTH:
                    adjust(ADDR_CUR_MON);
                    break;
                case DM_ADJ_DAY:
                    adjust(ADDR_CUR_DAY);
                    break;
                case DM_ADJ_YEAR:
                    adjust(ADDR_CUR_YEAR);
                    break;
                case DM_ADJ_DOW:
                    adjust(ADDR_CUR_DOW);
                    break;
                default:
                    break;
            }

            btn1Pressed = true;
        }
    }

    if (digitalRead(btnPin1) == HIGH) {
        delayMilliseconds(20);

        if (digitalRead(btnPin1) == HIGH) {
            btn1Pressed = false;
        }
    }

    if (digitalRead(btnPin2) == LOW && !btn2Pressed) {
        delayMilliseconds(20);

        if (digitalRead(btnPin2) == LOW) {//debouncing btn2
            if (btnMode1 == DM_TIME) {
                btnMode2 = (btnMode2 + 1) % 7;
            }

            if (btnMode1 == DM_STOP_WATCH && !stopWatchStarted && stopWatchInit) {
                stopWatchInit = false;
                stopWatchStarted = true;
            } else if (btnMode1 == DM_STOP_WATCH && stopWatchStarted && !stopWatchInit) {
                stopWatchStarted = false;
            } else if (btnMode1 == DM_STOP_WATCH && !stopWatchStarted && !stopWatchInit) {
                stopWatchInit = true;
                stopWatchCounter = 0;
            }

            btn2Pressed = true;
        }
    }

    if (digitalRead(btnPin2) == HIGH) {//debouncing btn2
        delayMilliseconds(20);              
        if (digitalRead(btnPin2) == HIGH) { 
            btn2Pressed = false;
        }
    }
}
Be Sociable, Share!