As part of a bigger project, I needed to make a timer that would activate a relay for a set time to switch power on/off to another device. Rather than buy one I decided to build my own from electronic bits and pieces that were on hand in my workshop, wrote some software for a ‘spare’ Arduino Pro Mini that was lying around and packaged it all up in a small box. It turned out to be quite functional, so I decided to document the build in case someone else finds this useful.
What have I got?
I wanted to minimize the number of components to make this project and use what I had at hand. Looking through my workshop supplies I settled on an assortment of modules and components:
- Arduino Pro Mini as the brains of the operation. As this was going to fit in a small box I needed a small form factor, but basically any Arduino should be able to run the software.
- 4 digit seven segment display. Mine was a common cathode model from Tayda Electronics. Any similar type will do, including common anode, as the software can be made to compensate for any differences.
- Rotary encoder with built-in switch. These are commonly available – mine are component-only encoders from eBay. These from ICStation are similar, sold as modules. I also had a plastic knob to fit the encoder.
- Relay module. These are also very common, and I had one left over from a previous experiment. This one from ICStation is similar. Basically it is triggered on/off by the Arduino software and needs to be able to switch the voltage and current that you expect to be controlling.
- Buck Converter used to power the Arduino Mini Pro and the display. This takes in up to 24V DC and converts it to 5V output. The model I have is good for up to 2A, which is plenty for the display and processor.
- A small plastic box to house the project and a couple of 2.1mm DC power jack sockets.
- A 12V 3A power supply that was rescued from the dump sometime in the past.
With the basic kit of parts identified, time to work out how they will hang together – a system block diagram – that will help in the software design and putting it all together later.
To minimize the number of components, I decided to use the Mini Pro to drive the display directly, multiplexing each digit every time through loop() to create a Persistence of Vision (POV) effect. This makes it look like the digits are illuminated when in fact they spend most of the time turned off.
As the first pass of the design I included a 74HC595 serial to parallel buffer to drive the segments as I thought there would not be enough spare digital I/O to run the display directly (the first implementation of the software uses the 595 and SPI). Subsequently, some thinking allowed me to free up enough I/O to enable me to use direct connections between the Arduino I/O and the display, removing the need for the 595.
This also led me to decide I could get away without current limiting resistors for each display segment, as the average power through each segment is quite low, further reducing the component count.
The rotary encoder and the selection switch are also wired directly to Arduino inputs, using the built-in pull-up resistors to stabilize the signals. I have existing (and much used) libraries for these simple devices, so integrating them into the system was straightforward.
Finally, the output relay needs a single output to toggle it on/off. My relay seemed to work well off the Arduino output, further reducing component count.
The software needs to take care of 3 major functions – running the LED display, managing the user interface and executing the timer.
The LED display is multiplexed and all digits are refreshed every time through the loop() function. For each digit, the LED segments representing the current time, or message, are illuminated for a very short time. A circuit is created by setting the digit selection I/O HIGH (or LOW, depending on whether common anode or cathode) and the corresponding segments to the opposite setting if they are on – the voltage difference then allows current to flow between the common and the segments. The segment patterns used for displaying the LED segments are stored in look up tables and include all the digits and the alpha characters needed for this project.
The remaining two functions (User interface and Timer) are built into the Finite State Machine (FSM) that is also executed each time through loop().
The INIT state is used to initialize an actual time register from the encoder setpoint. Each encoder ‘click’ corresponds to a (compile time configurable) fixed amount of time. The encoder setting is maintained separately from the timer value so that one timer value can be used for display and countdown without ‘forgetting’ the current set point. Some boundary checks are also carried out to ensure the set point does not exceed the maximum displayable (99 minutes and 99 seconds). Setting the encoder ‘click’ to larger values reduces the timer resolution but allows for faster setting of any time, as the encoder needs fewer rotations.
The IDLE state is one where the FSM waits for user input to either
- start the timer with a switch press, progressing to the START state, or
- change the setpoint using the encoder, going back the INIT state to recalculate the displayed timer value.
The START state activates the relay output and initializes the internal counting timer for this run of the relay timer. It then progresses to the RUNNING state.
In the RUNNING state the main function is to detect when one second has elapsed and adjust the display timer values accordingly. When the timer reaches zero the FSM progresses to the END state. Whilst in the RUNNING state, the key switch is also checked to see if a press is detected, in which case the FSM moves to the PAUSE state.
PAUSE suspends all timer processing and either moves back to RUNNING on a short key press or directly to END on a long press.
The END state is the end of the timer sequence, so the relay output is turned off and the FSM goes back to the INIT state.
The software sketch can be found at my code repository.
Putting it all Together
I decided to make a custom lid for the plastic box using the technique I described in a previous blog. I pushed the process too quickly and some of the white paint bled under the acrylic paper protection. Good enough for my own use…
The final step was to wire together all the hardware components and work out how to fit them in the box. Modules and parts were hot-glued in place and it all seemed to fit nicely. I put the Mini Pro on the base of the lid as it drastically reduced the number of wires between the lid and the main part of the box. The final assembly shows that this is not the neatest project, but once the box is shut, no-one can see the mess!