Complete Guide to Using RPi.GPIO with Raspberry Pi 3

Complete Guide to Using RPi.GPIO with Raspberry Pi 3
1. Introduction to RPi.GPIO
RPi.GPIO is a Python module designed specifically for the Raspberry Pi, allowing you to control the GPIO (General Purpose Input/Output) pins. Through these pins, you can connect various electronic components (such as LEDs, buttons, sensors, etc.) and control them to create various interesting projects.
1.1 Main Features
RPi.GPIO provides the following features:
– Control the input and output direction of GPIO pins
– Set and read pin level states (high/low)
– Configure pull-up or pull-down resistors for input pins
– Software emulation of PWM (Pulse Width Modulation)
– Edge detection (interrupt handling)
– Clean up all used GPIO pins at once
1.2 Installation
Installing RPi.GPIO on Raspberry Pi 3 is very simple:

# Update package list<br/>sudo apt-get update<br/># Install RPi.GPIO (Python 3 version)<br/>sudo apt-get install python3-rpi.gpio<br/>

If you are using Python 2 (not recommended), you can install python-rpi.gpio.
Note: The RPi.GPIO module is not suitable for real-time critical applications. This is due to Python’s garbage collection mechanism and the multitasking scheduling of the Linux kernel, which may cause execution delays. For real-time control needs, Arduino may be a better choice.
2. Basics of GPIO
2.1 Pin Numbering System
The Raspberry Pi 3 has 40 GPIO pins, but not all pins can be used for general input and output. RPi.GPIO provides two pin numbering schemes:
– BOARD numbering: numbered according to physical pin positions (1 to 40)
– BCM numbering: numbered according to the GPIO channel numbers of the Broadcom chip (e.g., GPIO17, GPIO27, etc.)
Below is a layout table of the Raspberry Pi 3B GPIO pins (BOARD and BCM numbering comparison):

BOARD Numbering BCM Numbering Function
1 3.3V Power
2 5V Power
3 2 GPIO (Input/Output)
4 5V Power
5 3 GPIO (Input/Output)
6 GND (Ground)
7 4 GPIO (Input/Output)
8 14 GPIO (Input/Output)
9 GND (Ground)
10 15 GPIO (Input/Output)
11 17 GPIO (Input/Output)
12 18 GPIO (Input/Output)
13 27 GPIO (Input/Output)
14 3.3V Power
15 22 GPIO (Input/Output)
16 23 GPIO (Input/Output)
17 GND (Ground)
18 24 GPIO (Input/Output)
19 25 GPIO (Input/Output)
20 GND (Ground)
21 8 GPIO (Input/Output/PWM)
22 7 GPIO (Input/Output/PWM)
23 10 GPIO (Input/Output)
24 9 GPIO (Input/Output)
25 11 GPIO (Input/Output)
26 8 GPIO (Input/Output/PWM)
27 GND (Ground)
28 12 GPIO (Input/Output)
29 16 GPIO (Input/Output)
30 3.3V Power
31 26 GPIO (Input/Output)
32 20 GPIO (Input/Output)
33 21 GPIO (Input/Output)
34 GND (Ground)
35 5 GPIO (Input/Output)
36 32 GPIO (Input/Output)
37 33 GPIO (Input/Output)
38 GND (Ground)
39 35 GPIO (Input/Output)
40 37 GPIO (Input/Output)

Note: Not all GPIO pins can be used simultaneously. Some pins have special functions, such as I2C, SPI, or PWM.
2.2 Pin Voltage and Current Limitations
GPIO pins provide a 3.3V signal; never connect a 5V signal!
The maximum current for each GPIO pin is approximately 16mA, and the total GPIO current should not exceed 50mA. When connecting high-power devices such as motors or relays, additional driver circuits must be used; do not connect them directly!
3. Basic Usage of RPi.GPIO
3.1 Initialization and Cleanup
The basic steps to use RPi.GPIO are:
– Import the module
– Set the pin numbering mode
– Set the pin direction and initial state
– Operate the pins
– Clean up and exit
Example code:

