Rowing Clock
I've been giving the rowing machine a bit of a hammering over the last year or so. The plan is to shed my perpetual winter plumage (aka fat) and trim down to a point where I don't have to continually invest in a whole new wardrobe.
The problem (as a numbers guy) has been the ... er ... numbers on the machine. It's a comprehensive readout that comes with the machine and it successfully distracts me away from the business of proper form and zen-like concentration on the actual rowing. I'm always chasing the numbers.
After a couple of visits to the physiotherapist to confirm that I am old and fat and shouldn't be chasing numbers I switched off the readout and used instead my phone countdown to measure the time rowed. It worked semi-well until my weird brain started to panic and as I was sweating away I became distracted through wondering if the damn phone was set correctly, and whether or not I was going to be rowing until Christmas.
So what I needed was a visual way of seeing the rowing but without the actual numbers. Inspired by a pileofstuff video I planned out a little 3D printed box full of goodies including an LED Ring, a 4-digit 7-segment display (TM1637), rotary encoder and buzzer as follows.
- Set time to row
- Countdown to rowing start
- Countdown to rowing finish
- Warmdown
- Shutdown
#include <OneButton.h> #include <Rotary.h> #include <TM1637Display.h> #include <FastLED.h> #include "LowPower.h" #define NUM_LEDS 16 #define DATA_PIN 7 #define CLK 11 #define DIO 10 #define buzzer 9 uint32_t intervaldelay = 0; CRGB leds[NUM_LEDS]; volatile byte rowingmins = 1; byte minmins = 1; byte maxmins = 180; volatile byte cw = 0; volatile byte clicked = 0; byte buzzdelay = 200; TM1637Display display(CLK, DIO); Rotary r = Rotary(3, 2); OneButton button(4, true); void setup() { FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS); FastLED.setBrightness(20); PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); pinMode(buzzer, OUTPUT); button.attachClick(singleclick); display.setBrightness(4); setupcolour(0, 0, 0, 0); } void setupcolour(byte numgreen, byte numyellow, byte numred, byte numoff) { byte whichlight = 0; byte endlight = numgreen; for (byte countgreen = 0; countgreen < endlight; countgreen++) { leds[countgreen] = 0x00CC00; whichlight++; } endlight = whichlight + numyellow; for (byte countyellow = whichlight; countyellow < endlight; countyellow++) { leds[countyellow] = 0xFF9900; whichlight++; } endlight = whichlight + numred; for (byte countred = whichlight; countred < endlight; countred++) { leds[countred] = 0xCC0000; whichlight++; } endlight = whichlight + numoff; for (byte countblack = whichlight; countblack < endlight; countblack++) { leds[countblack] = 0x000000; whichlight++; } FastLED.show(); } void precount() { for (byte showcount = 0; showcount <= 16; showcount++) { setupcolour(showcount, 0, 0, 16 - showcount); delay(80); } setupcolour(0, 0, 0, 16); delay(500); setupcolour(16, 0, 0, 0); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(8000); setupcolour(12, 0, 0, 4); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(8000); setupcolour(8, 0, 0, 8); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(8000); setupcolour(4, 0, 0, 12); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(1000); setupcolour(3, 0, 0, 13); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(1000); setupcolour(2, 0, 0, 14); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(1000); setupcolour(1, 0, 0, 15); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(1000); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); } void warmdown() { for (byte downcount = 1; downcount < 4; downcount++) { setupcolour(0, 0, 16, 0); tone(buzzer, 2000); delay(buzzdelay); noTone(buzzer); delay(250); setupcolour(0, 0, 0, 16); delay(250); } for (byte warmcount = 16; warmcount >= 0; warmcount -= 1) { setupcolour(0, warmcount, 0, 16 - warmcount); delay(4000); } } ISR(PCINT2_vect) { unsigned char result = r.process(); if ((result == DIR_CW) && (rowingmins < 180)) { rowingmins++; } else if ((result == DIR_CCW) && (rowingmins > 1)) { rowingmins--; } } void singleclick() { clicked = true; } void settime() { while (!clicked) { button.tick(); display.showNumberDec(rowingmins); } PCICR = 0; //disable pin change interrupts } void loop() { settime(); precount(); display.clear(); intervaldelay = rowingmins * 60000 / 32; for (byte countdown = 16; countdown > 0; countdown--) { setupcolour(countdown - 1, 1, 0, 16 - countdown); delay(intervaldelay); setupcolour(countdown - 1, 0, 1, 16 - countdown); delay(intervaldelay); } warmdown(); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); }
No comments:
Post a Comment