世の中のキッチンタイマーはユーザインタフェースがなっとらん!ということで、最小の手間で使えるキッチンタイマーを目指しました。
電源スイッチ以外にはロータリエンコーダだけ!
スイッチを入れると電源が入りバッテリーの電圧を表示します。
つまみ(ロータリエンコーダ)を右に回すと設定時間の分をインクリメント。
左に回すと10秒ずつ時間を減らします。
ロータリエンコーダをクリックするとカウントダウンを開始し、0秒で音を鳴らします。
上の方にまとまっているのは、背面に取り付けてあるネオジ磁石です。
バッテリーは携帯電話の電池ですので電圧が下がりすぎないようにしないといけません。なので起動時に電圧を測るようにしています。しかし、電池がマイコンのADCの基準電圧でもあるので、単にADCで測っても客観的に測ることができません。
ツェナーダイオードの電圧との比率でバッテリーの電圧を算出しています。
スピーカーはピエゾスピーカです。ちゃんと使えばどえらい音が鳴るはずなのですが、直接PWM波形を入れるだけにして音圧は控えめにしています。
全部品を3D CADでモデル化し、筐体を設計。3D プリンタで出力。
ソースは以下の通り。
#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;
}
}
投稿者の人気記事
-
eepoo
さんが
2021/02/28
に
編集
をしました。
(メッセージ: 初版)
-
eepoo
さんが
2021/02/28
に
編集
をしました。
-
eepoo
さんが
2021/03/13
に
編集
をしました。
ログインしてコメントを投稿する