import RPi.GPIO as GPIO<br/>import time<br/># Set pin numbering mode - use BOARD numbering or BCM numbering<br/>GPIO.setmode(GPIO.BOARD)  # Use physical pin numbering<br/># GPIO.setmode(GPIO.BCM)  # Use Broadcom numbering<br/># Disable warning messages (can be enabled for debugging)<br/>GPIO.setwarnings(False)<br/>try:<br/>    # Set pin to output mode and initialize state<br/>    GPIO.setup(35, GPIO.OUT, initial=GPIO.LOW)     # Loop to control LED blinking<br/>    for _ in range(5):<br/>        GPIO.output(35, GPIO.HIGH)  # Turn on LED<br/>        time.sleep(1)<br/>        GPIO.output(35, GPIO.LOW)   # Turn off LED<br/>        time.sleep(1)<br/>finally:<br/>    # Clean up used pins, restore default state<br/>    GPIO.cleanup()<br/>GPIO.cleanup() is very important; it will reset all used GPIO pins to input mode to prevent system state confusion. If you only want to clean specific pins, you can pass the pin number or a list of pin numbers:<br/>GPIO.cleanup(35) or GPIO.cleanup([35, 36]).<br/>3.2 Output Control (LED)<br/>Here is a complete example of LED control:<br/><pre><code class="language-python">import RPi.GPIO as GPIO<br/>import time<br/>LED_PIN = 35  # Use physical pin 35 (BCM GPIO18)<br/>def main():<br/>    # Set to BOARD numbering mode<br/>    GPIO.setmode(GPIO.BOARD)<br/>    GPIO.setwarnings(False)     # Set LED pin to output<br/>    GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)     <br/>    try:<br/>        print("LED test started, press Ctrl+C to exit...")<br/>        while True:<br/>            # On<br/>            GPIO.output(LED_PIN, GPIO.HIGH)<br/>            print("LED ON")<br/>            time.sleep(1)             # Off<br/>            GPIO.output(LED_PIN, GPIO.LOW)<br/>            print("LED OFF")<br/>            time.sleep(1)<br/>    except KeyboardInterrupt:<br/>        print("Program terminated by user")<br/>    finally:<br/>        # Clean up and set to low level<br/>        GPIO.output(LED_PIN, GPIO.LOW)<br/>        GPIO.cleanup()<br/>        print("GPIO state has been reset")<br/>if __name__ == "__main__":<br/>    main()<br/>

This program will make the LED blink once per second until you press Ctrl+C.
3.3 Input Detection (Button)
To detect a button press, you can use the following code:

import RPi.GPIO as GPIO<br/>import time<br/>BUTTON_PIN = 37  # Use physical pin 37 (BCM GPIO26) as button input<br/>LED_PIN = 35     # Use physical pin 35 (BCM GPIO18) to control LED<br/>def button_callback(channel):<br/>    """Button press callback function"""<br/>    if GPIO.input(channel) == GPIO.HIGH:<br/>        GPIO.output(LED_PIN, GPIO.HIGH)<br/>        print("Button pressed, LED ON")<br/>    else:<br/>        GPIO.output(LED_PIN, GPIO.LOW)<br/>        print("Button released, LED OFF")<br/>def main():<br/>    # Set GPIO mode<br/>    GPIO.setmode(GPIO.BOARD)<br/>    GPIO.setwarnings(False)     # Set button pin to input and enable pull-up resistor<br/>    GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)     # Set LED pin to output<br/>    GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW)     # Register event detection for button pin<br/>    GPIO.add_event_detect(BUTTON_PIN, GPIO.BOTH, callback=button_callback, bouncetime=200)     try:<br/>        print("Button detection started, press Ctrl+C to exit...")<br/>        while True:<br/>            # Main program can do other things<br/>            time.sleep(0.1)<br/>    except KeyboardInterrupt:<br/>        print("Program terminated by user")<br/>    finally:<br/>        GPIO.remove_event_detect(BUTTON_PIN)  # Remove event detection<br/>        GPIO.cleanup()<br/>        print("GPIO state has been reset")<br/>if __name__ == "__main__":<br/>    main()<br/>

