.. note::
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
**Why Join?**
- **Expert Support**: Solve post-sale issues and technical challenges with help from our community and team.
- **Learn & Share**: Exchange tips and tutorials to enhance your skills.
- **Exclusive Previews**: Get early access to new product announcements and sneak peeks.
- **Special Discounts**: Enjoy exclusive discounts on our newest products.
- **Festive Promotions and Giveaways**: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [|link_sf_facebook|] and join today!
.. _2.1.9_py_mcp3008:
2.1.9 Joystick(MCP3008)
=========================
Introduction
------------
In this project, We're going to learn how joystick works. We manipulate
the Joystick and display the results on the screen.
Required Components
------------------------------
In this project, we need the following components.
.. image:: ../img/image317 - Copy.png
It's definitely convenient to buy a whole kit, here's the link:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - Name
- ITEMS IN THIS KIT
- LINK
* - Raphael Kit
- 337
- |link_Raphael_kit|
You can also buy them separately from the links below.
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT INTRODUCTION
- PURCHASE LINK
* - :ref:`cpn_gpio_board`
- |link_gpio_board_buy|
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_joystick`
- \-
* - :ref:`cpn_mcp3008`
- \-
Schematic Diagram
------------------
When the data of joystick is read, there are some differents between
axis: data of X and Y axis is analog, which need to use MCP3008 to
convert the analog value to digital value. Data of Z axis is digital, so
you can directly use the GPIO to read, or you can also use ADC to read.
.. .. image:: ../img/2.1.9_joystick_schematic_1.png
* - T-Board Name
- physical
- WiringPi
- BCM
* - SPICE0
- pin24
- 10
- 8
* - SPIMOSI
- pin19
- 12
- 10
* - SPIMISO
- pin21
- 13
- 9
* - SPISCLK
- pin23
- 14
- 11
* - GPIO22
- pin15
- 3
- 22
.. image:: ../img/schematic_2.1.9_joystick_mcp3008.png
Experimental Procedures
--------------------------
**Step 1:** Build the circuit.
.. image:: ../img/july24_2.1.9_joystick_mcp3008.png
**Step 2:** Set up the SPI interface and install the ``spidev`` library (see :ref:`spi_configuration` for detailed instructions). If you have already completed these steps, you can skip this.
**Step 3:** Go to the folder of the code.
.. raw:: html
.. code-block::
cd ~/raphael-kit/python
**Step 4:** Run.
.. raw:: html
.. code-block::
sudo python3 2.1.9-2_Joystick.py
After the code runs, turn the Joystick, then the corresponding values of
x, y, Btn are displayed on screen.
.. warning::
If there is an error prompt ``RuntimeError: Cannot determine SOC peripheral base address``, please refer to :ref:`faq_soc`
**Code**
.. note::
You can **Modify/Reset/Copy/Run/Stop** the code below. But before that, you need to go to source code path like ``raphael-kit/python``. After modifying the code, you can run it directly to see the effect.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
# Define GPIO pin for joystick button (SW pin)
BTN_PIN = 22
# Set up GPIO mode
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Use internal pull-up
# Initialize SPI communication with MCP3008
spi = spidev.SpiDev()
spi.open(0, 0) # SPI bus 0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
def read_adc(channel):
"""
Reads analog value from the specified MCP3008 channel (0–7)
:param channel: ADC channel number (0–7)
:return: 10-bit integer value (0–1023)
"""
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
try:
# Main loop to read and print joystick values and button state
while True:
# Read X and Y values from MCP3008 channels 1 and 2
x_val = read_adc(1) # Joystick VRX connected to CH1
y_val = read_adc(2) # Joystick VRY connected to CH2
# Read the state of the joystick button (SW)
Btn_val = GPIO.input(BTN_PIN) # 0 = pressed, 1 = released
# Print the read values
print('X: %d Y: %d Btn: %d' % (x_val, y_val, Btn_val))
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
spi.close()
GPIO.cleanup()
**Code Explanation**
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
This section imports the required libraries:
- ``RPi.GPIO`` is used to handle GPIO input (joystick button).
- ``spidev`` is used to communicate with the MCP3008 ADC chip via SPI.
- ``time`` is used to introduce delays between readings.
.. code-block:: python
# Define GPIO pin for joystick button (SW pin)
BTN_PIN = 22
# Set up GPIO mode
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Initialize SPI communication with MCP3008
spi = spidev.SpiDev()
spi.open(0, 0) # SPI bus 0, CE0
spi.max_speed_hz = 1000000
This block sets the GPIO mode to ``BCM``, initializes the joystick button input on GPIO22 with a pull-up resistor, and configures the SPI interface with MCP3008 using bus 0 and chip enable 0 (CE0) at 1 MHz.
.. code-block:: python
def read_adc(channel):
"""
Reads analog value from the specified MCP3008 channel (0–7)
:param channel: ADC channel number (0–7)
:return: 10-bit integer value (0–1023)
"""
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
Defines the ``read_adc()`` function to read analog data from a specific MCP3008 channel. It sends three bytes over SPI and interprets the response to return a 10-bit value from 0 to 1023.
.. code-block:: python
try:
# Main loop to read and print joystick values and button state
while True:
# Read X and Y values from MCP3008 channels 0 and 1
x_val = read_adc(0) # Joystick VRX connected to CH0
y_val = read_adc(1) # Joystick VRY connected to CH1
# Read the state of the joystick button (SW)
Btn_val = GPIO.input(BTN_PIN) # 0 = pressed, 1 = released
# Print the read values
print('X: %d Y: %d Btn: %d' % (x_val, y_val, Btn_val))
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
spi.close()
GPIO.cleanup()
This main loop reads and prints the X/Y analog positions from the joystick and its button state every 200ms. If the script is interrupted via keyboard (Ctrl+C), SPI and GPIO are properly cleaned up.