This article offers a highly configurable approach to implementing multiple switches of type button and/or toggle in a simple, direct but reliable way and using a technique of switch 'polling'. (For the purpose of the article 'toggle' switches will also include slide, tilt or rotary style switches.)
The article builds on the approach and techniques laid out in previous publications (a tutorial), namely Understanding & Using Button Switches and the article Toggle Switches, Reliable Reading.
The background and basis to the methods offered here are largely those put forward in that tutorial and article. If it is that you wish for a deeper understanding in the theory and implementation of simple button/toggle switches, then please do refer to this tutorial and article.
The example sketch at the centre of this article is capable of working with multiple mixed switch types (button and/or toggle), wired in either or a mix of commonly seen schemes - circuits incorporating pull down 10k ohm resistors (see figure 1) or without (see figures 1 and 2).
The design of the sketch is such that switches, either style, may be wired in either way or a mixture of both - there is no restriction. This flexibility is achieved through data configuration, with each switch to be implemented being defined in accordance with the developer's needs. The sketch's switch reading functionality is controlled and directed in accordance with the switch definition data.
In summary, the two commonly seen button switch wiring schemes are:
When implementing the sketch it essential to decide which switch wiring scheme is used for each style of switch you wish to connect as this can have a fundamental bearing and affect on how the inputs are interpreted for switch ON and OFF. If you are unsure then have a look at the tutorial mentioned above, that is Understanding & Using Button Switches.
How Does It Work?The sketch is able to support many switches each connected to a digital pin. The number of switches that can be connected in this way is therefore determined by the architecture of the microcontroller used. For instance, the Arduino Mega 2560 will support literally dozens of direct digital switch connections - enough for a mock up of the Star Ship Enterprise bridge! However, 'out-of-the-box' (OOTB), the example sketch is configured for just six switches, three button and three toggle, so my UNO is a good choice with headroom to spare.
The example OOTB sketch has been preconfigured for six switches -
- 2 x button switches wired for circuit_C1,
- 1 x button switch wired for circuit_C2,
- 2 x toggle switches wired for circuit_C2,
- 1 x toggle switch wired for circuit_C1.
So, if we wish to add/remove switches or change switch circuit schemes, we simply need to make changes to the sketch's preset switch control data and, of course, include user defined code which is performed when a switch is activated.
Once configured, the sketch's main loop will poll each declared switch in turn in accordance with its switch control data. If a switch activation is detected, allowing for debounce, the switch read function returns a 'switched' status result which is then actioned by a corresponding main loop switch-case statement for that switch.
That's it, all very clear, but let's see how we can vary things.
Steps to ImplementationImplementation of the sketch is reasonably straight forward and can be directly worked out by reference to and inspection of the OOTB sketch. However, the steps to be followed will be:
- decide how many switches and of what type you wish to configure.
- for each switch, decide how it should be wired - either as 'circuit_C1' or 'circuit_C2'.
- wire up the switches according to the above choices and connect to the microcontroller.
- load up the sketch.
- update the macro definition '#define num_switches' to be the total number of switches you are connecting.
- update the macro definition list 'Switch to Pin Macro Definition List' for the switches you are connecting, one entry for each switch, suitably defined with a digital pin number etc. For ease of reading, follow the existing naming structure- see example OOTB sketch.
- now add preset data items for each switch in the 'Switch Control Sruct(ure) Declaration' ('switch_control'), but note that preset data entries for button and toggle switches are a little different, as follows -
For button type switches the presets per buttonswitch are-
For toggle type switches the presets per toggleswitch are-
- add your switch control code to the polling loop section in the main loop, add/remove switch-case segments as necessary.
Number of Wired Switches-
Switch to Pin Macro Definition List-
Switch Control Sruct(ure) Declaration, preset data-
* NOTE: to improve readability and provide a degree of self documentation, digital pins are defined by a 'Switch to Pin Macro Definition List'. This helps the readability of the switch control preset data as, rather than see, for instance, a pin value of 12, we might define this pin as being 'button_switch_3' and declaring as this macro definition. That is, '#define button_switch_3 12'.
Main Loop Polling Segment -
- Finally, for each switch, decide what you want it to do - see the main loop switch-case section under the polling for loop.
I wish to add a seventh button switch to the existing six switch OOTB sketch configuration and for this to be on digital pin 10 and configured as circuit_C1 (with a 10k ohm pull down resistor). The declarative macro/variable/code changes to the sketch would be:
- define the number of button switches configured as '#define num_switches 7'.
- add a new button switch to digital pin definition to the 'Switch to Pin Macro Definition List'. That is, '#define button_switch_7 10'.
- add new preset data to the 'Switch Control Sruct(ure) Declaration' ('switch_control') for the new button switch. That is,
'button_switch, button_switch_7, circuit_C1, LOW, false, 0, not_used'
Note that the order of the preset data in this structure is not relevant for decision control/processing - entries can be random.
- include a switch-case section in the main loop to handle your newly added button switch.
The size of the sketch was assessed, with a varying number of switches configured with the following results:
- 1 x switch, plus 1 x switch-case handler - 1152 bytes of program storage and 23 bytes of dynamic memory
- each additional switch configured adds an average of 13 bytes to both memory types, an average of 26 bytes overall.
Note that sizing considerations do not take into account any additional code beyond defining and processing switches.
The sketch is designed for handling both types of switch - button and toggle style. However, if your project only handles one of these two types of switch the sketch may be easily modified to remove the code not required.
To Note- There is a difference to be observed between the reading outcome of button switches and toggle switches. The polling section of the man loop is responsible for keeping an 'eye open' for all switch change states, irrespective of their type. This section is ideal for switch associated code to be added to process switch change states for both button and toggle style switches. Outside of the polling loop, data relating to button switches is not relevant as we can only detect a button press if we do a read - button switches are momentary switches, they go through a cycle of OFF/ON/OFF. However, toggle switches behave in a different way and are either ON or OFF. As a result the current status of toggle switches persists its last read and so can be examined and used outside of the polling loop by reference to switches[?].switch_status (it is either 'on' or '!on').
- If you find that your switches are giving spurious results it will most likely be because they are configured with the wrong preset circuit type. Check and modify as appropriate. If fact, even if you have wired and configured correctly and all is working as expected, it is instructional to flip a circuit type preset or two in the sketch and witness the results!
There is a balance to be struck with the number of switches required for a project and the method used to configure them. Whilst this article has largely been instructional, it would prove suitable where switch numbers are not too great. I would most likely look for other methods if the number of switches was, say, more than 10? For example, connecting several switches to a single analogue pin. The wiring scheme would be different and the switch reading process quite different also. No method is perfect and each comes with constraints and limitations.
Further ReadingYou might also find these contributions interesting and useful, by the same author:
- UnderstandIng and UsIng Button SwItches, the basIcs - button switches, a simple but often tricky piece of kit. The tutorial provides in ins and outs of implementing a simple button switch, with flexibility to explore differences in circuit design, different reading methods and debouncing.
- Interrupts Driven Button Switches - an approach and example of tying a button switch to an external interrupt.
- Toggle Switches - how to reliably read a toggle style switch.
- Buttons & Lights Game - a bit of fun using button switches and LEDs.
- External Interrupts, a generic framework supporting concurrent asynchronous multiple interrupts. Configure multiple external interrupts with different characteristics and add code to provide post-interrupt asynchronous processing.
- Programmatic Timed Reminder Alerting, a programmatic framework for both elapsed and real-time asynchronous alerting. Define any number of reminder alerts (sub second to hours) and process asynchronously.
Other Online Resources
Comments