A countdown timer for use when you can't have any light. Multiple sequential timers stored in EEPROM, with coded beeps to indicate events.

Similar projects worth following
The Dangerpants Labs Darktimer is designed for a niche market within a niche market: darkroom film processing in trays.

When tray-processing film, there is no acceptable amount of light. If you can see anything, you're fogging the film.*

I've used single-shot timers, but they always left something lacking. Thus the Darktimer: a device that would run multiple timers in sequence (60 sec film wash; 8.5 min development; 30 sec stop bath; 4 min fix; 10 min wash), and provide customizable audio feedback. And it should be simple to build: an Arduino Pro Mini, an LCD (no backlight), some pushbuttons, a speaker and a battery holder round out the BOM.

* It is possible to use 1st gen night-vision gear to see without damaging most film. And that's cool. But I didn't want to build that.

The Darktimer is designed to have multiple sequential timers, so particular attention was paid to making a simple UI so that entering, editing and deleting timers would be straightforward. The use of a 16x2 LCD makes this simpler, since it can spell out instructions as necessary.

The UI was also designed to facilitate usage in the dark: it has one Big Red Button (referred to as GO in the documentation and code) to make the next timer go, and three smaller buttons (NEXT, + and -). Hit the GO button to start the timer. Once it's finished, the next timer is armed and ready to fire on the next press of GO. Hit GO by mistake? Hit NEXT to pause, and NEXT again to reset that timer.

Because this was never designed to be a super-accurate timer, it makes use of the CPU clock (via TIMER1) to keep track of time. The maximum time for a timer is 99 minutes and 59 seconds, which should still come in with reasonable accuracy, and avoids having to add an RTC.

The LCD I'll be using is a cheap-as-possible 16x2 from MPJA. I think it cost $1.95, as did my BRB, and the other three pushbuttons were even cheaper. The lack of a backlight keeps the price down, and the whole project can be built for about $30, or less if you have a reasonably stocked junkbox.

The code was developed using Test-Driven Development, mostly as an exercise for myself in TDD. The end result, though, is that the Darktimer is almost completely covered by tests down to the hardware interface, with all the benefits that entails. It also means that all the development thus far has been on a Linux machine, and each complete test run takes ~0.3 seconds to execute. Much faster than attempting to do the testing on the Arduino. Of course, this also means that the code was developed independent of the limits of an AVR, and it's possible (though unlikely) that it will require reworking to avoid resource constraints. Fortunately, being developed divorced from hardware also means that if the Arduino proves an infertile ground for the project, it can be moved to some other processor with relative ease. UPDATE: the compiled code only takes up 8k of program space, and the 328P has exactly the right number of hardware timers, so there are no concerns about resource limitations!

Finally, the beep coding system is kind of cool. A brief, high beep indicates a key press (good confirmation in the dark). A low brief beep indicates a one-second tick. A low, longer beep indicates a whole minute marker. A per-timer double-beep can be set to mark that N seconds have passed (think every 15 seconds, to help indicate when to start or stop agitating film). Then, the last 5 seconds get treble-beeps in a higher tone, and the final alarm is currently set at 5 short beeps in the higher tone. These were inspired in part by the WWV time broadcasts on 2.5, 5, 10, 15 and 20 MHz.

  • 1 × Arduino Pro MIni
  • 1 × Speaker
  • 1 × 16x2 LCD without backlight
  • 1 × Big Red Button
  • 3 × Smaller pushbuttons

