Control LEDs with a Raspberry Pi Pico W and Arduino Uno via UART
Control LEDs with a Raspberry Pi Pico W and Arduino Uno via UART
If you’ve ever wanted to make two microcontrollers talk to each other, this project is a perfect starting point! In this beginner-friendly guide, I’ll show you how to connect a Raspberry Pi Pico W to an Arduino Uno using UART (serial communication) to control LEDs with button presses. Press a red button on the Pico, and a red LED lights up on the Arduino—same for blue and green. It’s simple, fun, and a great way to dip your toes into microcontroller communication.
Since you’ve already got MicroPython installed on your Pico W and have some basic experience, we’ll jump right into the setup. I’ll walk you through the wiring, share the code, and explain how UART works—plus why the Pico’s 3.3V signals play nice with the Arduino’s 5V expectations. Let’s get started!
What You’ll Need
- Raspberry Pi Pico W (with MicroPython installed)
- Arduino Uno
- 3 Push Buttons (momentary switches)
- 3 LEDs (red, blue, green) + 3 220Ω resistors
- Jumper Wires (or a short Ethernet cable if you want to test distance)
- Breadboard (optional but handy)
- USB cables to power and program both boards
Step 1: Wiring the Hardware
We’re keeping it simple by using the Pico W’s internal pull-down resistors for the buttons—no external resistors required! Here’s how to connect everything:
Pico W Connections
- Buttons:
- Red Button: One side to GP12 (pin 16), other side to 3.3V (pin 36).
- Blue Button: One side to GP13 (pin 17), other side to 3.3V (pin 36).
- Green Button: One side to GP14 (pin 19), other side to 3.3V (pin 36).
- UART to Arduino:
- GP0 (UART0 TX, pin 1) → Arduino RX (pin 0).
- GND (e.g., pin 3) → Arduino GND (critical for a shared reference).
Arduino Uno Connections
- LEDs:
- Red LED: Anode to pin 3, cathode through a 220Ω resistor to GND.
- Blue LED: Anode to pin 4, cathode through a 220Ω resistor to GND.
- Green LED: Anode to pin 5, cathode through a 220Ω resistor to GND.
- UART from Pico:
- RX (pin 0) → Pico GP0 (TX).
- GND → Pico GND.
Tip: If you’re using Ethernet cable like I did, use one twisted pair (e.g., orange and orange-white) for TX-to-RX and GND. It worked flawlessly for me at 3 feet!
Step 2: The Code
Here’s the code for both boards. We’ll use MicroPython on the Pico W to send signals and Arduino’s C++ to receive them.
Pico W Code (MicroPython)
This code detects button presses and sends a character over UART:
from machine import Pin, UART import time # Set up UART on GP0 (TX) and GP1 (RX) at 9600 baud uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) # Set up buttons with internal pull-down resistors red_button = Pin(12, Pin.IN, Pin.PULL_DOWN) blue_button = Pin(13, Pin.IN, Pin.PULL_DOWN) green_button = Pin(14, Pin.IN, Pin.PULL_DOWN) # Main loop while True: if red_button.value() == 1: # Red button pressed uart.write('R') # Send 'R' print("Red button pressed") # Debug output time.sleep(0.2) # Debounce elif blue_button.value() == 1: # Blue button pressed uart.write('B') # Send 'B' print("Blue button pressed") time.sleep(0.2) elif green_button.value() == 1: # Green button pressed uart.write('G') # Send 'G' print("Green button pressed") time.sleep(0.2) time.sleep(0.01) # Small delay to keep things smooth
Upload: Save this as main.py
on your Pico W using Thonny or your preferred editor, then reset the Pico.
Arduino Uno Code
This code listens for UART signals and controls the LEDs:
// Define LED pins const int redLed = 3; const int blueLed = 4; const int greenLed = 5; void setup() { // Start serial at 9600 baud Serial.begin(9600); // Set LED pins as outputs pinMode(redLed, OUTPUT); pinMode(blueLed, OUTPUT); pinMode(greenLed, OUTPUT); // All LEDs off initially digitalWrite(redLed, LOW); digitalWrite(blueLed, LOW); digitalWrite(greenLed, LOW); } void loop() { if (Serial.available() > 0) { // Check for incoming data char command = Serial.read(); // Read the character // Light the right LED based on the command if (command == 'R') { digitalWrite(redLed, HIGH); digitalWrite(blueLed, LOW); digitalWrite(greenLed, LOW); } else if (command == 'B') { digitalWrite(redLed, LOW); digitalWrite(blueLed, HIGH); digitalWrite(greenLed, LOW); } else if (command == 'G') { digitalWrite(redLed, LOW); digitalWrite(blueLed, LOW); digitalWrite(greenLed, HIGH); } } }
Upload: Open the Arduino IDE, paste this in, and upload it to your Uno.
Step 3: Test It Out
- Power both boards via USB.
- Press the red button on the Pico—watch the red LED light up on the Arduino! Same for blue and green.
- If it doesn’t work, double-check your wiring (especially GND) and ensure both codes are uploaded.
Understanding UART: How They Talk
UART stands for Universal Asynchronous Receiver/Transmitter. It’s a simple way for two devices to send data over a wire, one bit at a time. Here’s the breakdown:
- Wires: The Pico’s TX (transmit) pin sends data to the Arduino’s RX (receive) pin. We’re not using Arduino’s TX to Pico’s RX since this is one-way communication.
- Baud Rate: Both boards are set to 9600 baud—think of it as 9600 bits per second. This speed keeps them in sync without a shared clock.
- How It Works: When you press a button, the Pico sends a character (like 'R') as a series of HIGH and LOW pulses. The Arduino decodes these pulses back into 'R' and acts on it.
Imagine UART as a telegraph: the Pico taps out a quick “R” in electrical pulses, and the Arduino listens and responds by lighting the red LED. It’s reliable and built into both boards’ hardware, making it perfect for beginners.
Logic Levels: Why 3.3V Works with 5V
Here’s where it gets interesting. The Pico W runs at 3.3V logic—its HIGH signals are 3.3V. The Arduino Uno, though, uses 5V logic and expects HIGH signals closer to 5V. So why does this setup work without a level shifter?
- Thresholds: The Arduino’s RX pin doesn’t need a full 5V to recognize a HIGH signal. For a 5V Arduino, anything above about 2.5V (sometimes as low as 2V) counts as HIGH. The Pico’s 3.3V is comfortably above that, so the Arduino reads it just fine.
- Distance: At short lengths (like 3 feet), the signal doesn’t degrade much, keeping the 3.3V strong enough.
- Safety: The Pico’s TX isn’t harmed by the Arduino’s 5V RX expectations since we’re only sending data one way—no 5V is fed back to the Pico.
If you extend the distance (say, 20-50 feet with Ethernet cable), the signal might weaken or pick up noise, dropping below 2.5V. That’s when a level shifter (to boost 3.3V to 5V) could help. For now, at a few feet, the voltage difference isn’t a problem—it’s a happy accident of compatibility!
What’s Next?
Your boards are chatting, and the LEDs are dancing to your button presses! Want to take it further?
- Add Feedback: Make the Arduino send a signal back to the Pico to confirm the LED lit up.
- Test Distance: Try longer cables and see when it breaks—share your results in the comments!
- More Controls: Add buttons or tweak the code for fancier LED patterns.
This project’s a stepping stone to bigger things. UART’s versatility opens doors to sensors, displays, and more. Let me know how it goes for you—or if you hit any snags!
Comments
Post a Comment