This program uses the following important concepts:
– pull_up_down=GPIO.PUD_UP: Enables the internal pull-up resistor
– GPIO.add_event_detect(): Adds detection for pin state changes
– bouncetime=200: Sets debounce time (200ms) to prevent multiple triggers when the button is pressed/released. The callback function button_callback is automatically called when the pin state changes.
3.4 Software PWM (Dimming Effect)
Although RPi.GPIO does not support hardware PWM, it provides software PWM functionality:

import RPi.GPIO as GPIO<br/>import time<br/>LED_PIN = 35    # Pin connected to LED<br/>PWM_FREQ = 100  # PWM frequency (Hz)<br/>DUTY_CYCLE = 50 # Initial duty cycle (0-100)%<br/>def main():<br/>    GPIO.setmode(GPIO.BOARD)<br/>    GPIO.setwarnings(False)     # Set LED pin to output<br/>    GPIO.setup(LED_PIN, GPIO.OUT)     # Create PWM instance with frequency of 100Hz<br/>    pwm = GPIO.PWM(LED_PIN, PWM_FREQ)     try:<br/>        # Start PWM with initial duty cycle of 50%<br/>        pwm.start(DUTY_CYCLE)<br/>        print(f"PWM started, duty cycle: {DUTY_CYCLE}%")         # Loop to adjust brightness<br/>        while True:<br/>            # Gradually brighten (0% to 100%)<br/>            for dc in range(0, 101, 5):<br/>                pwm.ChangeDutyCycle(dc)<br/>                time.sleep(0.1)<br/>             # Gradually dim (100% to 0%)<br/>            for dc in range(100, -1, -5):<br/>                pwm.ChangeDutyCycle(dc)<br/>                time.sleep(0.1)<br/>    except KeyboardInterrupt:<br/>        print("Program terminated by user")<br/>    finally:<br/>        # Stop PWM and clean up<br/>        pwm.stop()<br/>        GPIO.cleanup()<br/>        print("GPIO state has been reset")<br/>if __name__ == "__main__":<br/>    main()<br/>

This program will make the LED gradually brighten and then dim, repeating the cycle. The principle of PWM is to rapidly switch the pin on and off, simulating different levels by controlling the ratio of on time to total cycle time (duty cycle).
4. Advanced Applications
4.1 Simultaneous Control of Multiple Channels
RPi.GPIO allows you to set and operate multiple pins at once:

import RPi.GPIO as GPIO<br/>import time<br/># Define the list of pins to control<br/>LED_PINS = [35, 36, 37]  # Three LEDs connected to different pins<br/>def main():<br/>    GPIO.setmode(GPIO.BOARD)<br/>    GPIO.setwarnings(False)     # Set multiple pins to output simultaneously<br/>    GPIO.setup(LED_PINS, GPIO.OUT, initial=GPIO.LOW)     try:<br/>        while True:<br/>            # Turn on each LED in sequence<br/>            for pin in LED_PINS:<br/>                GPIO.output(pin, GPIO.HIGH)<br/>                time.sleep(0.5)<br/>                GPIO.output(pin, GPIO.LOW)<br/>                time.sleep(0.5)<br/>             # Turn on all LEDs simultaneously<br/>            GPIO.output(LED_PINS, GPIO.HIGH)<br/>            time.sleep(1)<br/>            GPIO.output(LED_PINS, GPIO.LOW)<br/>            time.sleep(1)<br/>    except KeyboardInterrupt:<br/>        print("Program terminated by user")<br/>    finally:<br/>        GPIO.cleanup(LED_PINS)  # Clean up specified pins<br/>        print("GPIO state has been reset")<br/>if __name__ == "__main__":<br/>    main()<br/>

4.2 Implementing Binary Reading of Digital Inputs
The following example shows how to read binary values from multiple digital input pins and convert them to decimal:

import RPi.GPIO as GPIO<br/># Define 4-bit binary input pins (from low to high)<br/>INPUT_PINS = [35, 36, 37, 38]  # These pins are connected to buttons or other digital signal sources<br/>def read_binary():<br/>    """Read binary values from input pins and convert to decimal"""<br/>    binary_value = 0<br/>    for i, pin in enumerate(INPUT_PINS):<br/>        # Read pin state<br/>        bit = GPIO.input(pin)<br/>        # Combine the read bits<br/>        binary_value |= (bit << i)<br/>    return binary_value<br/>def main():<br/>    GPIO.setmode(GPIO.BOARD)<br/>    GPIO.setwarnings(False)     # Set all input pins and enable pull-up resistors<br/>    for pin in INPUT_PINS:<br/>        GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)     try:<br/>        print("Binary input reading started, press Ctrl+C to exit...")<br/>        while True:<br/>            # Read binary value<br/>            value = read_binary()<br/>            # Display result<br/>            print(f"Binary: {' '.join(str(GPIO.input(pin)) for pin in INPUT_PINS)}")<br/>            print(f"Decimal: {value}")<br/>            time.sleep(0.5)<br/>    except KeyboardInterrupt:<br/>        print("Program terminated by user")<br/>    finally:<br/>        GPIO.cleanup(INPUT_PINS)<br/>        print("GPIO state has been reset")<br/>if __name__ == "__main__":<br/>    main()<br/>

This program assumes each input pin is connected to 3.3V (using pull-up resistors) or ground through buttons. Each loop reads the state of all pins, combines the obtained binary bits into a decimal number, and displays it.
5. Common Issues and Solutions
5.1 “Module not found” Error
Problem: Encountering ModuleNotFoundError: No module named ‘RPi.GPIO’ or ImportError: No module named RPi when running the script.
Solution: Confirm correct installation: Execute sudo apt-get install python3-rpi.gpio in the terminal.
Check Python version: Use python3 instead of python to run the script.
Virtual environment users: Ensure RPi.GPIO is installed in the virtual environment (pip install RPi.GPIO).
5.2 “Channel already in use” Warning
Problem: Encountering This channel is already in use, continuing anyway warning when running multiple scripts.
Solution: Add GPIO.setwarnings(False) at the beginning of the script to disable warnings.
Ensure GPIO.cleanup() is executed before each run to clean up previous states.
Use different pin numbers.
5.3 No Output or Incorrect Output from Pins
Problem: Pins do not output signals or output signals incorrectly.
Solution: Check if the pin numbering mode (BOARD vs BCM) is correct.
Confirm GPIO.setup() has been called to set the pin as output.
Use GPIO.output() to explicitly set the pin state.
Add time.sleep() delays to ensure state changes are correctly read.
Verify hardware connections.
5.4 Unstable PWM Signal
Problem: PWM signal is unstable or LED flickers.
Solution: Increase PWM frequency (usually above 100Hz, where flickering is less perceptible to the human eye).
Ensure no other operations are performed on the PWM pin.
Consider using alternative solutions for hardware PWM (such as the pigpio library).
6. Best Practices for Using GPIO
– Always use pin cleanup: Call GPIO.cleanup() at the end of the script to avoid system state confusion.
– Use context managers: You can use the with statement to ensure GPIO resources are properly cleaned up:

import RPi.GPIO as GPIO<br/>with GPIO.getmode() as mode:<br/>    GPIO.setup(35, GPIO.OUT)<br/>    # Operate GPIO<br/>

Although RPi.GPIO itself does not directly support context management, you can use third-party wrappers or implement it yourself.
– Avoid blocking the main program: Long-running GPIO operations (such as delayed blinking) can be placed in a separate thread to keep the main program responsive.
– Use appropriate pin numbering schemes: For projects with fixed physical locations on the board, use BOARD numbering; for projects that may change boards or focus on specific GPIO channels, use BCM numbering.
– Add necessary resistors: Use current-limiting resistors (about 220-330Ω) when connecting LEDs to prevent damage to GPIO.
– Do not overly rely on software PWM: For precise PWM applications, consider using dedicated hardware PWM libraries (such as pigpio) or dedicated chips.
7. Conclusion
RPi.GPIO is a powerful and easy-to-use Python library that simplifies the control of GPIO pins on the Raspberry Pi. Through this tutorial, you should have mastered:
– Installation and basic usage of RPi.GPIO
– Pin numbering schemes and usage methods
– Control of digital inputs and outputs
– Implementation of software PWM
– Simultaneous control of multiple channels
– Solutions to common issues

Leave a Comment