The Raspberry Pi Pico has no Wi-Fi or Bluetooth, but an HC-05 module adds classic Bluetooth serial for about ₹250. It plugs into UART0 (GP0/GP1) and, being a 3.3 V-logic module, needs no level shifting on the Pico.
Send on, off or temp from a Bluetooth terminal app on your phone: the Pico switches its GP25 LED and replies with the chip temperature.
Wiring
| Raspberry Pi Pico | HC-05 Bluetooth serial module | Wire | Notes |
|---|---|---|---|
| VBUS | VCC | red | VBUS (pin 40) is USB 5 V. The HC-05 has its own 3.3 V regulator. |
| GND | GND | black | |
| GP1 | TXD | yellow | HC-05 TXD → GP1 (UART0 RX, physical pin 2). |
| GP0 | RXD | green | GP0 (UART0 TX, pin 1) → HC-05 RXD. Both sides are 3.3 V — no divider needed, unlike on an Uno. |
3.6–6 V on VCC (on-board 3.3 V regulator) — power from 5 V part, 3.3 V board. The module runs at 3.3 V logic. Its TXD connects straight to any board’s RX. Its RXD must not see 5 V: from an Uno or Nano TX, use a 1 kΩ / 2 kΩ divider. From ESP32 or Pico, connect directly.
Board quirks
- The plain Pico has no radio, so an HC-05 is the cheapest way to talk to it from a phone. (A Pico W can do Bluetooth LE itself, but phones’ “serial terminal” apps need classic Bluetooth SPP — which the HC-05 provides.)
- MicroPython’s REPL runs over USB on the Pico, so UART0 on GP0/GP1 is free. TX and RX cross: HC-05 TXD to the Pico’s RX pin.
- The LED is
Pin(25)on the plain Pico; the temperature comes from the RP2040’s internal sensor,ADC(4)— it reads the chip, a few degrees above room temperature. - Pair from Android Bluetooth settings (PIN 1234 or 0000), then connect in an app such as “Serial Bluetooth Terminal”. iPhones can’t see the HC-05 at all.
Code
# HC-05 Bluetooth module on a Raspberry Pi Pico (no wireless of its own) - MicroPython.
# Control the Pico from an Android "Serial Bluetooth Terminal" app: type on, off or temp.
# Wiring (UART0): VCC -> VBUS (pin 40, USB 5 V), GND -> GND,
# TXD -> GP1 (pin 2, UART0 RX), RXD -> GP0 (pin 1, UART0 TX). Both are 3.3 V logic - no divider.
from machine import UART, Pin, ADC
import time
bt = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1), timeout=50) # HC-05 data mode default: 9600 8N1
led = Pin(25, Pin.OUT) # the plain Pico's LED is GP25 (on a Pico W it would be Pin("LED"))
temp_sensor = ADC(4) # RP2040's internal temperature sensor
def chip_temp():
v = temp_sensor.read_u16() * 3.3 / 65535
return 27 - (v - 0.706) / 0.001721 # formula from the RP2040 datasheet
def reply(text):
bt.write(text + "\r\n")
print("->", text)
print("HC-05 on UART0 (GP0/GP1). Pair with PIN 1234 (or 0000), then send: on, off, temp")
buf = b""
while True:
data = bt.read()
if data:
buf += data
while b"\n" in buf or b"\r" in buf:
for sep in (b"\r\n", b"\n", b"\r"):
if sep in buf:
line, buf = buf.split(sep, 1)
break
try:
cmd = line.decode().strip().lower()
except UnicodeError:
continue
if not cmd:
continue
print("<-", cmd)
if cmd == "on":
led.on()
reply("LED on")
elif cmd == "off":
led.off()
reply("LED off")
elif cmd == "temp":
reply("Pico chip temperature {:.1f} C".format(chip_temp()))
else:
reply("Unknown command. Try: on, off, temp")
time.sleep_ms(20)# HC-05 Bluetooth module on a Raspberry Pi Pico (no wireless of its own) - MicroPython.
# Control the Pico from an Android "Serial Bluetooth Terminal" app: type on, off or temp.
# Wiring (UART0): VCC -> VBUS (pin 40, USB 5 V), GND -> GND,
# TXD -> GP1 (pin 2, UART0 RX), RXD -> GP0 (pin 1, UART0 TX). Both are 3.3 V logic - no divider.
from machine import UART, Pin, ADC
import time
bt = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1), timeout=50) # HC-05 data mode default: 9600 8N1
led = Pin(25, Pin.OUT) # the plain Pico's LED is GP25 (on a Pico W it would be Pin("LED"))
temp_sensor = ADC(4) # RP2040's internal temperature sensor
def chip_temp():
v = temp_sensor.read_u16() * 3.3 / 65535
return 27 - (v - 0.706) / 0.001721 # formula from the RP2040 datasheet
def reply(text):
bt.write(text + "\r\n")
print("->", text)
print("HC-05 on UART0 (GP0/GP1). Pair with PIN 1234 (or 0000), then send: on, off, temp")
buf = b""
while True:
data = bt.read()
if data:
buf += data
while b"\n" in buf or b"\r" in buf:
for sep in (b"\r\n", b"\n", b"\r"):
if sep in buf:
line, buf = buf.split(sep, 1)
break
try:
cmd = line.decode().strip().lower()
except UnicodeError:
continue
if not cmd:
continue
print("<-", cmd)
if cmd == "on":
led.on()
reply("LED on")
elif cmd == "off":
led.off()
reply("LED off")
elif cmd == "temp":
reply("Pico chip temperature {:.1f} C".format(chip_temp()))
else:
reply("Unknown command. Try: on, off, temp")
time.sleep_ms(20)Expected serial output
HC-05 on UART0 (GP0/GP1). Pair with PIN 1234 (or 0000), then send: on, off, temp
<- on
-> LED on
<- temp
-> Pico chip temperature 31.4 CHC-05 on UART0 (GP0/GP1). Pair with PIN 1234 (or 0000), then send: on, off, temp <- on -> LED on <- temp -> Pico chip temperature 31.4 C
Common errors
Phone connects but nothing arrives
TXD/RXD not crossed, or the module is at a different baud rate. Most HC-05s use 9600 in data mode; some ship at 38400.
Garbled characters
Baud mismatch. Try baudrate=38400, or check the module’s rate with the AT command AT+UART? in command mode.
HC-05 LED blinks fast and never connects
Fast blink = waiting for a connection. Pair in Android settings first, then connect from the app — not the other way round.