View all 10 components

  • It's very nearly a thing

    Dangerpants Labs12/14/2015 at 19:40 0 comments

    After a few months of competing priorities, I have finally cut the case and installed some of the bits and pieces. The correct buttons just arrived this morning, so I can take out the placeholder buttons and actually wire up the fully-functional Darktimer v1.

    Minimal testing suggests the code works fine with the power-saving features turned on -- primarily turning off pieces of the processor which aren't being used. I haven't measured current consumption yet, but now that I"ve got the code blown onto the Arduino Pro Mini, I expect it to be much lower.

    The project page is more or less done, and can be previewed here:

    Once I have the prototype fully built up, I'll be taking pictures and finalizing the project page. Looks like v1 is code-complete, and the first prototype is only an hour or two from being finished.

    Feature ideas for future versions:

    • Temperature-aware timers for precise timing of development (this may be a completely different project, too)
    • "Repeat" setting for timers when doing repetitive tasks
    • Configurable timer series: one for developing film, one for developing paper, etc.
    • Upgraded sounds: moving beyond the tone() function

  • Nearly ready to launch

    Dangerpants Labs09/25/2015 at 05:52 0 comments

    The prototype and code are in good shape. Knocked out all the bugs I could find, and I've been updating the project page. It's practically a real thing!

    Loaded up Fritzing for the first time, and made up a wiring diagram with it. Not very hard to figure out, which was nice. The output certainly looks nice, for the breadboard view.

    Once I get a chance to load the latest code onto the processor and see if my latest tweaks have broken anything (hopefully they've knocked down the power consumption a little bit -- 45 mA at rest!), I think this thing is ready to publish.

    I still have to put together the encased prototype, but this code is feeling pretty much ready.

    Cool new feature idea: adding a temperature probe, and adding a temperature compensation factor per timer: you program the correct time at a given temperature, and a ratio of time change per degree (probably by inputting temps vs. times rather than having to do any calculations on your own) and the timer automatically adjusts time to match temperature. That's for a future version, but I really like it, and it would allow me to stop being so fanatical about chemistry temperature.

  • (Probably) bug-free

    Dangerpants Labs08/26/2015 at 22:50 0 comments

    With various appendages crossed, I'm ready to call the code bug-free. I haven't tested absolutely everything, but all the big stuff is fixed, and all seems to be working the way I expect it to. Just pushed the "final" commit for this set of features, though I have one more useful thing to implement: hold-and-repeat on the + and - buttons. It shouldn't represent much code or even coding time, but will be a big leap forward in useability.

    There's an order from Mouser winging its way my direction, containing the bits and pieces I didn't already have (mostly a suitable LCD, and an enclosure). Once that arrives, I can make the (admittedly very hacky-looking) physical object. There are still a number of questions to answer as to the physical build (mostly whether I want a volume control so I can go from silent to just-audible, and whether I want to have an external contrast adjustment), but it'll be nice to break out the mill and do some LCD and button mounting.

    At this rate, I could have a working widget within a month or two. That's pretty cool.

  • Success! (Mostly!)

    Dangerpants Labs08/24/2015 at 05:23 0 comments

    The prototype phase is nearly complete. Rejiggering things so the buttons are just read instead of generating interrupts worked with minimal effort. I was able to get the code running, almost completely bug-free, on the hardware this weekend. The board, buttons and LCD are still terribly jury-rigged, but things are generally looking good.

    The one snag is that the code doesn't work quite the same way on the board as it does in the test run. I'm not sure if my test is incorrect (most likely scenario), or the code actually runs differently on the 328, but in a situation where there are multiple timers saved, deleting the first one then resetting the processor causes the program to claim there are no timers available. Testing for this exact scenario works perfectly, with no errors.

    Of course, one of the things the tests don't do very well is test what happens when multiple operations are strung together, so it may be that I'm running into bad EEPROM state after adding and deleting timers -- the tests are all very precisely focused, and reset "EEPROM" each time. I may have to add a couple more larger-scale tests.

    However, this one problem aside, it's pretty cool to see code that has only existed as a series of tests for many sporadically-active months actually work the way it's supposed to (mostly) on the hardware.

  • Assumptions bad

    Dangerpants Labs08/23/2015 at 00:11 0 comments

    I started out this project assuming I would be using interrupts to register button presses. A previous project had done that, and it had worked well, but I didn't consider it very hard in my coding. That was a detail for hardware implementation.

    This weekend, I actually did the research on it, and realized that using interrupts like that will not work the way I want. So, although I thought I was close to done, I'm now having to rejigger the way all the button interactions were tested (and there are a *lot* of tests around button interaction). Fortunately, I was clever enough to make a function to handle button presses for the majority of uses, so it will be a matter of updating that one function rather than touching a zillion tests.

    It's a bit silly having to go back and rework things, but this is pretty much the heart of iterative design: do it the way you think will work, then when you discover it won't, go back and rework things until it works the way it has to. Try to keep yourself from having to do too much of an about-face with changes like this, and design in such a way that the rework will be as minimally awful as possible.

    I was able to get the LCD hooked up properly last night, and got the display I was expecting, after some trouble with a doubled-up pin. No button handling meant I couldn't see anything happening, but it was pretty cool to see the opening screen looking like it should.

  • Arduino compilation: success

    Dangerpants Labs08/19/2015 at 18:44 0 comments

    This is a minor update, but I was able to get the Arduino IDE to compile the code successfully late last night. It was too late to try actually moving the code to hardware (and hardware isn't set up yet), but it was a nice milestone to pass.

    For those who question my interest in compiling with the IDE vs. going deeper with avr-gcc and friends (such as myself), I counter that this is intended to be a lightweight project that's easy to use. Setting up the Arduino IDE is about as simple as they come. I want to get to the point of compiling with gcc and uploading with avrdude, but that's for later.

    Up next: building up the hardware on a breadboard, and seeing if any of this stuff actually runs!

  • Logic code: finished

    Dangerpants Labs08/17/2015 at 23:05 0 comments

    This weekend saw the "feature complete" stage for logic code. 1283 lines of code, and 1709 lines of test code. With any luck, those 1283 lines will compile down into something that will still fit in the flash storage of an ATMega328P, though I haven't tried yet. It gives me a good appreciation for how much code surrounds us: this timer is pretty straightforward, and it still took many hours to write, and occupies (an admittedly somewhat sparse) 1283 lines.

    The logic code is basically everything that can be written without having the hardware in front of me. All the display stuff, timer manipulation, beep manipulation, button presses (via interrupt variables), etc. The hardware layer will be its own challenge, although there are only 8 function calls that will hook up to hardware (read and write EEPROM, tone on and off, start and stop a 1 second timer, get millis, and set a line on the display). These are all things that I've dealt with before, but never all at once.

    I know the Arduino Tone library (which I'm hoping to use) takes up a timer, and I believe the millis() function takes up another, which should fill up the timers available on the 328. So I'm not sure if I'm going to have trouble trying to set a 1s interrupting timer.

    One thing I'd like to do, but may not be able to just yet, is to put the CPU to sleep until the next interrupt comes in. The buttons and 1s timer are all designed as interrupts with this in mind, but I've never done any low-power work on a microcontroller, so I expect to have some challenges getting that to work. The battery will last a whole lot longer if the CPU can sleep between ticks and button presses.

View all 7 project logs

Enjoy this project?



jordan97826 wrote 03/09/2017 at 22:44 point

Wow so cool

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates