Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Maple_alarm_clock.cpp
- Committer:
- uehara00
- Date:
- 2011-10-16
- Revision:
- 2:299a1c9a5795
- Parent:
- 1:aefa1992ce0f
- Child:
- 3:eec13a411e94
File content as of revision 2:299a1c9a5795:
//copyright 2011 Uehara Yoshiyuki
//====================================================================
//The author provide the programs without any guarantees or warranty.
//The author is not responsible for any damage or losses of any kind
//caused by using or misusing of the programs.
//The author is under no obligation to provide support, service,
//corrections, or upgrades to the programs.
//====================================================================
// MAPLE board[MARM01-BASE]
// alarm clock
#include "Maple_alarm_clock.h"
#include "Maple_RTC.h"
#include "Maple_I2C.h"
#include "Maple_LCD.h"
#include "Maple.h"
#include "mbed.h"
// timer interrupt to refresh display
Ticker alarm_clock_refresh_tick;
// global variables
int alarm_clock_mode;
int alarm_clock_cursor;
int button_count[6];
int button_status[6];
// alarm_clock_initialize
void alarm_clock_initialize() {
alarm_clock_refresh_tick.attach(&alarm_clock_refresh, ALARM_CLOCK_REFRESH_RATE);
alarm_clock_mode = MODE_NORMAL;
alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
for (int i = 0; i < 6; ++i) {
button_count[i] = 0;
button_status[i] = BUTTON_IDLE;
}
}
// refresh display, called by a ticker
void alarm_clock_refresh() {
alarm_clock_refresh_display();
button_check();
}
// read RTC and print to LCD
static void alarm_clock_refresh_display() {
const int cursor_row[4][10] = {
{ 1, 1, 16, 16, 16, 16, 16, 16, 16, 16}, // MODE_NORMAL
{ 0, 0, 0, 0, 1, 1, 1, 16, 16, 16}, // MODE_ADJUST
{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, // MODE_ALARM
{ 0, 0, 0, 0, 0, 0, 0, 1, 16, 16}, // MODE_TIMER
};
const int cursor_column[4][10] = {
{12, 15, 16, 16, 16, 16, 16, 16, 16, 16}, // NODE_NORMAL
{ 1, 3, 6, 9, 1, 4, 7, 16, 16, 16}, // MODE_ADJUST
{ 4, 6, 8, 11, 14, 15, 0, 2, 4, 6}, // MODE_ALARM
{ 3, 8, 11, 12, 13, 14, 15, 6, 16, 16}, // MODE_TIMER
};
const char frequency_select[4][6] = { "32768", " 1024", " 32", " 1" };
const char timer_select[4][5] = { "4096", " 64", " 1", "1/60" };
char row0[17], row1[17], d[17], s[4];
i2c_RTC_read(RTC_REG_CONTROL1, d, 16);
switch(alarm_clock_mode) {
case MODE_NORMAL:
copy_string(row0, 0, 17, "XXXX.XX.XX XXX ");
copy_string(row1, 0, 17, "XX:XX:XX XXXXXXX");
if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) { // when RTC registers are valid:
copy_string(row0, 0, 2, "20");
if((d[RTC_REG_MONTH_CENTURY ] & RTC_CENTURY ) != 0) { row0[ 1] = '1'; }
copy_string(row0, 2, 2, int_to_hex2(d[RTC_REG_YEAR ] , s));
copy_string(row0, 5, 2, int_to_hex2(d[RTC_REG_MONTH_CENTURY] & 0x1f, s));
copy_string(row0, 8, 2, int_to_hex2(d[RTC_REG_DAY ] & 0x3f, s));
copy_string(row0, 11, 3, weekday_to_string(d[RTC_REG_WEEKDAY] & 0x07, s));
copy_string(row1, 0, 2, int_to_hex2(d[RTC_REG_HOUR ] & 0x3f, s));
copy_string(row1, 3, 2, int_to_hex2(d[RTC_REG_MINUTE ] & 0x7f, s));
copy_string(row1, 6, 2, int_to_hex2(d[RTC_REG_SECOND ] & 0x7f, s));
copy_string(row1, 9, 7, "-------");
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_PERIODIC ) != 0) { row1[ 9] = 'p'; }
if((d[RTC_REG_TIMER_CONTROL ] & RTC_TIMER_ENABLE ) != 0) { row1[10] = 't'; }
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_INTERRUPT_ENABLE) != 0) { row1[11] = 'i'; }
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_FLAG ) != 0) { row1[12] = 'T'; }
if((d[RTC_REG_ALARM_MINUTE ] & RTC_ALARM_DISABLE ) == 0) { row1[13] = 'a'; }
if((d[RTC_REG_ALARM_HOUR ] & RTC_ALARM_DISABLE ) == 0) { row1[13] = 'a'; }
if((d[RTC_REG_ALARM_DAY ] & RTC_ALARM_DISABLE ) == 0) { row1[13] = 'a'; }
if((d[RTC_REG_ALARM_WEEKDAY ] & RTC_ALARM_DISABLE ) == 0) { row1[13] = 'a'; }
if((d[RTC_REG_CONTROL2 ] & RTC_ALARM_INTERRUPT_ENABLE) != 0) { row1[14] = 'i'; }
if((d[RTC_REG_CONTROL2 ] & RTC_ALARM_FLAG ) != 0) { row1[15] = 'A'; }
}
break;
case MODE_ADJUST:
copy_string(row0, 0, 17, "XXXX.XX.XX XXX ");
copy_string(row1, 0, 17, "XX:XX:XX adjust");
if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) { // when RTC registers are valid:
copy_string(row0, 0, 2, "20");
if((d[RTC_REG_MONTH_CENTURY ] & RTC_CENTURY ) != 0) { row0[ 1] = '1'; }
copy_string(row0, 2, 2, int_to_hex2(d[RTC_REG_YEAR ] , s));
copy_string(row0, 5, 2, int_to_hex2(d[RTC_REG_MONTH_CENTURY] & 0x1f, s));
copy_string(row0, 8, 2, int_to_hex2(d[RTC_REG_DAY ] & 0x3f, s));
copy_string(row0, 11, 3, weekday_to_string(d[RTC_REG_WEEKDAY] & 0x07, s));
copy_string(row1, 0, 2, int_to_hex2(d[RTC_REG_HOUR ] & 0x3f, s));
copy_string(row1, 3, 2, int_to_hex2(d[RTC_REG_MINUTE ] & 0x7f, s));
copy_string(row1, 6, 2, int_to_hex2(d[RTC_REG_SECOND ] & 0x7f, s));
}
break;
case MODE_ALARM:
copy_string(row0, 0, 17, "day:XXX XXXX XXX");
copy_string(row1, 0, 17, "XXX:XXX alarm");
if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) { // when RTC registers are valid:
row0[ 4] = '-';
row0[ 8] = '-';
copy_string(row0, 13, 3, "---");
row1[ 0] = '-';
row1[ 4] = '-';
copy_string(row0, 5, 2, int_to_hex2(d[RTC_REG_ALARM_DAY ] & 0x3f, s));
copy_string(row0, 9, 3, weekday_to_string(d[RTC_REG_ALARM_WEEKDAY] & 0x07, s));
copy_string(row1, 1, 2, int_to_hex2(d[RTC_REG_ALARM_HOUR ] & 0x3f, s));
copy_string(row1, 5, 2, int_to_hex2(d[RTC_REG_ALARM_MINUTE ] & 0x7f, s));
if((d[RTC_REG_ALARM_DAY ] & RTC_ALARM_DISABLE ) == 0) { row0[13] = 'a'; row0[ 4] = '*'; }
if((d[RTC_REG_ALARM_WEEKDAY] & RTC_ALARM_DISABLE ) == 0) { row0[13] = 'a'; row0[ 8] = '*'; }
if((d[RTC_REG_ALARM_HOUR ] & RTC_ALARM_DISABLE ) == 0) { row0[13] = 'a'; row1[ 0] = '*'; }
if((d[RTC_REG_ALARM_MINUTE ] & RTC_ALARM_DISABLE ) == 0) { row0[13] = 'a'; row1[ 4] = '*'; }
if((d[RTC_REG_CONTROL2 ] & RTC_ALARM_INTERRUPT_ENABLE) != 0) { row0[14] = 'i'; }
if((d[RTC_REG_CONTROL2 ] & RTC_ALARM_FLAG ) != 0) { row0[15] = 'A'; }
}
break;
case MODE_TIMER:
copy_string(row0, 0, 17, "XXXXHz XX XXXXX");
copy_string(row1, 0, 17, "f=XXXXXHz timer");
if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) { // when RTC registers are valid:
copy_string(row0, 0, 4, timer_select[d[RTC_REG_TIMER_CONTROL] & 0x03]);
copy_string(row0, 7, 2, int_to_hex2(d[RTC_REG_TIMER], s));
copy_string(row1, 2, 5, frequency_select[d[RTC_REG_CLKOUT_FREQUENCY] & 0x03]);
copy_string(row0, 11, 5, "-----");
if((d[RTC_REG_CLKOUT_FREQUENCY] & RTC_CLKOUT_ENABLE ) != 0) { row0[11] = 'f'; }
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_PERIODIC ) != 0) { row0[12] = 'p'; }
if((d[RTC_REG_TIMER_CONTROL ] & RTC_TIMER_ENABLE ) != 0) { row0[13] = 't'; }
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_INTERRUPT_ENABLE) != 0) { row0[14] = 'i'; }
if((d[RTC_REG_CONTROL2 ] & RTC_TIMER_FLAG ) != 0) { row0[15] = 'T'; }
}
break;
}
LCD_cursor(LCD_CURSOR_OFF);
LCD_locate(0, 0);
LCD_print_string(row0);
LCD_locate(1, 0);
LCD_print_string(row1);
LCD_locate(cursor_row[alarm_clock_mode][alarm_clock_cursor], cursor_column[alarm_clock_mode][alarm_clock_cursor]);
LCD_cursor(LCD_CURSOR_ON);
}
// read button and update button_on_count[i]
// called by timer tick interrupt
static void button_check() {
char r = i2c_BTN_read();
button_on_check(r, BUTTON_A );
button_on_check(r, BUTTON_B );
button_on_check(r, BUTTON_LEFT );
button_on_check(r, BUTTON_DOWN );
button_on_check(r, BUTTON_RIGHT);
button_on_check(r, BUTTON_UP );
if(button_trigger(BUTTON_A, 0, 0)) { button_exit(); }
if(button_trigger(BUTTON_B, 0, 0)) { button_function(); }
if(button_trigger(BUTTON_LEFT, 1, 0)) { button_cursor_move(0); }
if(button_trigger(BUTTON_RIGHT, 1, 0)) { button_cursor_move(1); }
if(button_trigger(BUTTON_DOWN, 1, 1)) { button_xxcrement(0); }
if(button_trigger(BUTTON_UP, 1, 1)) { button_xxcrement(1); }
}
// button on check
static void button_on_check(int read_data, int button_number) {
if((read_data & (0x01 << button_number)) == BUTTON_ON) {
++button_count[button_number];
}
else {
button_count[button_number] = 0;
button_status[button_number] = BUTTON_IDLE;
}
}
// button action trigger check
// b: button number
// r: repeat enable
// f: fast-repeat enable
static bool button_trigger(int b, int r, int f) {
if((button_status[b] == BUTTON_IDLE) && (button_count[b] > BUTTON_THRESHOLD)) {
button_status[b] = BUTTON_BUSY;
return true; // one shot
}
else if((f != 0) && (button_count[b] > BUTTON_FAST) && (button_count[b] % BUTTON_PERIOD_FAST == 0)) {
return true; // repeat fast
}
else if((r != 0) && (button_count[b] > BUTTON_REPEAT) && (button_count[b] % BUTTON_PERIOD_REPEAT == 0)) {
return true; // repeat
}
else {
return false;
}
}
// exit to normal mode
static void button_exit() {
alarm_clock_mode = MODE_NORMAL;
alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
}
// select a function
static void button_function() {
switch(alarm_clock_mode) {
case MODE_NORMAL:
alarm_clock_mode = MODE_ADJUST;
alarm_clock_cursor = CURSOR_ADJUST_SECOND;
break;
case MODE_ADJUST:
alarm_clock_mode = MODE_ALARM;
alarm_clock_cursor = CURSOR_ALARM_FLAG;
break;
case MODE_ALARM:
alarm_clock_mode = MODE_TIMER;
alarm_clock_cursor = CURSOR_TIMER_FLAG;
break;
case MODE_TIMER:
alarm_clock_mode = MODE_NORMAL;
alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
break;
}
}
// move cursor
// flag 0:left, 1:right
static void button_cursor_move(int flag) {
const int max[4] = { CURSOR_NORMAL_MAX, CURSOR_ADJUST_MAX, CURSOR_ALARM_MAX, CURSOR_TIMER_MAX };
switch(flag) {
case 0: // move left .. decrement
if(alarm_clock_cursor > 0) {
--alarm_clock_cursor;
}
else {
alarm_clock_cursor = max[alarm_clock_mode];
}
break;
case 1: // move right .. increment
++alarm_clock_cursor;
if(alarm_clock_cursor > max[alarm_clock_mode]) {
alarm_clock_cursor = 0;
}
break;
}
}
// increment/decrement
// flag 0:decrement, 1:increment
static void button_xxcrement(int flag) {
switch(alarm_clock_mode) {
case MODE_NORMAL:
button_xxcrement_normal(flag);
break;
case MODE_ADJUST:
button_xxcrement_adjust(flag);
break;
case MODE_ALARM:
button_xxcrement_alarm(flag);
break;
case MODE_TIMER:
button_xxcrement_timer(flag);
break;
}
}
// increment/decrement for NORMAL
// flag 0:decrement, 1:increment
static void button_xxcrement_normal(int flag) {
char d;
d = RTC_read1(RTC_REG_CONTROL2);
switch(alarm_clock_cursor) {
case CURSOR_NORMAL_TIMER_FLAG:
d = d & 0x1b | (flag == 0 ? 0x00 : 0x04);
break;
case CURSOR_NORMAL_ALARM_FLAG:
d = d & 0x17 | (flag == 0 ? 0x00 : 0x08);
break;
}
RTC_write1(RTC_REG_CONTROL2, d);
}
// increment/decrement for ADJUST
// flag 0:decrement, 1:increment
static void button_xxcrement_adjust(int flag) {
char d;
switch(alarm_clock_cursor) {
case CURSOR_ADJUST_HOUR:
d = RTC_stop_read1(RTC_REG_HOUR) & 0x3F;
d = xxcrement_bcd(flag, d, 0x00, 0x23);
RTC_write1_start(RTC_REG_HOUR, d);
break;
case CURSOR_ADJUST_MINUTE:
d = RTC_stop_read1(RTC_REG_MINUTE) & 0x7F;
d = xxcrement_bcd(flag, d, 0x00, 0x59);
RTC_write1_start(RTC_REG_MINUTE, d);
break;
case CURSOR_ADJUST_SECOND:
d = RTC_stop_read1(RTC_REG_SECOND) & 0x7f;
d = (flag == 0 ? 0x30 : 0x00);
RTC_write1_start(RTC_REG_SECOND, d);
break;
default:
button_xxcrement_adjust_date(flag);
}
}
// increment/decrement century, year, month, day
// flag 0:decrement, 1:increment
static void button_xxcrement_adjust_date(int flag) {
char century, bcd_year, bcd_month, bcd_day, weekday, d;
RTC_stop_read_date(century, bcd_year, bcd_month, bcd_day);
switch(alarm_clock_cursor) {
case CURSOR_ADJUST_CENTURY:
century = xxcrement_bcd(flag, century, 0x00, 0x01);
break;
case CURSOR_ADJUST_YEAR:
bcd_year = xxcrement_bcd(flag, bcd_year, 0x00, 0x99);
break;
case CURSOR_ADJUST_MONTH:
bcd_month = xxcrement_bcd(flag, bcd_month, 0x01, 0x12);
break;
case CURSOR_ADJUST_DAY:
bcd_day = xxcrement_bcd(flag, bcd_day, 0x01, bcd_days_in_month(century, bcd_year, bcd_month));
break;
}
d = bcd_days_in_month(century, bcd_year, bcd_month);
if(bcd_day > d) {
bcd_day = d;
}
weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
RTC_write_date_start(century, bcd_year, bcd_month, bcd_day, weekday);
}
// increment/decrement for ALARM
// flag 0:decrement, 1:increment
static void button_xxcrement_alarm(int flag) {
char d;
switch(alarm_clock_cursor) {
case CURSOR_ALARM_DAY_DISABLE:
d = RTC_read1(RTC_REG_ALARM_DAY) & 0x3f | (flag == 0 ? 0x80 : 0x00);
RTC_write1(RTC_REG_ALARM_DAY, d);
break;
case CURSOR_ALARM_DAY:
d = RTC_read1(RTC_REG_ALARM_DAY);
d = xxcrement_bcd(flag, d & 0x3f, 0x00, 0x31) | d & 0x80;
RTC_write1(RTC_REG_ALARM_DAY, d);
break;
case CURSOR_ALARM_WEEKDAY_DISABLE:
d = RTC_read1(RTC_REG_ALARM_WEEKDAY) & 0x07 | (flag == 0 ? 0x80 : 0x00);
RTC_write1(RTC_REG_ALARM_WEEKDAY, d);
break;
case CURSOR_ALARM_WEEKDAY:
d = RTC_read1(RTC_REG_ALARM_WEEKDAY);
d = xxcrement_bcd(flag, d & 0x07, 0x00, 0x06) | d & 0x80;
RTC_write1(RTC_REG_ALARM_WEEKDAY, d);
break;
case CURSOR_ALARM_INTERRUPT:
d = RTC_read1(RTC_REG_CONTROL2) & 0x1d | (flag == 0 ? 0x00 : 0x02);
RTC_write1(RTC_REG_CONTROL2, d);
break;
case CURSOR_ALARM_FLAG:
d = RTC_read1(RTC_REG_CONTROL2) & 0x17 | (flag == 0 ? 0x00 : 0x08);
RTC_write1(RTC_REG_CONTROL2, d);
break;
case CURSOR_ALARM_HOUR_DISABLE:
d = RTC_read1(RTC_REG_ALARM_HOUR) & 0x3f | (flag == 0 ? 0x80 : 0x00);
RTC_write1(RTC_REG_ALARM_HOUR, d);
break;
case CURSOR_ALARM_HOUR:
d = RTC_read1(RTC_REG_ALARM_HOUR);
d = xxcrement_bcd(flag, d & 0x3f, 0x00, 0x23) | d & 0x80;
RTC_write1(RTC_REG_ALARM_HOUR, d);
break;
case CURSOR_ALARM_MINUTE_DISABLE:
d = RTC_read1(RTC_REG_ALARM_MINUTE) & 0x7f | (flag == 0 ? 0x80 : 0x00);
RTC_write1(RTC_REG_ALARM_MINUTE, d);
break;
case CURSOR_ALARM_MINUTE:
d = RTC_read1(RTC_REG_ALARM_MINUTE);
d = xxcrement_bcd(flag, d & 0x7f, 0x00, 0x59) | d & 0x80;
RTC_write1(RTC_REG_ALARM_MINUTE, d);
break;
}
}
// increment/decrement for TIMER
// flag 0:decrement, 1:increment
static void button_xxcrement_timer(int flag) {
char d;
switch(alarm_clock_cursor) {
case CURSOR_TIMER_SELECT:
d = RTC_read1(RTC_REG_TIMER_CONTROL);
d = xxcrement_bcd(flag, d & 0x03, 0x00, 0x03) | d & 0x80;
RTC_write1(RTC_REG_TIMER_CONTROL, d);
break;
case CURSOR_TIMER_COUNT:
d = RTC_read1(RTC_REG_TIMER);
switch(flag) {
case 0: --d; break;
case 1: ++d; break;
}
RTC_write1(RTC_REG_TIMER, d);
break;
case CURSOR_CLKOUT_ENABLE:
d = RTC_read1(RTC_REG_CLKOUT_FREQUENCY) & 0x03 | (flag == 0 ? 0x00 : 0x80);
RTC_write1(RTC_REG_CLKOUT_FREQUENCY, d);
break;
case CURSOR_TIMER_PERIODIC:
d = RTC_read1(RTC_REG_CONTROL2) & 0x0f | (flag == 0 ? 0x00 : 0x10);
RTC_write1(RTC_REG_CONTROL2, d);
break;
case CURSOR_TIMER_ENABLE:
d = RTC_read1(RTC_REG_TIMER_CONTROL) & 0x03 | (flag == 0 ? 0x00 : 0x80);
RTC_write1(RTC_REG_TIMER_CONTROL, d);
break;
case CURSOR_TIMER_INTERRUPT:
d = RTC_read1(RTC_REG_CONTROL2) & 0x1e | (flag == 0 ? 0x00 : 0x01);
RTC_write1(RTC_REG_CONTROL2, d);
break;
case CURSOR_TIMER_FLAG:
d = RTC_read1(RTC_REG_CONTROL2) & 0x1b | (flag == 0 ? 0x00 : 0x04);
RTC_write1(RTC_REG_CONTROL2, d);
break;
case CURSOR_CLKOUT_FREQUENCY:
d = RTC_read1(RTC_REG_CLKOUT_FREQUENCY);
d = xxcrement_bcd(flag, d & 0x03, 0x00, 0x03) | d & 0x80;
RTC_write1(RTC_REG_CLKOUT_FREQUENCY, d);
break;
}
}