Skip to content

Instantly share code, notes, and snippets.

@jshiell
Last active February 14, 2022 10:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jshiell/04468c5bb118e3a85b36616e7a9c35fa to your computer and use it in GitHub Desktop.
Save jshiell/04468c5bb118e3a85b36616e7a9c35fa to your computer and use it in GitHub Desktop.
Adafruit Circuit Playground Express Cheatsheet

Adafruit Circuit Playground Express Cheatsheet

This is a cheatsheet for getting up and going with the Adafruit Circuit Playground Express using CircuitPython.

Setup

How can I work out what version of Circuit Python I'm using?

When you plug the device into a USB port it should mount a drive called CircuitPy. In the root of this drive should reside a file called boot_out.txt. This will contain version information for the device, e.g.

Adafruit CircuitPython 4.1.2 on 2019-12-18; Adafruit CircuitPlayground Express with samd21g18

Our devices should all be preconfigured with CircuitPython 4.1.

How can I get a serial console?

You can either use the Adafruit recommended editor, Mu Editor, or directly connect to the serial console via the terminal. This allows you to see output from print commands, and to restart the device (Control-D) or use the REPL (any other key).

Mu Editor

  • Download Mu Editor or install via brew: brew cask install mu-editor
  • Connect the device via USB. A drive called CircuitPy should mount.
  • Open Mu Editor.
  • Click the Serial button.
  • A panel should appear at the bottom with the console output, which should look something like: Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Terminal

  • Connect the device via USB. A drive called CircuitPy should mount.
  • Find the device name. On the Mac, ls /dev/tty.usbmodem* should list possible devices; on Linux, ls /dev/ttyACM* should do the same.
  • Connect to the device, e.g. using screen: screen /dev/tty.usbmodem14301 115200, changing device name as appropriate.
  • A panel should appear at the bottom with the console output, which should look something like: Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
  • You can use Control-A, D to exit screen.

Editing Text

You can edit the code using any text editor. When you connect the device via USB a drive called CircuitPy will mount. Edit main.py in the root of this drive.

Adding Additional Files

You can make other files available, e.g. audio files, by simply copying them to the CircuitPy drive.

Installing Libraries

Should you need any libraries which are not pre-installed then you can just add them to the lib directory in the root of the CircuitPy drive.

The pre-packaged libraries are available on the CircuitPython website.

Writing Code

What is CircuitPython?

It's an embedded runtime based on Python 3. You can do a lot (but not all) of Python 3.

My code runs once and stops!

Stick an infinite loop in there, e.g.

while True:
  print('Ka pai')

My code runs too fast!

Have you considered sleeping for a bit?

import time

while True:
  print('Langsamer, bitte')
  time.sleep(0.1)

My LEDs flash and then go out?

Did you put a loop in? The board will enter a clear state once the end of the script is reached. If you want to hold the last state then just enter a blank loop, e.g.

while True:
  time.sleep(0.1)

How-to

How do I control the primary LED?

This is the LED opposite the power LED, next to the USB socket. Here we turn it on.

import board
import digitalio
import time

led = digitalio.DigitalInOut(board.D13)
led.switch_to_output()

led.value = True

while True:
  time.sleep(0.1)

How do I control a coloured LED?

You can use the NeoPixel library to control the ten coloured LEDs.

import neopixel
import board
import time

pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
pixels.fill((0, 0, 0))
pixels.show()

offset = 0
while True:
  colours = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
  for i in range(0, 10, 1):
    pixels[i] = colours[(offset + i) % len(colours)]
  pixels.show()
  offset = (offset + 1) % 10
  time.sleep(0.5)

How do I use the push-buttons?

You can use the digitalio library to access the two push-buttons.

import board
import digitalio
import time 
import neopixel

pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
pixels.fill((0, 0, 0))
pixels.show()
 
button_a = digitalio.DigitalInOut(board.BUTTON_A)
button_a.switch_to_input(pull=digitalio.Pull.DOWN)

button_b = digitalio.DigitalInOut(board.BUTTON_B)
button_b.switch_to_input(pull=digitalio.Pull.DOWN)
 
while True:
  pixels.fill((0, 0, 0))
  if button_a.value:
    pixels[0] = (0, 255, 0)
  if button_b.value:
    pixels[9] = (0, 255, 0)
  pixels.show()
 
  time.sleep(0.01)

