paulsb
Published © GPL3+

Rechargeable general/game turn timer with battery monitor

Rechargeable timer with battery level monitor. Countdown display and buzzer to signify time up/end of turn. Set duration stored in EPROM.

BeginnerFull instructions provided255
Rechargeable general/game turn timer with battery monitor

Things used in this project

Hardware components

Arduino Pro Mini 328 - 3.3V/8MHz
SparkFun Arduino Pro Mini 328 - 3.3V/8MHz
Any PRO Mini, Nano R3 or Uno R3 will work. I actually used a WayinTop 2pcs Pro Mini ATMEGA328P 3.3V 8MHz. https://www.amazon.co.uk/gp/product/B086ZN9M1J/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&psc=1.
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×3
Youmile LED Display Module TM1637
×1
Universal Passive Buzzer,
×1
TP4056 5V 1A TYPE C Micro USB Board Module for 18650 Lithium Battery Charging
×1
3.7V 1000mAh Lithium Rechargeable Battery
×1
1M ohm Resistor
×1
330K ohm Resistor
×1
Hook Up wire
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Breadboard

Schematic

Code

Rechargeable countdown timer

Arduino
// General and Game Countdown Timer
// After turning on, use the UP and DOWN buttons to
//    set the time in minutes and seconds for the time to track or 
//    time allowed for the turn, hold button for repeated time changes
// The set time will remain showing on the display
// Press start a short tone will sound, "go" will be displayed 
//    and the time will start counting down to 0
// When 0 is reached a longer tone will sound and "End" displayed 
//    for 5 seconds before resetting to the allocated time 
//    for the next players go.
// You can terminate the countdown at any time be pressing the 
//    start/stop button.

// Include the library driver for display:
#include <TM1637Display.h>
// Include the library for managing eprom
#include <EEPROM.h>

// Define the connections pins for display
#define CLK 6
#define DIO 7

// Define other pin connections
#define UP_BUTTON 2
#define DOWN_BUTTON 3
#define START_BUTTON 4              // Also the stop button
#define BUZZER 9
#define MONITOR_PIN A0              // Pin used to monitor supply voltage
const float voltageDivider = 4.0;   // Used to calculate the actual voltage from the monitor pin reading
                                    // Using 1m and 330k ohm resistors divides the voltage by approx 4
                                    // You may want to substitute actual values of resistors in an equation (R1 + R2)/R2
                                    // E.g. (1000 + 330)/330 = 4.03
                                    // Alternatively take the voltage reading across the battery and from the joint between 
                                    // the 2 resistors to ground and divide one by the other to get the value.

int epromFlagAddress = 1;           // Address used to store flag when duration saved - no relevance to address used
int durationAddress  = 10;          // Address where duration is stored - no relevance to address used
                                    // EPROM addresses run from 0 to 1,023 on the Pro Mini  
int duration;                       // Current duration in seconds
int storedDuration;                 // Last stored duration

// Create display object of type TM1637Display:
TM1637Display display = TM1637Display(CLK, DIO);

// Set the individual segments for the word displays:
const uint8_t seg_end[] = {
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,          // E
  SEG_C | SEG_E | SEG_G,                          // n 
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,          // d
  0x00                                            // All off
};

const uint8_t seg_go[] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,  // g
  SEG_A | SEG_B | SEG_G | SEG_F,                  // o top of digit
  0x00,                                           // All off
  0x00                                            // All off
};

// Full battery
const uint8_t seg_full[] = {
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G                           // 3 lines
};

// Three quatrters
const uint8_t seg_34[] = {
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  0x00                                            // All off
};

// Half
const uint8_t seg_half[] = {
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  0x00,                                           // All off
  0x00                                            // All off
};

// One quarter
const uint8_t seg_14[] = {
  SEG_A | SEG_D | SEG_G,                          // 3 lines
  0x00,                                           // All off
  0x00,                                           // All off
  0x00                                            // All off
};

// Low battery warning
const uint8_t seg_low[] = {
  SEG_D | SEG_E | SEG_F,                          // L
  SEG_C | SEG_D | SEG_E | SEG_G,                  // o bottom of segment
  0x00,                                           // All off
  0x00                                            // All off
};




