Experiment 2: Digital Input
All the program examples in Experiment 1 dealt with digital output, and we learned how to set the bits in the Data Direction Register (DDR) to make designated ports work as outputs. In Experiment 2 we shall look at digital inputs.
DDRC7 | DDRC6 | DDRC5 | DDRC4 | DDRC3 | DDRC2 | DDRC1 | DDRC0 |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
Referring to Table 22.1, the bits set to logic “1” in DDRC
correspond to physical ports set as outputs.
Question: What about the bits set to logic “0”?
Answer: The physical ports are inputs, and can be connected to devices outside the microcontroller, for example switches and sensors.
Question: How is the logic state of a port accessed by the microcontroller?
Answer: By reading from the corresponding port number. The ports on our Nano board are a maximum of 8 bits wide, so a read from the port returns a value between 0 and 255 (\(2^8 - 1\)).
Question: Supposing there are several digital inputs on a particular port. How can we distinguish between one input and another?
Answer: There are several ways of doing this, but they are all based on the idea of masking.
In the following example, imagine that there is a physical switch connected to Port C, bit 7. A read from Port C returns the state of all the bits from 0 to 7. In order to isolate just bit 7, we use a mask and a decision.
Value read from Port | 0 or 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 |
---|---|---|---|---|---|---|---|---|
Mask | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Value AND Mask | 0 or 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
The last row of Table 22.2 shows the result of an AND operation on the value read and the mask. So, a decision zero/non-zero will be exclusive to the bit that was masked.
The Arduino version of “C” includes some commands which allow individual bits to be interrogated. The mask operation is still there but it is “behind the scenes”.
Connecting a switch to a port
How do we connect a switch to a port pin? There are various possibilities as shown in Figure 22.1.
Option “A” looks good, but there are several problems. It requires a “change over” switch, with connections to both contacts. In addition, when the switch is in motion from “0” to “1” there is a brief period when the port voltage is undefined, which can result in unpredictable operation. For example, it could be seen as multiple operations of the switch.
Option “B” is much better. It only requires a “single pole” switch, which is the usual configuration for a keyboard. In addition, the voltage on the port is always defined; logic “0” when the switch is open, logic “1” when it is closed.
Option “C” has the same advantages as option “B”, though of course the switch action is reversed – logic “1” when the switch is open, logic “0” when the switch is closed. Historically, switch inputs on digital circuits tend to be of this type, which is known as “active low” switching. In fact, this option is supported by the internal hardware of the microcontroller, which has built-in resistors so all that is required is an external switch connected between the port and logic “0”.
This is the case for the hardware that we are using and is illustrated in Figure 22.2.
Each port has an associated pull-up register, which allows individual bits of the port to be “tied” to logic “1” through a high-value resistor. Different families of microcontrollers have different mechanisms for achieving this. In the demonstration programthat follows, the input pull-up resistors are enabled by a Arduino specific instruction, pinMode().
Another microcontroller used in our undergraduate labs, the “AW60”, has special registers called “pull-up enable” registers to perform the same task.
Using a switch in a programme
The demonstration program illustrated as a flow-chart in Figure 22.4 in Listing 22.1 is, in fact, the very first program we tried in Experiment 1. There is one refinement; a switch is tested and if the logic input is “0”, the counter does not advance. Notice the pinMode()
instruction in setup()
, which turns on the internal pull-up resistor. This is a one-off instruction at the start of program execution.
Create an Arduino sketch, and copy/paste the code from Listing 22.1 into it.
The testing of the switch input could be done using an Arduino-specific instruction, digitalRead()
, but for the sake of completeness here is how it can be done using a port read and a logical “and” operation. The designated port is port D, bit 2. Note the use of the exclamation mark (“!”); “!=” means “does not equal”.
This will work with a wide range of different microcontrollers and “C” compilers. Note the use of the ampersand (“&”) which is the logical “and” operation. The equivalent using an Arduino specific command is as follows:
The argument of the digitalRead()
operation, 2, is part of the “shorthand” used by Arduino programmers to designate a particular port pin. It has the advantage of being consistent over a wide range of boards in the Arduino family.
Add the two push button switches to the plug-in breadboard, using pin-to-pin leads ans shown in Figure 22.3. Take great care when mounting the switches on the breadboard, to orient them correctly, and to avoid bending the little tabs!
When the program runs, the LEDs on Port C will count up as before. When the left-hand button is pressed, the counter stops and resumes when the button is released. We are “in control” of the counter!
Let’s go faster
The next program, in Listing 22.2, uses both buttons. The left-hand button, as before, stops the counter. The right-hand button is a “turbo” button, and makes the counter speed up by a factor of 10!
A new program structure, if...else
has been introduced Listing 22.2 (lines 28—33) is used to decide on a delay of 1000 ms or a delay of 100 ms, depending on the condition of the button.
The general if…else
structure is as follows:
An additional program structure, else if
, can replace else
if there are multiple decisions.
An exercise for the reader…
The last part of Experiment 2 is an exercise for the reader. Do not despair, all the program elements needed have been covered in this Experiment and Experiment 1.
Modify the program in Listing 22.2 so that the buttons have this effect:
- If no buttons are pressed, a counter on Port C and a counter on Port B increment at the same rate, with a delay of 1000 ms so that the LEDs seem to be counting identically.
- If the left button is pressed, the LEDs on Port C stop counting but the LEDs on Port B continue as before.
- If the right button is pressed, the LEDs on Port B stop counting but the LEDs on Port C continue as before.
- If both buttons are pressed, both sets of LEDs stop counting but resume when the buttons are released.
A hint: there are four distinct parts inside loop()
; first of all, update both sets of LEDs. Then test one button and make a decision to increment counter 1 or not. Then test the other button and do the same for counter 2. Finally, adjust the delay.
Assessment of Experiment 2
This follows the pattern set in Experiment 1.
- A photograph of the modified breadboard, with some form of identification.
- A flow-chart of your final program as specified in An exercise for the reader… above.
- A listing of your final program with suitable comments.
Code Listings and Flow-Charts
Binary counter with stop/start control
View and download code as a GitHub gist: digi_input1.ino.
Wokwi simulation of binary counter with stop/start control
You can run a wokwi simulation of this circuit which was created by EEE project student Yousef Alsayegh (class of 2024-2025). The link is Lab 2: Binary counter with stop/start control and it uses the code from Listing 22.1. You can copy and edit this to create your own simulation the binary counter with stop/start and turbo button using the code from Listing 22.2.
If you do, it would be useful to provide links to the simulations in your lab diary.
Photograph of Experiment 2
The following photograph (Figure 22.5) has been provided by Dr Davies who created this experiment.
Copyright © 2021-2024 Swansea University. All rights reserved.