How do I use the slide switch?

Like the push-buttons, this is exposed via digitalio. The following will light up one side of the board, depending on which side the switch is on.

import board
import digitalio
import time 
import neopixel

pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2, auto_write=False)
pixels.fill((0, 0, 0))
pixels.show()
 
switch = digitalio.DigitalInOut(board.SLIDE_SWITCH)
switch.direction = digitalio.Direction.INPUT
switch.pull = digitalio.Pull.UP
 
while True:
  pixels.fill((0, 0, 0))
  if switch.value:
    led_range = range (0, 5, 1)
  else:
    led_range = range (5, 10, 1)

  for i in led_range:
    pixels[i] = (0, 255, 0)
  pixels.show()
 
  time.sleep(0.01)

How can I read the capacitive touch-sensors?

The holes around the edge of the board can be used to wire up external devices to the board, but most of them also work as capacitive touch-sensors. If you can't get your fingers in there then try something metal, like scissors.

import time
import board
import touchio
 
touch_A1 = touchio.TouchIn(board.A1)
touch_A2 = touchio.TouchIn(board.A2)
touch_A3 = touchio.TouchIn(board.A3)
touch_A4 = touchio.TouchIn(board.A4)
touch_A5 = touchio.TouchIn(board.A5)
touch_A6 = touchio.TouchIn(board.A6)
touch_TX = touchio.TouchIn(board.TX)
 
while True:
  if touch_A1.value:
    print("A1 touched!")
  if touch_A2.value:
    print("A2 touched!")
  if touch_A3.value:
    print("A3 touched!")
  if touch_A4.value:
    print("A4 touched!")
  if touch_A5.value:
    print("A5 touched!")
  if touch_A6.value:
    print("A6 touched!")
  if touch_TX.value:
    print("TX touched!")
 
  time.sleep(0.01)

How do I use the light sensor?

The light sensor returns a 16-bit unsigned value (0 to 65535) representing the amount of light - higher is more. The sensor is marked with an eye symbol on the board.

import time
import board
import analogio
 
light = analogio.AnalogIn(board.LIGHT)
 
while True:
  print(light.value)
  time.sleep(1.0)

How can I map a value to the LEDs?

We can use simpleio.map_range to map a sensor range to the number of LEDs, done here with the light sensor.

import time
import board
import neopixel
import analogio
import simpleio
 
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=.05, auto_write=False)
pixels.fill((0, 0, 0))
pixels.show()
 
light = analogio.AnalogIn(board.LIGHT)
 
while True:
  # transform light value to LED range - higher values are lighter
  peak = simpleio.map_range(light.value, 2000, 62000, 0, 9)
    
  for i in range(0, 9, 1):
    if i <= peak:
      pixels[i] = (0, 255, 0)
    else:
      pixels[i] = (0, 0, 0)
    pixels.show()
 
    time.sleep(0.1)

How can I read the temperature sensor?

The temperature sensor returns a value in degrees centigrade.

import time
import adafruit_thermistor
import board
 
thermistor = adafruit_thermistor.Thermistor(board.TEMPERATURE, 10000, 10000, 25, 3950)
 
while True:
  temp_c = thermistor.temperature
  print("Temperature is: %fC" % temp_c)
  time.sleep(1.0)

How can I play a sound?

You can generate a waveform and play it.

import time
import array
import math
import board
import digitalio
 
from audioio import WaveFile, AudioOut, RawSample
 
FREQUENCY = 440  # 440 Hz middle 'A'
SAMPLERATE = 8000  # 8000 samples/second, recommended!
 
# Generate one period of sine wave
length = SAMPLERATE // FREQUENCY
sine_wave = array.array("H", [0] * length)
for i in range(length):
  sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
 
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.direction = digitalio.Direction.OUTPUT
speaker_enable.value = True
 
audio = AudioOut(board.SPEAKER)
sine_wave_sample = RawSample(sine_wave)
 
# Play sine wave for one second
audio.play(sine_wave_sample, loop=True)
time.sleep(1)
audio.stop()

How can I play an audio file?

You can play simple WAV files with the built-in libraries.

import time
import board
import digitalio

from audioio import WaveFile, AudioOut

speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.direction = digitalio.Direction.OUTPUT
speaker_enable.value = True

audio = AudioOut(board.SPEAKER)

