Skip to content

Commit 2eb1581

Browse files
authored
arduino alarm clock added
1 parent d9c82e9 commit 2eb1581

File tree

12 files changed

+826
-0
lines changed

12 files changed

+826
-0
lines changed

alarm-clock/AlarmTone.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <Arduino.h>
2+
#include "AlarmTone.h"
3+
4+
#define TONE_TIME 500 /* ms */
5+
#define TONE_SPACING 100 /* ms */
6+
7+
static const uint16_t TONES[] = {
8+
500,
9+
800,
10+
};
11+
const uint16_t NUM_TONES = sizeof(TONES) / sizeof(TONES[0]);
12+
13+
AlarmTone::AlarmTone()
14+
: _playing(false)
15+
, _tone_index(0)
16+
, _last_tone_time(0) {
17+
}
18+
19+
void AlarmTone::begin(uint8_t pin) {
20+
_pin = pin;
21+
pinMode(_pin, OUTPUT);
22+
}
23+
24+
void AlarmTone::play() {
25+
if (!_playing || _last_tone_time + TONE_TIME + TONE_SPACING < millis()) {
26+
tone(_pin, TONES[_tone_index], TONE_TIME);
27+
_tone_index = (_tone_index + 1) % NUM_TONES;
28+
_last_tone_time = millis();
29+
}
30+
_playing = true;
31+
}
32+
33+
void AlarmTone::stop() {
34+
noTone(_pin);
35+
_tone_index = 0;
36+
_playing = false;
37+
}

alarm-clock/AlarmTone.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef __ALARM_TONE_H__
2+
#define __ALARM_TONE_H__
3+
4+
class AlarmTone {
5+
public:
6+
AlarmTone();
7+
void begin(uint8_t pin);
8+
void play();
9+
void stop();
10+
11+
private:
12+
uint8_t _pin;
13+
bool _playing;
14+
uint8_t _tone_index;
15+
unsigned long _last_tone_time;
16+
};
17+
18+
#endif /* __ALARM_TONE_H */

alarm-clock/Button.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
Button - a small library for Arduino to handle button debouncing
3+
4+
MIT licensed.
5+
*/
6+
7+
#include "Button.h"
8+
#include <Arduino.h>
9+
10+
Button::Button(uint8_t pin, uint16_t debounce_ms)
11+
: _pin(pin)
12+
, _delay(debounce_ms)
13+
, _state(HIGH)
14+
, _ignore_until(0)
15+
, _has_changed(false)
16+
, _reported_repeats(0)
17+
, _repeat_delay_ms(-1)
18+
, _repeat_ms(-1)
19+
{
20+
}
21+
22+
void Button::begin()
23+
{
24+
pinMode(_pin, INPUT_PULLUP);
25+
}
26+
27+
//
28+
// public methods
29+
//
30+
31+
bool Button::read()
32+
{
33+
// ignore pin changes until after this delay time
34+
if (_ignore_until > millis())
35+
{
36+
// ignore any changes during this period
37+
}
38+
39+
// pin has changed
40+
else if (digitalRead(_pin) != _state)
41+
{
42+
_state = !_state;
43+
44+
if (_state == RELEASED)
45+
{
46+
_reported_repeats = repeats_since_press();
47+
}
48+
49+
else
50+
{
51+
_reported_repeats = 0;
52+
}
53+
54+
_ignore_until = millis() + _delay;
55+
_has_changed = true;
56+
}
57+
58+
return _state;
59+
}
60+
61+
// has the button been toggled from on -> off, or vice versa
62+
bool Button::toggled()
63+
{
64+
read();
65+
return has_changed();
66+
}
67+
68+
// mostly internal, tells you if a button has changed after calling the read() function
69+
bool Button::has_changed()
70+
{
71+
if (_has_changed)
72+
{
73+
_has_changed = false;
74+
return true;
75+
}
76+
return false;
77+
}
78+
79+
// how many repeated press events occured since the button was pressed
80+
uint16_t Button::repeat_count()
81+
{
82+
return _state == PRESSED ? repeats_since_press() : _reported_repeats;
83+
}
84+
85+
// has the button gone from off -> on or pressed repeatedly
86+
bool Button::pressed()
87+
{
88+
if (read() == PRESSED)
89+
{
90+
uint16_t old_repeats = _reported_repeats;
91+
_reported_repeats = repeats_since_press();
92+
return (has_changed() || old_repeats != _reported_repeats);
93+
}
94+
else
95+
{
96+
return false;
97+
}
98+
}
99+
100+
// has the button gone from on -> off
101+
bool Button::released()
102+
{
103+
return (read() == RELEASED && has_changed());
104+
}
105+
106+
void Button::set_repeat(int16_t delay_ms, int16_t repeat_ms)
107+
{
108+
_repeat_delay_ms = delay_ms > _delay ? delay_ms - _delay : 0;
109+
_repeat_ms = repeat_ms;
110+
}
111+
112+
uint16_t Button::repeats_since_press()
113+
{
114+
if (_repeat_delay_ms == -1 || millis() < _ignore_until + _repeat_delay_ms)
115+
{
116+
return 0;
117+
}
118+
119+
if (_repeat_ms <= 0)
120+
{
121+
return 1;
122+
}
123+
124+
uint32_t press_time = millis() - _ignore_until;
125+
return 1 + (press_time - _repeat_delay_ms) / _repeat_ms;
126+
}

