HC05 / XBee First Steps



This content originally appeared on DEV Community and was authored by Daniel Guerrero

Long time ago, while researching ways to communicate through arduino, I found XBee modules, I was looking LoRa modules and this seems to fit so I got several of them
XBee Modules

since the pins are smaller than regular later I got something called an XBee Explorer to connect to computer
XBee Explorer

I didn’t know at the time much about communication modules so didn’t do much research.
Recently I wanted to test the modules again, so I started doing the research.

The original XBee are devices from Zigbee that have a specific shape and specific pins, there are different options for modules, including LoRa, WiFi and Bluetooth

The pinout for the Xbee is this:
XBee Pinout
Source

Now, the modules I got are labeled “HC05” it turns those are actually a breakout board for a module called HC05 which is soldered to the pin, the module is this:
HC05

This module is also a breakout board to only use Serial capabilities

The pinout for the module is this:
HC05 Pinout Source

So contain a lot of pins that are not used in any board

The HC05 is a Bluetooth module that supports:

  • Master / Slave Mode
  • AT Commands
  • Serial data transmission

So the module is a bit similar to the CH9143 except:

  • Master mode can pair to any other device
  • There is no USB support on HC05, only Serial
  • You can set name of the device (among other things)

Connect to module

There is a lot of examples using Arduino to send Serial data, but in this case will be directly connected to computer with python.

So to connect to computer the XBee Explorer seems like a good solution, this contains an USB to Serial solution. The main issue is to enter into AT Commands you need to set AD0 / Key / BTN pin to VCC, otherwise the module will be in pairing and only sending / receiving data but can’t configure.

So a solution is to use a USB to Serial module and a breakout board (to convert 2mm pins from xbee to standard 2.5mm, an alternative could be to solder into the pin of the XBee Explorer), so the connection is:

  • 3.3v -> VCC (PIN 1)
  • RX -> Dout (PIN 2)
  • TX -> Din (PIN 3)
  • GND -> Dout (PIN 10)
  • RTS -> AD0/Key/BTN (PIN 20)

Xbee Breakout Board

The RTS is needed to enter into AT Mode, the serial code will send this signal to enter and leave after paired with other device.

To test you could use the app Serial Bluetooth Terminal

You can run with:

python3 ch05.py /dev/ttyACM1

The output will show some info about the device and wait until you pair the device in the app

Opening port:  /dev/ttyACM1
Entering into AT mode
Sending AT... (checking if AT is enabled)
Response:  ['ERROR:(0)']
AT+VERSION? ['+VERSION:2.0-20100601', 'OK']
device MAC XX:XX:XX:XX:XX:XX
AT+NAME?: [device name] H-C-2010-06-01
AT+ROLE?: [role, 0=Slave, 1=Master] ['+ROLE:0', 'OK']
AT+ADCN?:  ['+ADCN:7', 'OK']
AT+MRAD? [connected device mac]:  XX:XX:XX:XX:XX:XX
Pair to the device: H-C-2010-06-01 with password 1234
Waiting until is paired
Sending and receiving messages, press CTRL+C to stop
Creating background receiving thread
Sending ping 0
Sending ping 1
Sending ping 2
Sending ping 3

To pair in device, in the app select the three dots, then Devices and later the H-C-2010-06-01 (note that name can be different like HC05 or similar but that will show in the console)
Devices Menu
List of Devices

And on device will show the ping

Android Bluetooth Serial Terminal

Code:

import serial
import threading
import argparse
import time
from typing import List

keep_reading = True

def read_serial(ser: serial.Serial):
    while keep_reading:
        if ser.in_waiting > 0:
            waiting = ser.in_waiting
            line = ser.read(waiting).decode("utf-8").strip()
            print("Serial Input: ", line)

def send_at_command(ser: serial.Serial, command: str) -> List[str]:
    # send command
    ser.write(f"{command}\r\n".encode("ascii"))
    # read command back
    data = []
    while True:
        line = ser.readline().decode("ascii").strip()
        data.append(line)
        if line == "OK" or "ERROR" in line:
            break

    return data

def clean_mac_response(mac: str) -> str:
    # first part is always from response
    mac = mac.split(":")[1:]
    # make a single string
    mac = "".join(mac)

    # split into groups of 2 values
    mac = [mac[i:i+2] for i in range(0, len(mac), 2)]

    return ":".join(mac)

parser = argparse.ArgumentParser(prog="HC05 Uart Example")
parser.add_argument(
    "serial_port", 
    help="Serial port like /dev/ttyACM0",
)
args = parser.parse_args()

params = {
    "port": args.serial_port,
    "baudrate": 38400,
    "bytesize": serial.EIGHTBITS, 
    "parity": serial.PARITY_NONE, 
    "stopbits": serial.STOPBITS_ONE, 
    "timeout": 1,
}

print("Opening port: ", args.serial_port)
with serial.Serial(**params) as ser:
    print("Entering into AT mode")
    # this will set RTS=3.3v 
    ser.rts = False
    time.sleep(0.1)

    print("Sending AT... (checking if AT is enabled)")
    print("Response: ", send_at_command(ser, "AT..."))
    print("AT+VERSION?", send_at_command(ser, "AT+VERSION?"))

    mac = send_at_command(ser, "AT+ADDR?")[0]
    if "ERROR" not in mac:
        print("device MAC", clean_mac_response(mac))

    device_name = send_at_command(ser, "AT+NAME?")[0].replace("+NAME:", "")
    print("AT+NAME?: [device name]", device_name)
    print("AT+ROLE?: [role, 0=Slave, 1=Master]", send_at_command(ser, "AT+ROLE?"))
    print("AT+ADCN?: ", send_at_command(ser, "AT+ADCN?"))

    mac = send_at_command(ser, "AT+MRAD?")[0]
    if "ERROR" not in mac:
        print("AT+MRAD? [connected device mac]: ", clean_mac_response(mac))

    # wait until is paired
    print(f"Pair to the device: {device_name} with password 1234")
    print("Waiting until is paired")
    while True:
        state = send_at_command(ser, "AT+STATE?")[0]
        if state == "OK" or state == "+STATE:PAIRED" or state == "+STATE:CONNECTED":
            break
        else:
            time.sleep(1)


    # disable AT mode
    ser.rts = True

    # send and receive data
    print("Sending and receiving messages, press CTRL+C to stop")
    print("Creating background receiving thread")
    thread_read = threading.Thread(target=read_serial, args=(ser,))
    thread_read.start()

    try:
        send_idx = 0
        while True:
            print(f"Sending ping {send_idx}")
            ser.write(f"UART PING {send_idx}\n".encode("ascii"))
            send_idx += 1
            time.sleep(1)
    except KeyboardInterrupt:
        pass
    finally:
        print("Finishing reading thread")
        keep_reading = False
        thread_read.join()

You will need pyserial

pip install pyserial

Final Notes

There are more commands in AT mode, here is a simple list of all: https://s3-sa-east-1.amazonaws.com/robocore-lojavirtual/709/HC-05_ATCommandSet.pdf

The HC05 module is actually a MCU BC417 with a flash memory with the firmware.
The MCU seems very capable of different things, including sending audio and controlling several GPIO and SPI, but there is no documentation about how to program it.


This content originally appeared on DEV Community and was authored by Daniel Guerrero