# Adafruit Circuit Playground Express Cheatsheet This is a cheatsheet for getting up and going with the [Adafruit Circuit Playground Express](https://learn.adafruit.com/adafruit-circuit-playground-express) using [CircuitPython](https://circuitpython.org). ## 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](https://codewith.mu/) or install via [brew](https://brew.sh/): `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](https://circuitpython.org/libraries). ## 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](https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-built-ins). ### My code runs once and stops! Stick an infinite loop in there, e.g. ```python while True: print('Ka pai') ``` ### My code runs too fast! Have you considered sleeping for a bit? ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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! ```python 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](https://circuitpython.readthedocs.io/projects/circuitplayground/en/latest/api.html). To detect tapping: ```python from adafruit_circuitplayground.express import cpx cpx.detect_taps = 2 while True: if cpx.tapped: print("Tapped!") ``` Or, for shaking: ```python 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: ```python 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? ```python 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. ```python 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. ```python 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) ```