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 12V 3A power supply that was rescued from the dump sometime in the past.
System Design
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. System Block Diagram
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. Schematic – Click to enlarge
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.
Software Design
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
FSM transition diagram shown on the left has 6 states – INIT, IDLE,
START, RUNNING, PAUSE and END – and is implemented in the code as a
switch/case FSM.
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!