while True:
  file = open('sample.wav', 'rb')
  wave_file = WaveFile(file)
  audio.play(wave_file)
  time.sleep(0.5)

How can I use the microphone?

You can sample data from the microphone, however we aware you don't have a lot of memory to play with!

import time
import array
import audiobusio
import board
import neopixel

NUM_SAMPLES = 160

mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA,
                       sample_rate=16000, bit_depth=16)

samples = array.array('H', [0] * NUM_SAMPLES)

while True:
  mic.record(samples, len(samples))
  print(samples)
  time.sleep(1.0)

How can use the accelerometer?

The built-in libraries make this pretty trivial.

Warning: the adafruit_circuitplayground.express library wraps a lot of the functionality of the board, and may conflict with code that doesn't use it. In particular, it takes control of the speaker, so code that tries to use board.SPEAKER may not work. You can instead access the audio functions via the library.

To detect tapping:

from adafruit_circuitplayground.express import cpx
 
cpx.detect_taps = 2
 
while True:
    if cpx.tapped:
        print("Tapped!")

Or, for shaking:

import time

from adafruit_circuitplayground.express import cpx

while True:
  if cpx.shake(shake_threshold=20):
    print("Shake detected!")
    cpx.pixels.fill((150, 0, 0))
    time.sleep(5.0)
  else:
    cpx.pixels.fill((0, 0, 0))

Or for raw acceleration data:

import time
from adafruit_circuitplayground.express import cpx
 
while True:
  x, y, z = cpx.acceleration
  print((x, y, z))
  time.sleep(0.5)

How can I become a USB keyboard?

import time
import board
import usb_hid

from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode
from digitalio import DigitalInOut, Direction, Pull
 
buttonpins = [board.BUTTON_A, board.BUTTON_B]
buttons = []

buttonkeys = [(Keycode.A, Keycode.SHIFT), ("Hello World!\n", None)]
 
kbd = Keyboard()
layout = KeyboardLayoutUS(kbd)
 
for pin in buttonpins:
  button = DigitalInOut(pin)
  button.direction = Direction.INPUT
  button.pull = Pull.DOWN
  buttons.append(button)
 
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT

while True:
  for button in buttons:
    if button.value:
      i = buttons.index(button)
      print("Button #%d Pressed" % i)
 
      led.value = True
 
      while button.value:
        pass
            
      (key_code, control_key) = buttonkeys[i]
      if isinstance(key_code, str):
        layout.write(key_code)
      else:
        if control_key is not None:
          kbd.press(key_code, control_key)
        else:
          kbd.press(key_code)
        kbd.release_all()

        led.value = False
 
  time.sleep(0.1)

How can I use the infrared sensors?

You'll need two devices for this one. The sensors are on the top of the device.

The receiver listens for volume up/down events.

import pulseio
import board
import adafruit_irremote

pulsein = pulseio.PulseIn(board.IR_RX, maxlen=120, idle_state=True)
decoder = adafruit_irremote.GenericDecode()
 
while True:
  pulses = decoder.read_pulses(pulsein)
  try:
    received_code = decoder.decode_bits(pulses)
  except adafruit_irremote.IRNECRepeatException:
    continue
  except adafruit_irremote.IRDecodeException as e:
    continue

  print("NEC Infrared code received: ", received_code)
  if received_code == [255, 2, 255, 0]:
    print("Received NEC Vol-")
  elif received_code == [255, 2, 191, 64]:
    print("Received NEC Vol+")

And the transmitter sends them when one of the push buttons is pressed.

import time
from adafruit_circuitplayground.express import cpx
import adafruit_irremote
import pulseio
import board
 
pwm = pulseio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=2 ** 15)
pulseout = pulseio.PulseOut(pwm)
encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], one=[550, 550], zero=[550, 1700], trail=0)
 
while True:
  if cpx.button_a:
    print("Sending NEC Vol-\n")
    cpx.red_led = True
    encoder.transmit(pulseout, [255, 2, 255, 0])
    cpx.red_led = False
    # wait so the receiver can get the full message
    time.sleep(0.2)
  if cpx.button_b:
    print("Sending NEC Vol+\n")
    cpx.red_led = True
    encoder.transmit(pulseout, [255, 2, 191, 64])
    cpx.red_led = False
    time.sleep(0.2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment