編集履歴一覧に戻る
eepooのアイコン画像

eepoo が 2021年02月28日17時22分55秒 に編集

初版

タイトルの変更

+

シンプル時間設定キッチンタイマー

タグの変更

+

秋葉原2021

+

Arduino

+

キッチンタイマー

本文の変更

+

世の中のキッチンタイマーはユーザインタフェースがなっとらん!ということで、最小の手間で使えるキッチンタイマーを目指しました。 ![キャプションを入力できます](https://camo.elchika.com/1b1d030e5caefc4639cf2d5bd3aa097461a7f38c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f34646666663835652d323762632d346636312d623232392d303034643363646236616664/) 電源スイッチ以外にはロータリエンコーダだけ! スイッチを入れると電源が入りバッテリーの電圧を表示します。 つまみ(ロータリエンコーダ)を右に回すと設定時間の分をインクリメント。 左に回すと10秒ずつ時間を減らします。 ロータリエンコーダをクリックするとカウントダウンを開始し、0秒で音を鳴らします。 ![中を開いたところはこんな感じ](https://camo.elchika.com/9dbb6067a988de97e235949ab70237f41edcec75/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f35326334326634352d323134632d343738652d626238362d343339633035613539613930/) 上の方にまとまっているのは、背面に取り付けてあるネオジ磁石です。 バッテリーは携帯電話の電池ですので電圧が下がりすぎないようにしないといけません。なので起動時に電圧を測るようにしています。しかし、電池がマイコンのADCの基準電圧でもあるので、単にADCで測っても客観的に測ることができません。 ツェナーダイオードの電圧との比率でバッテリーの電圧を算出しています。 スピーカーはピエゾスピーカです。ちゃんと使えばどえらい音が鳴るはずなのですが、直接PWM波形を入れるだけにして音圧は控えめにしています。 全部品を3D CADでモデル化し、筐体を設計。3D プリンタで出力。 ![外観](https://camo.elchika.com/7985312ee5d743b2327d75bf088ed44c8069c023/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f61333334303937382d346430622d346234632d623334372d623431323035343936633035/) ![フロントカバーを外したところ](https://camo.elchika.com/41b8787b141297114da83a4c12ce40e4bbc22c71/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f32336163363633302d386661342d346663372d386130312d356262656661663032633631/) ![回路図](https://camo.elchika.com/f77ce4003da7bff2ff37d9bb336c80e9e0052cda/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f66623735373465352d643937352d346165332d383337372d353764376434653932633434/) ソースは以下の通り。 ```キッチンタイマー #define ROTA 3 #define ROTB 4 #define ROTSW 2 #define PWMPIN 9 #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); byte currMin = 0; byte currSec = 0; byte lastROTA = HIGH; byte setTens = 0; byte setMins = 0; byte state = 0;//idle 回転でセット受付 クリック待ち ⇒クリックで 1になる 時刻になると 警告音発する 2 1以上でクリックでリセット bool statusChanged = false; long nextSec = 0; bool first = true; #define BEEPMAX 100 //100回beepしたら自動で止まる #define BUZZONTIME 10 #define BUZZOFFTIME 300 int beepcount = 0; bool buzzOn = false; long nextBuzz = 0; #define LEFTALONE 60000 long leftAlone = LEFTALONE;//これを過ぎたら警告音 #define LFAC 30 byte lfAlarmCount = LFAC; #define STATUSMASK 200 long nextSSReady = 0; bool ssReady = false; void startStop() { if (ssReady) { statusChanged = true; ssReady = false; } } void setup() { //Serial.begin(115200); pinMode(ROTA, INPUT_PULLUP); pinMode(ROTB, INPUT_PULLUP); pinMode(ROTSW, INPUT_PULLUP); pinMode(PWMPIN, OUTPUT); pinMode(A0, INPUT); attachInterrupt(0, startStop, FALLING); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); int voltage = analogRead(A0); float vol = -0.017653 * voltage + 14.40377551; display.setTextSize(4); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0, 0); display.print(vol); display.print("V"); display.display(); delay(500); showSetTime(); } void resetLeftAlone() { leftAlone = millis() + LEFTALONE; lfAlarmCount = LFAC; } void showSetTime() { display.clearDisplay(); display.setCursor(0, 0); display.print(setMins); display.setCursor(64, 0); display.println(setTens * 10); display.display(); resetLeftAlone(); } void checkRotation() { bool rotA = digitalRead(ROTA); if (lastROTA == HIGH) { if (rotA == LOW) { byte rotB = digitalRead(ROTB); if (rotB == LOW) { setMins++; setTens = 0; } else {// CCW 10秒戻す if (setTens == 0) {//0秒からなので分桁下がり if (setMins > 0) { setTens = 5; setMins = setMins - 1; } else { setTens = 0; setMins = 0; } } else { setTens = setTens - 1; } } showSetTime(); ssReady = true; delay(50); } } lastROTA = rotA; } void showCurrTime() { display.clearDisplay(); display.display(); display.setTextSize(4); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.print(currMin); display.setCursor(64, 0); display.println(currSec); display.display(); resetLeftAlone(); } void loop() { long curr = millis(); if (curr > leftAlone) { if (lfAlarmCount > 0) { digitalWrite(PWMPIN, HIGH); delay(5); digitalWrite(PWMPIN, LOW); delay(100); digitalWrite(PWMPIN, HIGH); delay(5); digitalWrite(PWMPIN, LOW); delay(100); lfAlarmCount--; leftAlone = curr + 1000; } } //Serial.println(state); if (!ssReady) { if (curr > nextSSReady) { ssReady = true; } } switch (state) { case 0:// idle 分秒セット ロータリスイッチをチェックする checkRotation(); if (statusChanged) { statusChanged = false; nextSSReady = curr + STATUSMASK; state = 1; currMin = setMins; currSec = setTens * 10; nextSec = curr + 1000; } break; case 1://開始されたので、カウントダウンする if ( curr > nextSec) { //Serial.println(millis()); nextSec = nextSec + 1000; if (currSec == 1) { currSec = 0; if (currMin == 0) { //Mode変えてBeepしはじめる state = 2; beepcount = 0; buzzOn = true; } else { currSec = 0; //だけにして次の秒に分桁下がり } } else { if (currSec == 0) { currMin = currMin - 1; currSec = 59; } else { currSec = currSec - 1; } } showCurrTime(); } //クリックで Abort if (statusChanged) { statusChanged = false; nextSSReady = curr + STATUSMASK; state = 0; setMins = 0; setTens = 0; showSetTime(); } break; case 2://beepする if (buzzOn) { digitalWrite(PWMPIN, HIGH); delay(BUZZONTIME); digitalWrite(PWMPIN, LOW); buzzOn = false; beepcount++; nextBuzz = curr + BUZZOFFTIME; } else { if (curr > nextBuzz) { buzzOn = true; } } if (beepcount > BEEPMAX) { digitalWrite(PWMPIN, LOW); state = 0; setMins = 0; setTens = 0; showSetTime(); } //クリックで Beepを止める if (statusChanged) { statusChanged = false; nextSSReady = curr + STATUSMASK; digitalWrite(PWMPIN, LOW); state = 0; setMins = 0; setTens = 0; showSetTime(); } break; } } ```