void setup() {
  pinMode(UP_BUTTON, INPUT_PULLUP);               // Pullup set so defaults high
  pinMode(DOWN_BUTTON, INPUT_PULLUP);             // Goes low when button pressed
  pinMode(START_BUTTON, INPUT_PULLUP);            
  pinMode(BUZZER, OUTPUT);
  analogReference(INTERNAL);     // Sets the reference voltage for the analog pins to 1.1v
  pinMode(MONITOR_PIN, INPUT);   // Set input on pin used to monitor the voltage
  // Check to see if there is a saved duration. If so read it, if not set default
  if(EEPROM.read(epromFlagAddress) == 1){
    storedDuration = EEPROM.read(durationAddress);
    duration = storedDuration;
  }
  else {
    duration = 30;               // Default to 30 seconds
    storedDuration = duration;
    EEPROM.write(durationAddress, storedDuration);
    EEPROM.write(epromFlagAddress, 1);
  }
  display.setBrightness(3);      // 0 to 7 change if required
  CheckBattery();
  ShowTime(duration);
}

void loop() {
  // Function loops checking for time change buttons and only returns 
  // when start button pressed
  WaitForStart();
  // Start the duration timer - returns on completion
  TimeDuration();
}

// Check and display battery level
void CheckBattery(){
  float voltage = BatteryVoltage();
  display.clear();
  if (voltage > 3.85)  // Was 3.6
    display.setSegments(seg_full);
  else
    if (voltage > 3.69)  // Was 3.5
      display.setSegments(seg_34);
    else
      if (voltage > 3.59)  // Was 3.4
        display.setSegments(seg_half);
     else
        if (voltage > 3.5)  // Was 3.3 
          display.setSegments(seg_14);
        else
          display.setSegments(seg_low);
  // If voltage less than 3.4v then sound alarm
  if (voltage < 3.4){
    for (int i = 0; i < 3; i++){
      tone(BUZZER, 1500, 500);
      delay(750);
    }
  }
  else {
    delay(2250);
  }
}

// Read the monitor pin and calculate the voltage
float BatteryVoltage(){
  float reading = analogRead(MONITOR_PIN);
  // Calculate voltage - reference voltage is 1.1v
  return 1.1 * (reading/1023) * voltageDivider;
}

void WaitForStart(){
  // Check for button presses every 0.15 seconds
  while (digitalRead(START_BUTTON) == HIGH){
    // Check if up or down has been pressed
    // If time <= 60 seconds increment by 1 second
    // If time > 60 then increment by 10 seconds
    if (digitalRead(UP_BUTTON) == LOW){
      if (duration < 60){
        duration++;
       }
       else{
        duration += 10;
       }
      ShowTime(duration);
    }
    // If time <= 60 seconds increment by 1 second
    // If time > 60 then reduce by 10 seconds
    if (digitalRead(DOWN_BUTTON) == LOW){
      if (duration > 60){
        duration -= 10;
       }
       else{
        duration--;
       }
      ShowTime(duration);
    }
    delay(150);
  }
  // Start button has been pressed
  tone(BUZZER, 1500, 100);
  display.clear();
  display.setSegments(seg_go);
  // Check if duration = storedDuration and if not update stored duration
  if (storedDuration != duration) {
    storedDuration = duration;
    EEPROM.write(durationAddress, storedDuration);
  }
}

void TimeDuration(){
  // While loop will continue until time up
  //   or start/stop pressed
  unsigned long startTime = millis();
  unsigned long timer = 1000ul * duration;
  // Repeatedly check if time is up
  while ((millis() - startTime) <= timer){
    // Calculate time elapsed in seconds
    int elapsed = int((millis() - startTime)/1000);
    // Only start to display countdown after 3 seconds
    if ((millis() - startTime) > 3000){
      ShowTime(duration - elapsed);
      // Pressing the start button again will terminate early
      if (digitalRead(START_BUTTON) == LOW){
        break;
      }
    }
  }
  // Time up
  tone(BUZZER, 750, 250);
  display.clear();
  display.setSegments(seg_end);
  // Wait 5 seconds and reset display
  delay(5000);
  // Show duration for next player
  ShowTime(duration);
}

void ShowTime(int value){
  static int lastTime;
  // Update the display if time has changed
  if (lastTime != value) {
    lastTime = value;
    int iMinutes = value / 60;
    int iSeconds = value - (iMinutes * 60);
    // Show on 4 digit display
    uint16_t number = iMinutes * 100 + iSeconds;
    display.showNumberDecEx(number, 0b01000000, true, 4, 0);    
  }
}

Credits

paulsb

paulsb

4 projects • 28 followers

Comments