# UART Communication Between Two CircuitPython Boards

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/104/662/medium800thumb/circuitpython_ezgif.com-gif-maker_%2812%29.jpg?1631729199)

In this project, you'll learn how to communicate between two different CircuitPython boards using UART.&nbsp;

UART, universal asynchronous receiver-transmitter, is a serial communication protocol that works asynchronously. Unlike I2C, it isn't structured and does not require pull-ups. UART is also, like the name implies, universal in that just about every microcontroller and microcomputer has a UART port. This can make it really easy to set up as cross-platform.

This guide will go through a really simple example where the boards send packets back and forth between each other that tell the other board to make the built-in NeoPixel brighter. The example in this guide is very simple, but it should give you a really good start for using UART to communicate between boards in your project.

## Parts
The examples apply to nearly the full range of CircuitPython boards that have UART available. For this guide, two Circuit Playground Express boards were used.

Featured
### Circuit Playground Express

[Circuit Playground Express](https://www.adafruit.com/product/3333)
 **Circuit Playground Express** is the next step towards a perfect introduction to electronics and programming. We've taken the original Circuit Playground Classic and made it even better! Not only did we pack even more sensors in, we also made it even easier to...

In Stock
[Buy Now](https://www.adafruit.com/product/3333)
[Related Guides to the Product](https://learn.adafruit.com/products/3333/guides)
![A Black woman's manicured hand holds a round microcontroller with lit up LEDs.](https://cdn-shop.adafruit.com/640x480/3333-05.jpg)

Featured
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

# UART Communication Between Two CircuitPython Boards

## Wiring

![](https://cdn-learn.adafruit.com/assets/assets/000/104/660/medium800/circuitpython_uart.png?1631729043)

Wiring for this project is really simple. Just connect the **RX** of one board to the **TX** of the other, and the **TX** of one board to the **RX** of the other. Then connect the **GND** pin from one board to the **GND** pin on the other.

Make sure that it's wired **RX-TX** and **TX-RX** and not **RX-RX** and **TX-TX**.

Info: 

When you've wired them up, they should look something like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/104/661/medium800/circuitpython_IMG_0307.jpg?1631729184)

# UART Communication Between Two CircuitPython Boards

## Code

![](https://cdn-learn.adafruit.com/assets/assets/000/104/663/medium800thumb/circuitpython_ezgif.com-gif-maker_%2812%29.jpg?1631729460)

## Installing the Project Code

Download a zip of the project by clicking **Download Project Bundle** &nbsp;below.

After unzipping the file, the contents to both of the&nbsp; **CIRCUITPY** drives (the second one appears as&nbsp; **CIRCUITPY1** on some operating systems) which appear when the Circuit Playgrounds are connected to your computer with USB cables. After you've copied everything over, it should look something like this:

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/UART-Between-Boards.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/UART-Between-Boards/code.py

If you open up the REPL for both boards in two separate windows, you can see messages being passed back and forth like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/104/666/medium800thumb/circuitpython_ezgif.com-gif-maker_%2813%29.jpg?1631736305)

## Code Run-Through

First, the code imports the required libraries.

```python
import time
import board
import busio
import digitalio
import neopixel
import analogio
```

Next, it sets up the NeoPixel and UART, as well as the buttons for controlling the brightness.

```python
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.1, auto_write=False)

light_sensor = analogio.AnalogIn(board.LIGHT)

btn_A = digitalio.DigitalInOut(board.BUTTON_A)
btn_A.switch_to_input(pull=digitalio.Pull.DOWN)

btn_B = digitalio.DigitalInOut(board.BUTTON_B)
btn_B.switch_to_input(pull=digitalio.Pull.DOWN)

# Use a timeout of zero so we don't delay while waiting for a message.
uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=0)
```

Before the code starts the main loop, it needs to define a few variables it will be using. The first one is a variable for how often to send a new message over the UART bus. The second variable will store the last time that a message was sent, and the final one is used to&nbsp;

```python
UPDATE_INTERVAL = 3.0
last_time_sent = 0

# Wait for the beginning of a message.
message_started = False
```

Now, the code enters the main loop. It first checks to see how long since the last packet was sent, and if it has been long enough, it writes the packet containing the value from the light sensor to the other board over UART.

```python
while True:
    # Send light sensor value only every UPDATE_INTERVAL seconds.
    now = time.monotonic()
    if now - last_time_sent >= UPDATE_INTERVAL:
        light = light_sensor.value
        uart.write(bytes(f"<L,{light}>", "ascii"))
        print("sending light value", light)
        last_time_sent = now
```

If any of the built-in buttons are pressed, the code will send a different packet to the other device telling it the status of both of the buttons. This packet will be used to set the brightness of the NeoPixels.

```python
⠀⠀⠀⠀if any((btn_A.value, btn_B.value)):
        # Send values of built-in buttons if any are pressed
        uart.write(bytes(f"<B,{btn_A.value},{btn_B.value}>", "ascii"))
        print(f"Sent ({btn_A.value}, {btn_B.value})")

        # Don't do anything else until both buttons are released
        time.sleep(0.1)
        while any((btn_A.value, btn_B.value)):
            pass
```

The code now reaches the part where it tries to read a packet over the UART bus. It first tries to read one byte. If it doesn't read one, it will run the main loop over again.

Assuming it has received a byte, the code then goes on to check if the byte received is a " **\<**", which is the defined starting byte. If it has received this byte, it then clears the `message` variable, and sets the variable to indicate that it is in the process of reading a packet.

Now that the packet is being read, it checks to see if it has reached the final byte. Up until then, it will go through and keep adding to the&nbsp;`message` variable. When it has reached the end, it prints the message, and sets a few variables to make reading the message a bit easier.

```python
⠀⠀⠀byte_read = uart.read(1)  # Read one byte over UART lines
⠀⠀⠀if not byte_read:
        # Nothing read.
        continue

    if byte_read == b"<":
        # Start of message. Start accumulating bytes, but don't record the "<".
        message = []
        message_started = True
        continue

    if message_started:
        if byte_read == b">":
            # End of message. Don't record the ">".
            # Now we have a complete message. Convert it to a string, and split it up.
            print(message)
            message_parts = "".join(message).split(",")
            message_type = message_parts[0]
            message_started = False
```

Now that the packet is easily readable, the code checks to see what type of packet it is. If it's a light sensor value, it converts the light sensor value to an integer out of 10. It then turns on the NeoPixels based on that value.

If the packet contains instructions for brightness, the code then raises or lowers the brightness of the NeoPixels accordingly.

At the end of the file, and moving out one level, the code adds the byte it has just read to the&nbsp;`message` variable.

```python
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀if message_parts[0] == "L":
                # Received a message telling us a light sensor value
                peak = int(((int(message_parts[1]) - 2000) / 62000) * 10)
                for i in range(0, 10):
                    if i <= peak:
                        pixels[i] = (0, 255, 0)
                    else:
                        pixels[i] = (0, 0, 0)
                pixels.show()
                print(f"Received light value of {message_parts[1]}")
                print(f"Lighting up {peak + 1} NeoPixels")

            elif message_parts[0] == "B":
                # Received a message asking us to change our brightness.
                if message_parts[1] == "True":
                    pixels.brightness = max(0.0, pixels.brightness - 0.1)
                    print(f"Brightness set to: {pixels.brightness}")
                if message_parts[2] == "True":
                    pixels.brightness = min(1.0, pixels.brightness + 0.1)
                    print(f"Brightness set to: {pixels.brightness}")

        else:
            # Accumulate message byte.
            message.append(chr(byte_read[0]))
```


## Guide Products

### Circuit Playground Express

[Circuit Playground Express](https://www.adafruit.com/product/3333)
 **Circuit Playground Express** is the next step towards a perfect introduction to electronics and programming. We've taken the original Circuit Playground Classic and made it even better! Not only did we pack even more sensors in, we also made it even easier to...

In Stock
[Buy Now](https://www.adafruit.com/product/3333)
[Related Guides to the Product](https://learn.adafruit.com/products/3333/guides)
### Colorful Clips - Tropical Alligator Test Clip Leads - 10 Pieces

[Colorful Clips - Tropical Alligator Test Clip Leads - 10 Pieces](https://www.adafruit.com/product/5152)
[Designed by Making & Hacking extraordinaire Lee Cyborg](http://leecyb.org/), these colorful clips are a nice switch-up from the standard colors. Connect this to that without soldering using these _Hot GitHub Summer_&nbsp;alligator clip test leads that look...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/5152)
[Related Guides to the Product](https://learn.adafruit.com/products/5152/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)

## Related Guides

- [Adafruit Circuit Playground Express](https://learn.adafruit.com/adafruit-circuit-playground-express.md)
- [PyLeap CLUE Sensor Plotter](https://learn.adafruit.com/pyleap-clue-sensor-plotter.md)
- [ABC Soundboards with NeoTrellis](https://learn.adafruit.com/abc-soundboards-with-neotrellis.md)
- [Zombie Tag Game with Circuit Playground Express](https://learn.adafruit.com/circuit-playground-express-ir-zombie-game.md)
- [Sparky the Blue Smoke Monster Automaton](https://learn.adafruit.com/sparky-automaton.md)
- [NeoTrellis M4 Noisy Grains of Sand](https://learn.adafruit.com/neotrellism4sand.md)
- [PyPortal Quarantine Clock](https://learn.adafruit.com/pyportal-quarantine-clock.md)
- [Tiny Museum Tour Device](https://learn.adafruit.com/tiny-museum-tour-device.md)
- [No-Touch Hand Wash Timer for Circuit Playground Express and CLUE](https://learn.adafruit.com/no-touch-hand-wash-timer-for-cpx-and-clue.md)
- [Reindeer Mask with Animated Eyes](https://learn.adafruit.com/reindeer-mask-with-animated-eyes.md)
- [CLUE BLE MIDI Glove](https://learn.adafruit.com/clue-midi-glove.md)
- [Crickit Powered Dancin' Snowman!](https://learn.adafruit.com/crickit-powered-dancin-snowman.md)
- [Clue Coffee Scale](https://learn.adafruit.com/clue-coffee-scale.md)
- [PyPortal YouTube Views and Subscribers Display](https://learn.adafruit.com/pyportal-youtube-views-and-subscribers-display.md)
- [IoT Temperature Logger with Analog Devices ADT7410, Feather and Adafruit IO](https://learn.adafruit.com/iot-temperature-logger-with-arduino-and-adafruit-io.md)
- [Remote Control Tree Ornament with Circuit Playground Express](https://learn.adafruit.com/remote-control-tree-ornament-with-circuit-playground-express.md)