alarm-clock/Button.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
Button - a small library for Arduino to handle button debouncing
3+
4+
MIT licensed.
5+
*/
6+
7+
#ifndef Button_h
8+
#define Button_h
9+
#include "Arduino.h"
10+
11+
class Button
12+
{
13+
public:
14+
Button(uint8_t pin, uint16_t debounce_ms = 100);
15+
void begin();
16+
bool read();
17+
bool toggled();
18+
bool pressed();
19+
bool released();
20+
bool has_changed();
21+
uint16_t repeat_count();
22+
void set_repeat(int16_t delay_ms, int16_t repeat_ms);
23+
24+
const static bool PRESSED = LOW;
25+
const static bool RELEASED = HIGH;
26+
27+
private:
28+
uint16_t repeats_since_press();
29+
30+
uint8_t _pin;
31+
uint16_t _delay;
32+
bool _state;
33+
uint32_t _ignore_until;
34+
bool _has_changed;
35+
uint16_t _reported_repeats;
36+
int16_t _repeat_delay_ms;
37+
int16_t _repeat_ms;
38+
};
39+
40+
#endif

alarm-clock/Clock.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include <Arduino.h>
2+
#include "Clock.h"
3+
4+
#define MINUTE 60 * 1000L /* ms */
5+
#define TIMESPAN_DAY TimeSpan(1, 0, 0, 0)
6+
7+
#define NVRAM_ADDR_ALARM_ENABLED 0
8+
#define NVRAM_ADDR_ALARM_HOUR 1
9+
#define NVRAM_ADDR_ALARM_MINUTE 2
10+
11+
12+
Clock::Clock()
13+
: _alarm_state(ALARM_OFF)
14+
, _alarm_snooze_time(0)
15+
, _alarm_hour(DEFAULT_ALARM_HOUR)
16+
, _alarm_minute(0) {
17+
}
18+
19+
void Clock::begin() {
20+
# if USE_RTC
21+
if (!_rtc.begin()) {
22+
Serial.println("Couldn't find RTC");
23+
abort();
24+
}
25+
_alarm_state = _rtc.readnvram(NVRAM_ADDR_ALARM_ENABLED) ? ALARM_OFF : ALARM_DISABLED;
26+
_alarm_hour = _rtc.readnvram(NVRAM_ADDR_ALARM_HOUR) % 24;
27+
_alarm_minute = _rtc.readnvram(NVRAM_ADDR_ALARM_MINUTE) % 60;
28+
# else /* USE_RTC */
29+
DateTime zeroTime;
30+
_rtc.begin(zeroTime);
31+
# endif
32+
}
33+
34+
/***** Clock management *****/
35+
36+
DateTime Clock::now() {
37+
return _rtc.now();
38+
}
39+
40+
void Clock::incrementMinute() {
41+
DateTime now = _rtc.now();
42+
DateTime newTime = DateTime(now.year(), now.month(), now.day(), now.hour(),
43+
(now.minute() + 1) % 60);
44+
_rtc.adjust(newTime);
45+
}
46+
47+
void Clock::incrementHour() {
48+
DateTime now = _rtc.now();
49+
DateTime newTime = DateTime(now.year(), now.month(), now.day(),
50+
(now.hour() + 1) % 24, now.minute());
51+
_rtc.adjust(newTime);
52+
}
53+
54+
/***** Alarm management *****/
55+
bool Clock::_isAlarmDueTime() {
56+
auto currentTime = now();
57+
auto alarm = alarmTime();
58+
return ((currentTime.hour() == alarm.hour())
59+
&& (currentTime.minute() == alarm.minute()));
60+
}
61+
62+
bool Clock::alarmEnabled() {
63+
return _alarm_state != ALARM_DISABLED;
64+
}
65+
66+
bool Clock::alarmActive() {
67+
switch (_alarm_state) {
68+
case ALARM_DISABLED:
69+
return false;
70+
71+
case ALARM_OFF:
72+
if (_isAlarmDueTime()) {
73+
_alarm_state = ALARM_ACTIVE;
74+
return true;
75+
}
76+
return false;
77+
78+
case ALARM_ACTIVE:
79+
return true;
80+
81+
case ALARM_SNOOZED:
82+
if (millis() >= _alarm_snooze_time) {
83+
_alarm_state = ALARM_ACTIVE;
84+
return true;
85+
}
86+
return false;
87+
88+
case ALARM_STOPPED:
89+
if (!_isAlarmDueTime()) {
90+
_alarm_state = ALARM_OFF;
91+
}
92+
return false;
93+
94+
default:
95+
return false;
96+
}
97+
}
98+
99+
100+
void Clock::toggleAlarm() {
101+
bool enabled = !alarmEnabled();
102+
_alarm_state = enabled ? ALARM_OFF : ALARM_DISABLED;
103+
_rtc.writenvram(NVRAM_ADDR_ALARM_ENABLED, enabled);
104+
}
105+
106+
DateTime Clock::alarmTime() {
107+
DateTime now = _rtc.now();
108+
DateTime alarm = DateTime(now.year(), now.month(), now.day(), _alarm_hour, _alarm_minute);
109+
return alarm >= now ? alarm : alarm + TIMESPAN_DAY;
110+
}
111+
112+
void Clock::snooze() {
113+
_alarm_state = ALARM_SNOOZED;
114+
_alarm_snooze_time = millis() + SNOOZE_TIME * MINUTE;
115+
}
116+
117+
void Clock::stopAlarm() {
118+
_alarm_state = ALARM_STOPPED;
119+
}
120+
121+
void Clock::incrementAlarmHour() {
122+
_alarm_hour = (_alarm_hour + 1) % 24;
123+
_alarm_state = ALARM_OFF;
124+
_rtc.writenvram(NVRAM_ADDR_ALARM_HOUR, _alarm_hour);
125+
}
126+
127+
void Clock::incrementAlarmMinute() {
128+
_alarm_minute = (_alarm_minute + 1) % 60;
129+
_alarm_state = ALARM_OFF;
130+
_rtc.writenvram(NVRAM_ADDR_ALARM_MINUTE, _alarm_minute);
131+
}

0 commit comments

Comments
 (0)