THIS CHAPTER INTRODUCES YOU to the analog joystick and digital rotary encoder for the Arduino and Raspberry Pi. We start off by covering the analog joystick for the Arduino, and you learn how to connect and operate it. Next, we present a game using this joystick that is similar to the popular electronic game called “Simon,” in which the user repeats a sequence of light patterns produced by a group of four LEDs. Then you learn about the rotary encoder controller. You learn how to connect and operate the encoder using an Arduino to control an RGB LED. This is followed by a discussion on how to connect and operate a rotary encoder using a Raspberry Pi. Finally, you use the Raspberry Pi to control a LED using the rotary encoder.
A joystick is a user input device that allows you to move a stick to the left or right and up or down. The joystick we will be using in this book is an analog joystick. That is, when a user moves the joystick, the values returned are within a range of values based on the position of the joystick (Figure 4-1).
Figure 4-1 | A joystick. |
In this hands-on example, you will learn how to hook up an analog joystick to an Arduino and how to read the horizontal and vertical positions of the joystick.
The parts you will need for this hands-on example project include
1 analog joystick
1 breadboard (optional)
4 wires (approximately)
To set up the hardware for this hands-on example, you will need to:
Connect the GND terminal of the joystick to the GND pin of the Arduino.
Connect the 5-V terminal of the joystick to the 5-V pin of the Arduino.
Connect the VRx pin on the joystick to the A0 or analog pin 0 of the Arduino.
Connect the VRy pin on the joystick to the A1 or analog pin 1 of the Arduino (Figure 4-2).
Figure 4-2 | Testing the joystick. |
An analog joystick measures the horizontal and vertical positions of the joystick using two potentiometers, one on each axis. The values are between 0 and 1,023, assuming a 5-V input to the joystick. The leftmost position is 0, and the rightmost position is 1,023. The topmost position is 0, and the bottommost position is 1,023. The default center position is somewhere in between 0 and 1,023. In this example, the center position is read at the beginning of the program and is used to offset the raw input values from the Joystick. Thus the center position will be zero.
The Arduino program for this hands-on example:
1. Assigns the JoyPinX
variable, which represents the VRx pin on the joystick, to analog pin 0 on the Arduino. This VRx pin represents the horizontal value of the joystick.
2. Assigns the JoyPinY
variable, which represents the VRy pin on the joystick, to analog pin 1 on the Arduino. This VRy pin represents the vertical value of the joystick.
3. Locates the CenterX
variable, which holds the adjusted x position of the joystick, as the center at 0.
4. Locates the CenterY
variable, which holds the adjusted y position of the joystick, as the center at 0.
5. Initializes the X
variable, which holds the raw value of the x position from the joystick.
6. Initializes the Y
variable, which holds the raw value of the y position from the joystick.
7. Initializes the X1
variable, which holds the adjusted value of the x position from the joystick.
8. Initializes the Y1
variable, which holds the adjusted value of the y position from the joystick.
9. Defines the setup()
function, which:
a. Initializes the Serial Monitor to 9,600 baud and prints out a message indicating that the program has started.
b. Determines the raw x and y values of the joystick center.
c. Prints out the raw x and y values of the joystick center to the Serial Monitor.
10. Defines the main loop()
function, which
a. Reads the raw x and y joystick positions using the analogRead()
function for the Arduino pins connected to the x and y joystick coordinate output pins.
b. Calculates the adjusted x and y joystick coordinates, with (0,0)
being the coordinates when the joystick is centered.
c. Prints out the adjusted and raw x and y joystick coordinates to the Serial Monitor. See Listing 4-1.
Now you need to upload the program to the Arduino. After uploading, start the Serial Monitor. The first line should read
Arduino Joystick Test
This should be followed by the x and y coordinates of the joystick center in raw unadjusted values:
JoyStick Center: 508 , 522
When the joystick is centered, the output should look something like this. The first pair of numbers is the adjusted x and y coordinates of the joystick, and the last pair of numbers is the raw or unadjusted pair of x and y joystick coordinates (both sets of numbers are shown in bold print):
0 , 0 Raw (X,Y): 508 , 522
When the joystick is pushed all the way to the right, the x values (shown in bold print) should increase to their maximum:
515 , 0 Raw (X,Y): 1023 , 522
When the joystick is pushed all the way to the left, the x values (shown in bold print) should decrease to their minimum:
-508 , 0 Raw (X,Y): 0 , 522
When the joystick is pushed all the way up, the y values (shown in bold print) should decrease to their minimum:
0 , -522 Raw (X,Y): 508 , 0
When the joystick is pushed all the way down, the y values (shown in bold print) should increase to their maximum:
0 , 501 Raw (X,Y): 508 , 1023
If the x or y axis of the joystick is in between the minimum and maximum positions, then the x or y value should be in between the minimum and maximum values.
In this hands-on example project, you will learn how to build a game similar to the popular electronic game called “Simon” in which different colored lights flash in a certain order, and the player must reproduce this pattern by pressing buttons that correspond to the correct lights. However, in this project, you will be using a joystick as the input device that allows you to highlight a LED and then press a button to select this as an entry for the sequence that needs to be reproduced.
To put together this hands-on example project, you will need
1 analog joystick
4 LEDs
4 10,000-Ω resistors (optional to reduce LED brightness)
1 push button
1 or more breadboards
Wires to connect the components
To set up the hardware for this hands-on example project, you will need to:
Connect the GND terminal of the joystick to the GND pin of the Arduino.
Connect the 5-V terminal of the joystick to the 5-V pin of the Arduino.
Connect the VRx pin on the joystick to the A0 or analog pin 0 of the Arduino.
Connect the VRy pin on the joystick to the A1 or analog pin 1 of the Arduino.
Connect all the negative terminals on the LEDs to GND.
Connect each of the positive terminals of the LEDS to a 10,000-Ω resistor.
For one of the LEDs, connect the other end of the resistor to pin 11 of the Arduino.
For one of the LEDs, connect the other end of the resistor to pin 10 of the Arduino.
For one of the LEDs, connect the other end of the resistor to pin 9 of the Arduino.
For one of the LEDs, connect the other end of the resistor to pin 8 of the Arduino.
Connect one pin of the push button to the 5-V output node of the Arduino.
Connect the other pin of the push button to a node that contains one end of a 10,000-Ω resistor. Then connect the other end of the resistor to GND.
Connect pin 7 of the Arduino to the node that contains the 10,000-Ω resistor and the pin from the push button (Figure 4-3).
Figure 4-3 | Arduino “Simon Says” game. |
The program that controls the hardware for this example consists of variables that hold the data needed for the program, functions that encapsulate key functions of the program, the setup()
function that is called first when the Arduino is turned on, and the loop()
function that is executed continuously by the Arduino after the setup()
function has finished executing. This section discusses each of these key parts. First, we will look at the variables for the program. Next, we will discuss the setup()
function . Then we will address the main loop()
function and its supporting functions.
The JoyPinX
and JoyPinY
variables represent the pins on the joystick that output the x and y positions of the joystick. The pin that outputs the x position of the joystick is assigned to analog pin 0 of the Arduino. The pin that outputs the y position of the joystick is assigned to the analog pin 1 of the Arduino:
int JoyPinX = 0; int JoyPinY = 1;
The CenterX
and CenterY
variables hold the raw x and y joystick positions of the joystick when the joystick is centered. Both of these variables are initialized to 0:
int CenterX = 0; int CenterY = 0;
The X
variable holds the adjusted value of the x joystick position, where a value of 0 is centered. The Y
variable is not used in this example but is left for future expansion. Both variables are initialized to 0:
int X = 0; int Y = 0;
The ButtonPin
variable represents the push button that is connected to pin 7 of the Arduino:
int ButtonPin = 7;
The PreviousButtonPress
variable is 1 if the button was pressed during the previous reading of the button and 0 if it was not pressed:
int PreviousButtonPress = 0;
The LEDPin1
through LEDPin4
variables represent the pin numbers on the Arduino to which each of these LEDs is connected:
int LEDPin1 = 8; int LEDPin2 = 9; int LEDPin3 = 10; int LEDPin4 = 11;
The NumberLEDS
variable holds the number of LEDs available to be used in the game and is initialized to 4:
const int NumberLEDS = 4;
The MaxEntries
variable holds the maximum number of entries for a sequence and is set here to 5:
const int MaxEntries = 5;
The NumberEntriesRequired
variable holds the number of entries that a player must enter for a sequence to be valid and is initialized to 4:
int NumberEntriesRequired = 4;
The LEDNum2PinMap
array maps the LED number, such as 0 through 3, to the pin of the Arduino that is connected to that LED. The array holds a maximum of NumberLEDS
elements:
int LEDNum2PinMap[NumberLEDS];
The ComputerEntries
array holds the entries of the sequence generated by the Arduino that the player must try to match. The sequence is MaxEntries
long:
int ComputerEntries[MaxEntries];
The ComputerEntryGenerated
variable is true if a new Arduino-generated sequence has been created and false otherwise:
boolean ComputerEntryGenerated = false;
The NumberUserEntries
variable holds the current number of selections the player has entered toward matching the Arduino-generated sequence:
int NumberUserEntries = 0;
The UserEntries
array holds LED identification numbers such as 0 for LED number 0 that the user has selected so far in order to match the Arduino-generated sequence:
int UserEntries[MaxEntries];
The UserSelection
variable holds the LED number that the player has chosen to enter into the player’s matching sequence:
int UserSelection = 0;
The JoystickThreshold
variable holds the minimum absolute value in the horizontal direction that is required to generate a joystick input event:
int JoystickThreshold = 150;
The JoystickDelay
variable holds the minimum amount of time that must pass before two different joystick inputs are recognized by the program. This is done to slow down the speed at which the LED selection by the player is updated. The minimum time between recognizing two different joystick inputs is set to 500 milliseconds:
int JoystickDelay = 500;
The JoystickPrevMovementTime
variable keeps track of the last time the joystick input was read:
unsigned long JoystickPrevMovementTime = 0;
The ButtonDelay
variable is the minimum time in milliseconds between reading input from the push button. This is needed so that electrical noise caused by pressing the button can settle before another reading can give accurate results. This process is called debouncing. The minimum delay is 350 milliseconds:
int ButtonDelay = 350;
The ButtonLastToggledTime
variable keeps track of the last time the button changed state from being pressed to being released in milliseconds:
unsigned long ButtonLastToggledTime = 0;
The Score
variable keeps track of the player’s score:
int Score = 0;
The EntryValue
is the value of each complete sequence. By default, a value of 10 is added to the player’s score for each correct sequence of LEDs that he or she reproduces. A value of 10 is subtracted from the player’s score for each incorrect sequence that the player enters:
int EntryValue = 10;
The setup()
function initializes the program by:
1. Initializing the Arduino Serial Monitor and setting up the communication speed at 9,600 baud.
2. Printing out a message to the Serial Monitor indicating that the game has started.
3. Reading the x position of the joystick and setting this as the center x position.
4. Halting program execution for 100 milliseconds so that the next analog read is accurate.
5. Reading in the y position of the joystick and setting this as the center y position.
6. Printing out the center x and y positions to the Serial Monitor.
7. Setting the pin of the Arduino that is connected to the push button to be an INPUT pin that will read the voltage level.
8. Calling the SetupLEDS()
function that initializes the LEDs that flash the sequence the player must reproduce. See Listing 4-2.
The SetupLEDS()
function initializes the LEDs that form the sequence the player must replicate by:
1. Setting as OUTPUT pins the Arduino pins that are connected to the LEDs. These pins will provide the voltage to the LEDs to light them up when needed.
2. Calling the SetupLEDPinMapping()
function to set up the system that maps LED identification numbers to actual Arduino pins. See Listing 4-3.
The SetupLEDPinMapping()
function maps LED numbers to the actual Arduino pins to which the LEDs are connected using the LEDNum2PinMap
array. See Listing 4-4.
The loop()
function contains the main game logic and does the following:
1. If a new Arduino-generated sequence needs to be generated, then the function:
a. Prints out a message to the Serial Monitor stating that you will need to press the button to start the game.
b. Waits until the button has been pressed and then continues execution of the program.
c. Generates a new sequence by calling the SelectComputerEntry()
function.
d. Prints out the new sequence to the Serial Monitor by calling the PrintComputerEntry()
function.
e. Displays the new sequence on the LEDs by calling the PlayComputerEntryOnLED()
function.
f. Prints a message to the Serial Monitor asking the player to hit the push button to start entering his or her matching sequence.
g. Waits until the push button has been pressed before continuing program execution.
2. When the player begins his or her input, the program:
a. Processes the player’s joystick input by calling the ProcessJoyStickMovement()
function.
b. Displays the player’s selection from step a on the correct LED by calling the DisplayUserSelectionLED()
function.
3. If the player presses the button, then the program:
a. Prints to the Serial Monitor the LED number that the player has selected.
b. Adds the player’s LED selection to the sequence that the player is generating.
c. Flashes all the LEDs briefly by calling the FlashAllLEDS()
function.
d. Updates the number of entries that the player has entered for the sequence and print this number to the Serial Monitor.
4. If the number of entries the player has entered is equal to the required number of entries for the sequence to be completed, then the program:
a. Turns off all the LEDs by calling the TurnOffAllLEDS()
function.
b. Tells the Arduino that another random sequence needs to be generated by setting the ComputerEntryGenerated
variable to false.
c. Resets the number of player entries for the sequence to 0.
d. Tests to see if the player’s sequence is the same as the Arduino-generated sequence by calling the EvaluateUserEntry()
function.
5. If the player’s sequence matches the Arduino’s sequence, then the program prints out a message indicating the sequences matched, flashes the LEDs on and off with a long duration for the LEDs’ on time and short off time, and updates the score. Otherwise, the program prints out a message indicating that the sequences did not match, flashes the LEDs on and off rapidly, and updates the score.
6. The program then prints the player’s score to the Serial Monitor. See Listing 4-5.
The SelectComputerEntry()
function generates a new sequence for the player to attempt to replicate by:
1. Generating a random number between 0 and 1 less than the number of LEDs availablefor each entry.
2. Adding this random number to the ComputerEntries
array, which holds the computer-generated sequence that the player must reproduce. This number represents the LED number that the player must select to complete the sequence. See Listing 4-6.
The PrintComputerEntry()
function prints out each entry in the computer-generated sequence that is stored in the ComputerEntries
array to the Serial Monitor. See Listing 4-7.
The PlayComputerEntryOnLED()
function displays the Arduino-generated sequence that the player must reproduce by:
1. Obtaining the LED identification number from the ComputerEntries
array.
2. Obtaining the Arduino pin number that is attached to this LED by using this identification number as an index into the LEDNum2PinMap
array.
3. Lighting up the LED for 1,000 milliseconds.
4. Turning off the LED for 500 milliseconds. See Listing 4-8.
The ButtonPressed()
function processes the player’s button presses by:
1. Reading in the button status.
2. Then, if the previous button status was that the button was pressed and the current button status is that it has been released, the function calculates the time between this button release and the last one.
3. If the time between button releases is greater than the button delay time, then this is a legitimate button press. Otherwise, this button press may be from electrical noise generated from a previous button press and release and thus should be ignored. See Listing 4-9.
The ProcessJoyStickMovement()
function processes the player’s joystick input by:
1. Calculating the difference between the current time and the last time the joystick input was processed by the program.
2. Exiting if this difference is less than the joystick delay value.
3. Reading the adjusted x or horizontal position of the joystick by calling the GetJoyStickX(false)
function with false
as a parameter to indicate that we want the adjusted x position returned.
4. Updating the player’s LED selection and making sure that the new LED number is within the valid range of LED numbers if the x joystick position is greater than the joystick threshold.
5. Updating the player’s LED selection and making sure the new LED number is within the valid range of LED numbers if the x joystick position is less than the negative of the joystick threshold. See Listing 4-10.
The GetJoyStickX()
function reads the x or horizontal position of the joystick. If the input parameter is true, the raw value that is within the range 0–1,023 assuming a 5-V input to the joystick is returned. If the input parameter is false, then an adjusted value of x is returned, where the x value of a centered joystick is 0. See Listing 4-11.
The DisplayUserSelectionLED()
function displays the player’s current LED entry selection by:
1. Using the LED number that the player has selected as an index into the LEDNum2PinMap
array to map the LED number to the actual pin of the Arduino to which the LED is connected and return the LED’s pin number.
2. Turning off all the LEDs by calling the TurnOffAllLEDS()
function.
3. Turning on the LED that the player has selected. See Listing 4-12.
The TurnOffAllLEDS()
function turns off all the LEDs by:
1. Determining the pin number on the Arduino to which the LED is attached for each of the LEDs.
2. Turning off the LED by using the digitalWrite()
function and setting the pin number obtained in the preceding step to a value of LOW
for each of the LEDs. See Listing 4-13.
The FlashAllLEDS()
function flashes all the LEDs NumLoops
times using the HighTime
in milliseconds as the time to keep the LEDs on and the LowTime
as the time to keep the LEDs off. See Listing 4-14.
The EvaluateUserEntry()
function compares each entry of the LED sequence entered by the player and the computer-generated LED sequence and returns true if the sequences match and false if the sequences do not match. See Listing 4-15.
Either type in the program or download it from the publisher’s website. Upload the program to the Arduino, make sure that the joystick is centered, and run the Serial Monitor.
You should see a message indicating that the “Simon Says” game is now running along with the raw x and y values from the joystick that indicate the center values.
Arduino Simon Says Game ... JoyStick Center: 508 , 522
You should also see a message indicating that you need to press the button to start the game. After you press the push button, the Arduino generates the sequence and displays it on the Serial Monitor and using the LEDs. You are prompted again to press the button to start your sequence entry. Press the button. You should see a LED light up. You can move the joystick left and right to move the LED selector over to the first LED in the sequence. Press the button to enter that LED as the first entry in the sequence. Repeat this for the rest of the LEDs in the sequence. After you enter the last LED in the sequence, the program validates the entry, and if it is correct, the score will be increased, all the LEDs should flash in long steady intervals, and a message saying that the entries match will be displayed on the Serial Monitor:
Press Button to Start Game ... Computer Entries: 3 1 1 2 Press Button to Begin Your Entry ... User LED Selection: 3, Number User Entries: 1 User LED Selection: 1, Number User Entries: 2 User LED Selection: 1, Number User Entries: 3 User LED Selection: 2, Number User Entries: 4 *********** YES, Entries Matched ************** Score: 10
After entering a few more correct entries, try to enter an incorrect sequence. For example, if the desired sequence is 0, 2, 3, 3 but you entered 0, 2, 3, 1, then the output displayed on the Serial Monitor would look something like this:
Press Button to Start Game ... Computer Entries: 0 2 3 3 Press Button to Begin Your Entry ... User LED Selection: 0, Number User Entries: 1 User LED Selection: 2, Number User Entries: 2 User LED Selection: 3, Number User Entries: 3 User LED Selection: 1, Number User Entries: 4 ---------NO, DID NOT MATCH ------------ Score: 20
A rotary encoder controller is a device that can measure an infinite number of rotations in the clockwise and counterclockwise directions. The user either turns a shaft directly or turns a knob attached to the shaft to produce rotational motions that can be read by the Arduino or Raspberry Pi (Figure 4-4).
Figure 4-4 | A rotary encoder. |
This hands-on example project shows the use of a rotary encoder with an Arduino. The encoder contains a shaft that you can turn clockwise or counterclockwise an infinite number of times. Some of these encoders also contain a shaft that can be used as a button. This device can be used for such things as a knob to allow the user to set a value in an Arduino program or in a game that uses a paddle that moves side to side across a thin-film-transistor (TFT) screen.
To build this hands-on example project, you will need
1 rotary encoder
1 breadboard (optional, to stick the encoder into)
5 wires to attach the encoder to the Arduino
To set up this example project, you need to:
Connect the CLK (Output A) pin on the encoder to pin 7 of the Arduino.
Connect the DT (Output B) pin on the encoder to pin 6 of the Arduino.
Connect the SW pin on the encoder to pin 5 of the Arduino.
Connect the + or VCC pin on the encoder to the 5- or 3.3-V pin of the Arduino.
Connect the GND pin on the encoder to the GND pin of the Arduino (Figure 4-5).
Figure 4-5 | Arduino rotary encoder test. |
The program in this example reads in the output from the CLK (output A) and DT (output B) pins on the encoder, and based on the output signals, it determines whether the encoder is rotating and, if so, in what direction it is rotating. The rotating direction can be either clockwise (positive) or counterclockwise (negative). The program:
1. Defines EncoderPinA
, which represents the CLK pin from the encoder, as being connected to pin 7 on the Arduino.
2. Defines EncoderPinB
, which represents the DT pin from the encoder, as being connected to pin 6 on the Arduino.
3. Defines ButtonPin
, which represents the SW or Switch or Button pin from the encoder, as being connected to pin 5 on the Arduino.
4. Initializes the EncoderPos
variable to 0, which is the encoder position where each movement of the encoder increments or decrements the position by 1.
5. Initializes the PinAValueLast
variable to 0, which is the variable that holds the previous value read from output pin A from the last loop iteration.
6. Defines the PinAValue
variable, which holds the current value read from output pin A on the encoder.
7. Defines the PinBValue
variable, which holds the current value read from output pin B on the encoder.
8. Defines the ButtonValue
variable, which holds the current value read from the SW pin on the encoder and is LOW or 0 if the button is being pressed.
9. Defines the setup()
function, which:
a. Sets as input the pins on the Arduino that are connected to the encoder’s output A pin, output B pin, and SW or Button pin.
b. Initializes the Serial Monitor and prints out a message indicating that the program has started.
c. Reads the initial value from output pin A on the encoder by calling the digitalRead(EncoderPinA)
function.
10. Defines the loop()
function, which:
a. Reads the values from the output A pin, the output B pin, and the SW pin on the encoder using the digitalRead()
function.
b. If the current value read from output pin A on the encoder is not equal to the last value read from output pin A, then:
i. If the value of output pin A is the same as the value of output pin B, then the rotary encoder is being turned clockwise, so the function increments the encoder’s position.
ii. Otherwise, the rotary encoder is being turned counterclockwise, so the function decrements the encoder’s position.
iii. Prints out the encoder’s position to the Serial Monitor.
c. If the value for the button on the encoder is LOW or 0, then the button is being pressed.
d. Saves the current value of output pin A in the PinAValueLast
variable, which represents the last value read from output pin A. See Listing 4-16.
Upload the program to your Arduino, and start the Serial Monitor. You should see the following message, which indicates that the setup()
has been executed and the program has been initialized:
Arduino Rotary Encoder Test...
Next, turn the encoder shaft in the clockwise direction. You should see the encoder position increasing in the Serial Monitor as in:
EncoderPos: 1 EncoderPos: 2 EncoderPos: 3 EncoderPos: 4
Turn the encoder shaft in the counterclockwise direction. You should see the encoder’s position decreasing in the Serial Monitor as in:
EncoderPos: 0 EncoderPos: -1 EncoderPos: -2 EncoderPos: -3 EncoderPos: -4
Finally, press down on the encoder shift until you hear a clicking sound. You should see messages that the button on the encoder has been pressed:
Button Has Been Pressed ... Button Has Been Pressed ... Button Has Been Pressed ...
In this hands-on example project, you will use a rotary encoder to set, control, and display the red, green, blue, and composite values of an RGB LED. You will be able to adjust and set the red, green, and blue values of the RGB LED by rotating the rotary encoder clockwise and counterclockwise to raise or lower the intensity of the color and press down on the encoder to set the new value of the color. You will also be able display the composite RGB color on the LED.
To perform this hands-on example project, you will need
1 rotary encoder
1 breadboard (optional, to stick the encoder into)
Wires to attach the encoder and RGB LED to the Arduino
1 RGB LED
To set up this hands-on example project, you need to:
Connect the CLK (output A) pin on the encoder to pin 7 of the Arduino.
Connect the DT (output B) pin on the encoder to pin 6 of the Arduino.
Connect the SW pin on the encoder to pin 5 of the Arduino.
Connect the + or VCC pin on the encoder to the 5- or 3.3-V pin of the Arduino.
Connect the GND pin on the encoder to the GND pin of the Arduino.
Connect the Red terminal on the LED to pin 9 of the Arduino.
Connect the Ground terminal on the LED to a GND pin of the Arduino.
Connect the Green terminal on the LED to pin 10 of the Arduino.
Connect the Blue terminal on the LED to pin 11 of the Arduino (Figure 4-6).
Figure 4-6 | Encoder-controlled RGB LED. |
This hands-on example project builds on the last hands-on project, which tested out the rotary encoder. The new code is highlighted in bold type.
1. The EncoderPosDelta
variable is the amount the color values are increased or decreased when the user turns the encoder shaft and is initialized to 1:
int EncoderPosDelta = 1;
2. The ButtonReleased
variable is true if the color selection button has just been released and needs to be processed. It is set to false after the button is processed by the program:
boolean ButtonReleased = false;
3. The Red terminal on the RGB LED is assigned pin 9 of the Arduino:
int RedPin = 9;
4. The Green terminal on the RGB LED is assigned to pin 10 of the Arduino:
int GreenPin = 10;
5. The Blue terminal on the RGB LED is assigned to pin 11 of the Arduino:
int BluePin = 11;
6. The Red
variable holds the red component of the RGB LED:
int Red = 10;
7. The Green
variable holds the green component of the RGB LED:
int Green = 10;
8. The Blue
variable holds the blue component of the RGB LED:
int Blue = 10;
9. The Selections
enumeration holds the available options for the RGB LED. The SetRed
selection sets the red component of the RGB LED. The SetGreen
selection sets the green component of the RGB LED. The SetBlue
selection sets the blue component of the RGB LED. The ShowRGB
selection shows the composite of all the red, green, and blue values on the RGB LED:
enum Selections { SetRed, SetGreen, SetBlue, ShowRGB };
10. The Selection
variable holds the current active selection mode and is initialized to setting the red color component of the LED:
Selections Selection = SetRed;
See Listing 4-17. Note that this hands-on example is an extension of the rotary encoder test example and the code in bold print is new code added in.
The SetLEDColor(int R, int G, int B)
function sets the red, green, and blue color components of the RGB LED using pulse-width modulation (PWM) by calling the analogWrite()
function. The first parameter is the Arduino pin on which to generate the PWM, and the second parameter is the value of the pulse in the range from 0 to 255. See Listing 4-18. Note that this function is completely new and not previously part of the rotary encoder test example. This is why the function is in all bold print.
The setup()
function initializes the program. This function is similar to the setup()
function for the encoder test hands-on example covered previously. The changes to this function include the following:
1. The color of the RGB LED is set to the default red value, and all the other color components are set to 0. This indicates that the SetRed
selection is active.
2. The encoder position is set, which indicates the user input to the value for the red component of the LED.
3. Some debug information is printed to the Serial Monitor. See Listing 4-19.
The ProcessRotaryEncoder()
function reads in both the rotational and push button input from the rotary encoder. This is the same function as you have seen before in the rotary encoder test example except that:
1. The rotary encoder position is adjusted by a variable called EncoderPosDelta
instead of 1. This allows for better readability and allows the user to easily change the speed at which the color components are adjusted.
2. A new variable called ButtonReleased
is set to true when the user has released the button on the encoder after having pressed it. See Listing 4-20.
The UpdateRGBLED()
function sets the color of the RGB LED by:
1. Modifying the encoder position so that the values are within the range 0 to 255, which are the valid input values for a red, green, or blue color component.
2. Setting Red
to the encoder position and setting the LED to this red color if the user is selecting the value of the red component.
3. Repeating step 2 for the green and blue color components.
4. Displaying the current colors held in the Red
, Green
, and Blue
variables on the RGB LED by calling the SetLEDColor()
function if the current selection is to show the composite RGB color on the LED.
5. Printing an error to the Serial Monitor if the current selection is none of the previous values. See Listing 4-21. Note that the entire function is in bold print because it is completely new and not previously part of the rotary encoder test example.
The ProcessButtonRelease()
function processes the encoder selection button that enters the new red, green, or blue color for the LED or displays the composite RGB colors on the LED by:
1. Setting the new selection value to set the green color component and restoring the current value for the green component into the rotary encoder position variable if the current selection is setting the red component of the LED.
2. Setting the new selection value to set the blue color component and restoring the current value of the blue component into the rotary encoder position variable if the current selection is setting the green component of the LED.
3. Displaying the new selection value as the composite of the red, green, and blue components of the LED if the current selection is setting the blue component of the LED.
4. Setting the new selection value to set the red component of the LED and restoring the red component value back into the rotary encoder position variable if the current selection is to show the composite RGB LED color. See Listing 4-22. Note that the entire function is in bold because it is completely new and not part of the previous hands on example.
The Selection2String()
function returns a string corresponding to the current selection mode, which is either setting the red, green, or blue components or showing the composite LED with all red, green, and blue components. See Listing 4-23. Note that the function is in all bold print because it is new and was not previously part of the rotary encoder test example.
The PrintDebug()
function prints the current selection mode and the current value of the LED’s red, green, and blue values to the Serial Monitor. See Listing 4-24. Here is another function that is completely new to this hands-on example and thus in all bold print.
The loop()
function executes continuously and performs the main encoder controller logic by:
1. Reading in the angular rotation amount and the push button status of the rotary encoder device.
2. Updating the color on the RGB LED according to the current selection mode and current values of the red, green, and blue color components.
3. If the button has been pressed and then released, then the function:
a. Processes the user’s selection based on the selection mode.
b. Resets the ButtonReleased
variable to false so that another button press and release can be detected.
c. Prints some informational debug statements to the Serial Monitor that indicate the current selection mode and the current values for the red, green, and blue components of the LED.
See Listing 4-25.
Upload the program to your Arduino. Start the Serial Monitor, and you should see the initialization message, the current selection mode, and the current red, green, and blue values for the LED:
Arduino Rotary Encoder RGB LED Controller... Current Selection: Red RGB: 10 , 10 , 10
The default red, green, and blue values are 10 each, and the initial selection mode defaults to selecting the red component value. Try to rotate the shaft on the encoder, and you should see the encoder position increase or decrease depending on the direction you rotate the shaft:
EncoderPos: 9 EncoderPos: 8
This encoder position is used to set the red, green, and blue color components. Now press and release the encoder shaft. You should see messages on the Serial Monitor similar to the following:
Button Has Been Released ... Current Selection: Green RGB: 8 , 10 , 10
The selection mode should now be green for selecting the green component of the color using the rotary encoder. Twist the shaft to raise or lower the green component’s value, and then press and release the shaft to move on to setting the blue component value:
Button Has Been Released ... Current Selection: Blue RGB: 8 , 2 , 10
Try to raise and lower the value of the blue component by turning the shaft. Press and release the button again, and you will have selected the RGB composite mode that shows all the red, green, and blue colors combined on the LED:
Button Has Been Released ... Current Selection: RGB Composite RGB: 8 , 2 , 18
In this hands-on example project, you will learn to operate a rotary encoder with a Raspberry Pi. This example project shows you how to measure the angular movement of the rotary encoder’s shaft and introduces you to the push button feature, where the shaft of the encoder acts as a regular push button.
The components needed for this example project include
1 rotary encoder
1 breadboard (optional)
5 wires to connect the rotary encoder to the Raspberry Pi
To connect the hardware needed for this hands-on example, you will need to:
Connect the CLK (output A) pin on the rotary encoder to pin 14 of the Raspberry Pi.
Connect the DT (output B) pin on the rotary encoder to pin 15 of the Raspberry Pi.
Connect the SW (push button) pin on the rotary encoder to pin 18 of the Raspberry Pi.
Connect the Vcc (+) pin on the rotary encoder to the 3.3-V pin of the Raspberry Pi.
Connect the GND pin on the rotary encoder to one of the GND pins of the Raspberry Pi (Figure 4-7).
Figure 4-7 | Raspberry Pi rotary encoder test. |
The software for this hands-on example:
1. Imports the Rpi.GPIO module into the program.
2. Assigns pin 14 of the Raspberry Pi to output pin A or CLK on the rotary encoder.
3. Assigns pin 15 of the Raspberry Pi to output pin B or DT on the rotary encoder.
4. Assigns pin 18 of the Raspberry Pi to the button pin or SW on the rotary encoder.
5. Initializes some key variables. The encoder position is initialized to 0, and the variable that is used to determine the amount the encoder position is incremented or decremented is set to 1.
6. Sets the pin numbering scheme to BCM mode.
7. Declares the Raspberry Pi pins that are connected to output A, output B, and the push button on the rotary encoder as input pins so that the voltage values on those pins can be read.
8. Reads the voltage value from the output A pin on the encoder and stores it in the PinAValueLast
variable.
9. Performs the following as long as the user does not execute a key board interrupt:
a. Reads in the values from output A pin, output B pin, and the push button pin from the encoder.
b. If the present value of output pin A is not the same as the last value of output pin A that was read in, then:
i. Increases the encoder’s position by Delta
amount if the values from output pin A and output pin B are the same.
ii. Otherwise, decrements the value of the encoder’s position by Delta
amount.
iii. Prints the encoder’s position to the terminal.
c. If the button value is 0 or LOW voltage, then the button is being pressed, so a message is printed to the terminal.
d. The PinAValueLast
is assigned the value that was just read in from the output pin A on the encoder.
e. Prints a message to the terminal indicating that the program is exiting.
10. Deallocates the GPIO resources by calling the GPIO.cleanup()
function. See Listing 4-26.
Start the program by typing “python filename.py” in the directory in which you have stored the python program. Turn the encoder shaft clockwise, and you should see the encoder position increasing. Turn the encoder shaft counterclockwise, and you should see the encoder position decreasing. Now press the encoder’s shaft down, and you should see a message saying that the encoder’s button is being pressed. This example gives you the basics you will need to create your own Raspberry Pi programs using the encoder.
This hands-on example project extends the preceding project using the Raspberry Pi and rotary encoder. Here we add a LED that has two modes. The default mode is that the LED light intensity can be adjusted by turning the encoder shaft clockwise or counterclockwise and then selecting that intensity by pressing down on the encoder shaft, which acts as a button. This intensity is now saved, and the second mode is activated, which fades the LED down from this selected intensity and then back up to this selected intensity. When the LED is fully faded up to the selected intensity, the mode is changed back to the default, which allows the user to adjust and then select another LED light intensity to fade down and back up again.
For this hands-on example project, you will need
1 rotary encoder
1 LED
1 breadboard (optional for encoder)
Enough wires to connect the LED and encoder to the Raspberry Pi
To connect the hardware needed for this hands-on example, you will need to:
Connect the CLK (output A) pin on the rotary encoder to pin 14 of the Raspberry Pi.
Connect the DT (output B) pin on the rotary encoder to pin 15 of the Raspberry Pi.
Connect the SW (push button) pin on the rotary encoder to pin 18 of the Raspberry Pi.
Connect the Vcc (+) pin on the rotary encoder to the 3.3-V pin of the Raspberry Pi.
Connect the GND pin on the rotary encoder to one of the GND pins of the Raspberry Pi.
Connect the negative terminal of the LED to a GND pin of the Raspberry Pi.
Connect the positive terminal of the LED to pin 17 of the Raspberry Pi (Figure 4-8).
Figure 4-8 | Rotary encoder LED controller. |
This example builds on the last hands-on example using the rotary encoder. The changes and additions to the source code are shown in bold print. The following changes and additions have been made to the source code from the preceding example:
1. A new variable that holds the LED intensity level is set to 10.
2. Pin 17 on the Raspberry Pi is assigned to the positive terminal on the LED.
3. The frequency of the pulse-width modulation (PWM) on pin 17 is set to 50.
4. The selection mode is set to 0, which is the mode used to set the LED intensity by turning the encoder’s shaft.
5. The button’s previous value is set to 1, which means that the button was not pressed.
6. The variable that keeps track of user button presses is set to false.
7. The pin on the Raspberry Pi connected to the LED is set to be an output pin to provide voltage to the LED. This pin is also designated as outputting PWMs.
8. The default LED intensity is assigned to the encoder position, which can then be increased or decreased by the user.
9. A message is printed out to the terminal indicating that the program has been initialized.
10. A new function is created called ProcessEncoderInput()
, which reads the encoder’s position and the status of the button. Most of this code comes from the preceding hands-on example, but some additional code:
a. Declares global variables “global” in the function, thus allowing them to be used inside the function.
b. Limits the encoder position to a value within the range of 0 to 100.
c. If the current button status is not pressed and the previous button status was pressed, then the program sets the variable that keeps track of the button press status to 1. This means that the button was just released and should be processed.
d. Assigns the value of the current button status to the previous button status.
11. A new function that is called def FadeDownUp()
is created that fades up and down the LED by:
a. Fading the LED down to 0 from the LED intensity value in Delta
increments.
b. Fading the LED from 0 up to the LED intensity value in Delta
increments.
c. Printing a message to the terminal indicating the LED intensity value used.
d. Setting Mode
to 0, which is the mode that allows the user to change and then select the intensity of the LED he or she wants to have fade down and then back up.
12. The program does the following until the user generates a keyboard interrupt by pressing CTRL-C:
a. Processes the rotary encoder input by calling the ProcessEncoderInput()
function.
b. If the encoder button is pressed, then:
i. Sets the encoder position back to the LED intensity value if the current mode is fading the LED up and down.
ii. Inverts the mode so that if the current mode is 0, then the new mode is 1, and vice versa.
iii. Resets the ButtonPressed
variable to 0 to indicate that the button press has been processed.
iv. Assigns the encoder position to the LED intensity variable and changes the brightness of the LED using this new LED intensity if the mode is 0, which is the LED intensity selection mode.
v. Fades the LED down and then back up by calling the FadeDownUp()
function if the mode is not 0.
13. The program prints a message to the terminal indicating that the program is now exiting.
14. The program stops the PWM output to the pin on the Raspberry Pi that is connected to the LED by calling the PWMLED.stop()
function. See Listing 4-27.
Run the program from the terminal by executing “python filename.py,” where filename.py is the name of the program file. The LED should light up, and a message indicating that the program has been initialized should be printed to the terminal. The program is now in mode 0. Turn the encoder shaft, and you should see the encoder position increase or decrease. Change the intensity of the LED light, and then press and release the rotary encoder shaft to select this intensity for the next mode. The next mode fades the LED down from the current intensity and then fades it back up to the same intensity. Next, the program mode should now switch back to mode 0.
This chapter has introduced the analog joystick and the rotary encoder for the Arduino and Raspberry Pi platforms. We started off by showing how to connect and operate an analog joystick with an Arduino. Then we built a game using the joystick for the Arduino. Then the rotary encoder for an Arduino was introduced, followed by an example of controlling an RGB LED with the encoder. Next, you learned how to use a rotary encoder with a Raspberry Pi. And finally, an example was presented where a rotary encoder was used with a Raspberry Pi to control a LED.