diff --git a/bme280.ino b/bme280.ino new file mode 100644 index 0000000..93271c8 --- /dev/null +++ b/bme280.ino @@ -0,0 +1,23 @@ +#include "Seeed_BME280.h" + +BME280 sensor; +float highTemp = 0.0, lowTemp = 0.0; +const float blindZone = 0.03; + +void initBME280() { + sensor.init(); +} + +void readTemperature() { + float newTemperature = sensor.getTemperature(); + + if (newTemperature > highTemp) { + temperature = newTemperature; + highTemp = newTemperature; + lowTemp = highTemp - blindZone; + } else if (newTemperature < lowTemp) { + temperature = newTemperature; + lowTemp = newTemperature; + highTemp = lowTemp + blindZone; + }; +} diff --git a/button.ino b/button.ino index 9fd0b9b..a29d8c5 100644 --- a/button.ino +++ b/button.ino @@ -1,11 +1,24 @@ volatile unsigned long lastButtonPress = millis(); +// Debouncing na timerze: +// https://github.com/khoih-prog/TimerInterrupt/blob/master/examples/SwitchDebounce/SwitchDebounce.ino +void initButton() { + pinMode(BUTTON_PIN, INPUT_PULLUP); + // Order of ISRs matter: RISING should be invoked first + attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISRtime, CHANGE); + attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISRstate, RISING); +} + void buttonISRstate() { if ((millis() - lastButtonPress) > 100) { - if (countdown > 0) + if (countdown < 0) countdown = 0; - else - countdown = BREAK_LENGTH; + else if (countdown == 0) + countdown = COUNTDOWN; + else { + countdown = -1; + digitalWrite(BUTTON_LED_PIN, LOW); + } } } diff --git a/buzzer.ino b/buzzer.ino new file mode 100644 index 0000000..39ff25c --- /dev/null +++ b/buzzer.ino @@ -0,0 +1,22 @@ +SAMDTimer BuzzerTimer(TIMER_TC5); + +bool attached = false; + +void initBuzzer() { + pinMode(BUZZER_PIN, OUTPUT); +} + +void buzzerISR() { + digitalWrite(BUZZER_PIN, !digitalRead(BUZZER_PIN)); +} + +void buzz() { + if (attached) + BuzzerTimer.enableTimer(); + else + BuzzerTimer.attachInterrupt(BUZZER_FREQ *2, buzzerISR); +} + +void noBuzz() { + BuzzerTimer.disableTimer(); +} diff --git a/metronom.ino b/metronom.ino index dbf53f7..f6a369b 100644 --- a/metronom.ino +++ b/metronom.ino @@ -1,32 +1,50 @@ +#include "SAMDTimerInterrupt.h" +#include "SAMD_ISR_Timer.h" + +SAMDTimer TaskTimer(TIMER_TC3); +SAMD_ISR_Timer TasksISRs; + +void TasksHandler(void) { TasksISRs.run(); } + + +const int COUNTDOWN = 240; +const int PERIOD_MS = 1000; +const int BUZZER_FREQ = 300; + +const uint BUTTON_PIN = 6; +const uint BUTTON_LED_PIN = 5; const uint BUZZER_PIN = 0; -const uint BUTTON_LED_PIN = 5; -const uint BUTTON_PIN = 6; - -const int BREAK_LENGTH = 240000; -const int BREAK_STEP = 2000; - -volatile int countdown = 0; -int step; +/* Metronome state is expressed by countdown: + * -1 - IDLE + * 0 - BEATING + * >0 - COUNTDOWN + */ +volatile int countdown = -1; +volatile float temperature = 0.0; void setup() { - pinMode(BUTTON_PIN, INPUT_PULLUP); - // Order of ISRs matter: RISING should be invoked first - attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISRtime, CHANGE); - attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISRstate, RISING); + initButton(); + initBME280(); + initBuzzer(); + initTube(); + + TaskTimer.attachInterruptInterval_MS(20, TasksHandler); + TasksISRs.setInterval(PERIOD_MS, runMetronome); + TasksISRs.setInterval(PERIOD_MS, readTemperature); + // TODO: move display from ISR to loop() + TasksISRs.setInterval(200, updateTube); } -void loop() { +void runMetronome() { if (countdown > 0) { - step = min(BREAK_STEP, countdown); - countdown -= step; - - digitalWrite(BUTTON_LED_PIN, HIGH); - delay(min(BREAK_STEP/2, step)); - digitalWrite(BUTTON_LED_PIN, LOW); - delay(max(step-BREAK_STEP/2, 0)); - } else { - tone(BUZZER_PIN, 300, 100); - delay(1000); + countdown -= 1; + + digitalWrite(BUTTON_LED_PIN, countdown % 2 ? HIGH : LOW); + } else if (countdown == 0) { + TasksISRs.setTimeout(100, noBuzz); + buzz(); } } + +void loop() {} diff --git a/tube.ino b/tube.ino new file mode 100644 index 0000000..9d998d7 --- /dev/null +++ b/tube.ino @@ -0,0 +1,30 @@ +#include "grove_alphanumeric_display.h" + +Seeed_Digital_Tube tube; +char tubeText[5] = ""; + +void initTube() { + // Wire initialized by BME280 sensor + tube.setTubeType(TYPE_4, TYPE_4_DEFAULT_I2C_ADDR); + tube.setBrightness(15); + tube.setBlinkRate(BLINK_OFF); +} + +void updateTube() { + char newText[5]; + bool highPoint = false, lowPoint = false; + + if (countdown <= 0) { + sprintf(newText, "%4u", (unsigned int) (temperature * 100.0)); + lowPoint = true; + } else { + sprintf(newText, "%4u", countdown); + } + + if (strcmp(tubeText, newText)) { + strcpy(tubeText, newText); + tube.displayString(tubeText); + tube.setPoint(highPoint, lowPoint); + tube.display(); + } +}