#include #include #include #include #include "font16x32digits.h" #define BUTTON1 1 #define BUTTON2 3 #define BUTTON3 4 // 3v電源クロック1MHzで1秒間隔の割り込み(1分で3秒ほど遅れる) #define MINCOUNT 57 // 1分間のウォッチドッグ割り込み回数 #define SLEEPCOUNT 19 // 20秒ほどでスリープ (19+1)x1秒 #define LONGPUSH 2 // 長押し3秒以上 (2+1)x1秒 static volatile uint8_t hour, minute, second; static volatile uint16_t wdCounter; static volatile bool sleep; uint8_t mode, selNO, oldNO; char tim[6], dispBuff[17]; bool checker[32]; const PROGMEM uint8_t letter[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .-_/@bae"; #define CHRNUMBER 45 uint8_t chrnum; void setup() { pinMode(BUTTON1, INPUT_PULLUP); pinMode(BUTTON2, INPUT_PULLUP); pinMode(BUTTON3, INPUT_PULLUP); oled.begin(); oled.setFont(FONT16X32DIGITS); oled.clear(); oled.off(); sleep = true; tim[2] = ':'; tim[5] = NULL; dispBuff[16] = NULL; mode = 0; selNO = 0; oldNO = 0xff; for(int i=0; i<32; i++) checker[i] = false; chrnum = 0; // EEPROM初期設定 initEEPROM(); // 省エネ設定 ACSR |= _BV(ACD); // アナログ比較器禁止 ADCSRA &= ~_BV(ADEN); // A/D変換禁止 PRR = 13; // タイマ/カウンタ0,1電力削減 A/D変換器電力削減 cli(); // 割り込み禁止 // ウォッチドッグ設定 // 1秒間隔で割り込み WDTCR = _BV(WDIE) | _BV(WDP2) | _BV(WDP1); // スリープ設定 set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); // スリープ許可 GIMSK |= _BV(PCIE); // ピン変化割り込み許可 PCMSK |= _BV(PCINT1); // ピン1変化割り込み sei(); // 割り込み許可 wdt_reset(); //ウォッチドッグタイマーリセット } void loop() { while(sleep) // スリープ中 sleep_mode(); if(mode == 0) // 時計表示 { oled.setCursor(24, 0); decFormat(tim, hour); decFormat(tim + 3, minute); oled.print(tim); } else // リスト表示 { dispList(); } if(digitalRead(BUTTON1) == LOW) { wdCounter = 0; while(digitalRead(BUTTON1) == LOW); // キーリリース待ち if(wdCounter > LONGPUSH) // 長押し { // 設定 if(mode == 0) setTime(); else setList(); } else { // 表示モード切り替え oled.clear(); if(mode == 0) { oldNO = 0xff; // 表示切替時にリスト強制表示 oled.setFont(FONT8X16); mode = 1; // リスト表示 } else { oled.setFont(FONT16X32DIGITS); mode = 0; // 時計表示 } } wdCounter = 0; } if(wdCounter > SLEEPCOUNT) // スリープ時間チェック { // スリーブ準備 oled.off(); cli(); GIMSK |= _BV(PCIE); PCMSK |= _BV(PCINT1); sei(); sleep = true; } delay(250); // スイッチクリックのレスポンス調整(数値はお好みで) } // ウォッチドッグタイマー割り込みエントリ ISR(WDT_vect) { if(++second == MINCOUNT) { second = 0; if(++minute == 60) { minute = 0; if(++hour == 24) hour = 0; } } ++wdCounter; // 割り込み回数 } // ピン変化割り込みエントリ ISR(PCINT0_vect) { cli(); GIMSK &= ~_BV(PCIE); PCMSK &= ~_BV(PCINT1); sleep_disable(); sei(); sleep = false; oled.on(); wdCounter = 0; // スイッチリリース待ち while(digitalRead(BUTTON1) == LOW); } // 数値を2桁の文字列にする void decFormat(char* s, uint8_t d) { if(d > 9) { s[0] = '0' + d / 10; s[1] = '0' + d % 10; } else { s[0] = '0'; s[1] = '0' + d; } } // 時計の設定 void setTime() { uint8_t h, m; oled.setCursor(24, 0); oled.print("--:--"); h = hour; m = minute; while(true) { // 時 while(digitalRead(BUTTON2) == LOW) { if(++h == 24) h = 0; decFormat(tim, h); oled.setCursor(24, 0); oled.print(tim); delay(200); } // 分 while(digitalRead(BUTTON3) == LOW) { if(++m == 60) m = 0; decFormat(tim + 3, m); oled.setCursor(24, 0); oled.print(tim); delay(200); } // 設定完了 if(digitalRead(BUTTON1) == LOW) { cli(); WDTCR = 0; hour = h; minute = m; second = 0; WDTCR = _BV(WDIE) | _BV(WDP2) | _BV(WDP1); sei(); // スイッチリリース待ち while(digitalRead(BUTTON1) == LOW); oled.clear(); wdt_reset(); break; } } } // リスト表示 void dispList() { int n; // チェックマークのON/OFF if((digitalRead(BUTTON2) == LOW) && (digitalRead(BUTTON3) == LOW)) { if(checker[selNO]) checker[selNO] = false; else checker[selNO] = true; oldNO = 0xff; // スイッチリリース待ち while(digitalRead(BUTTON2) == LOW); while(digitalRead(BUTTON3) == LOW); } // 次のリスト if(digitalRead(BUTTON2) == LOW) { if(++selNO == 32) selNO = 0; } // 前のリスト if(digitalRead(BUTTON3) == LOW) { if(--selNO == 0xff) selNO = 31; } // 選択されたリストの表示 if(selNO != oldNO) // 表示内容が変更されたか { oled.clear(); oled.setCursor(0, 0); oled.print("No."); oled.print(selNO); if(checker[selNO]) oled.print(" *"); oled.setCursor(0, 2); n = selNO * 16; for(int i=0; i<16; i++) dispBuff[i] = EEPROM[n + i]; if(dispBuff[0] != 0) oled.print(dispBuff); oldNO = selNO; wdCounter = 0; } } // リスト入力 void setList() { uint16_t n; char ch; chrnum = 0; ch = 'A'; dispBuff[0] = NULL; for(int i=1; i<16; i++) dispBuff[i] = ' '; oled.clear(); oled.setCursor(0, 0); oled.print("Selected No."); oled.print(selNO); oled.setCursor(0, 2); oled.print(ch); n = 0; // カーソル位置 while(true) { // 次の文字を表示 while(digitalRead(BUTTON2) == LOW) { if(++chrnum == CHRNUMBER) chrnum = 0; ch = pgm_read_byte(letter + chrnum); oled.setCursor(n * 8, 2); oled.print(ch); delay(150); } // 前の文字を表示 while(digitalRead(BUTTON3) == LOW) { if(--chrnum == 0xff) chrnum = CHRNUMBER - 1; ch = pgm_read_byte(letter + chrnum); oled.setCursor(n * 8, 2); oled.print(ch); delay(150); } // 次の文字位置へ移動 if(digitalRead(BUTTON1) == LOW) { // キーリリース待ち while(digitalRead(BUTTON1) == LOW); switch(ch) { case 'b': // バックスペース oled.setCursor(n * 8, 2); oled.print(' '); if(--n == 0xff) n = 0; dispBuff[n] = ' '; break; case 'a': // ALLクリア for(int i=0; i<16; i++) dispBuff[i] = ' '; oled.setCursor(0, 2); oled.print(dispBuff); n = 0; dispBuff[0] = NULL; break; case 'e': // 入力終了 goto EXIT; break; default: // 文字確定 dispBuff[n] = ch; if(++n == 16) n = 15; oled.setCursor(n * 8, 2); oled.print(ch); break; } } } EXIT: oled.clear(); n = selNO * 16; for(int i=0; i<16; i++) EEPROM[n + i] = dispBuff[i]; oldNO = 0xff; // 表示を変更 } // 未使用のEEPROMを初期化 void initEEPROM() { uint8_t m; // 何も書き込まれていなければリストの先頭を0で埋める for(int i=0; i<0x200; i+=16) { if(EEPROM[i] == 0xff) EEPROM[i] = 0; } }