We've explained how to use the features in the Adafruit CircuitPython TrellisM4 library. Now we'll show how to use the library to write a CircuitPython program. In this section, you'll learn how to initialise the library for use in your code, and then use Python lists and sets to keep track of LED states and button presses.
This program begins with all the NeoPixels turned off. You can then press the buttons to toggle the associated NeoPixels on and off in a rainbow pattern spread over all of the LEDs.
Imports and Setup
The first thing you need to do is import the library and then set it up for use. This is super simple. You being your program with the following code:
import adafruit_trellism4 trellis = adafruit_trellism4.TrellisM4Express()
This is how you'll begin any program that will be using the TrellisM4 library. You can include other libraries in your code by adding them after the import
line and setting them up after the trellis
line.
wheel
for the Rainbow
Next, a helper function called wheel
is defined. This code allows us to generate the rainbow pattern seen when you toggle all of the buttons on.
def wheel(pos): if pos < 0 or pos > 255: return 0, 0, 0 if pos < 85: return int(255 - pos * 3), int(pos * 3), 0 if pos < 170: pos -= 85 return 0, int(255 - pos * 3), int(pos * 3) pos -= 170 return int(pos * 3), 0, int(255 - (pos * 3))
For more information on how wheel
is used, check out the Wheel Explained section here.
A Set of Button Presses
With basic code, when you press a button, the button press gets sent over and over as long as you hold the button. This happens very quickly, too quickly for you to easily press it once and have the button press sent only once. Since we're trying to use the button as a toggle, we need it to respond only once until it is pressed again. So, we're going to use sets to keep track of which buttons have been pressed.
A set is an unordered collection with no duplicate elements. Since we're not keeping track of the order in which we press the buttons, we don't care that it's unordered. Since a set eliminates duplicates, we don't have to worry about it including the same button press twice. You can use math on sets to do things including subtracting one set from another. Subtracting one set from another provides you with the elements in one set that are not in another. This allows you to determine the difference between the two sets. We will be comparing two sets. So sets are perfect for our needs!
This code creates two sets and then compares them. This allows for us to keep track of the buttons currently being pressed and compare them to to the buttons previously pressed to determine what buttons have been released.
First, we create an empty set
called current_press
. Then we begin our loop and create a set
called pressed
that contains all the buttons being pressed (trellis.pressed_keys
) at the beginning of the loop. If no buttons are pressed, pressed
will be empty.
current_press = set() while True: pressed = set(trellis.pressed_keys) for press in pressed - current_press: ... # LED toggle code lives here. current_press = pressed
At the end of the loop, we set current_press = pressed
so current_press
contains all of the buttons currently pressed when the loop ends. Then, the loop begins again, and we check to see which buttons are being pressed by checking pressed
. This means we now have two sets: one containing the buttons pressed when the loop ended, and one containing the buttons pressed when the loop begins.
Now, we do some math so we can compare the two. press - current_press
will provide a collection of buttons still being pressed, and we can now apply the LED toggle code to only those buttons!
A Multidimensional List of NeoPixel States
This example toggles the NeoPixels on or off when each button is pressed. Whether the pixel is turned on or off is dependent on the pixel's current state; if the pixel is on, the button press turns it off, and if the pixel is off, the button press turns it on. We need to track the current state of every pixel to be able to determine what state to toggle it to. For that, we're going to use a multidimensional list.
A list is a collection of items that are both ordered and changeable. We want to use the (x, y)
coordinates of the pixels to keep track of which pixel is which, so we want to keep all of the list entries in a particular order. We are going to be tracking two states for each pixel, so we need to be able to change each entry in the list to reflect the current state. Lists are exactly what we need!
Since we are going to be using (x, y)
coordinates of the pixels to determine which pixel we are addressing, we need to create a list that is a representation of the NeoPixel grid. For this, we need to create a multidimensional list, which is a list made up of lists.
First we create the initial list and call it led_on
.
led_on = []
If you were to print(led_on)
, it would look like this:
[]
Then we create the multidimensional aspect of the list. We use append
to add width
number of empty lists to the initial list, and then we populate them with height
number of entries, which we're setting to False
because the LEDs are not on to begin with. As we initialised the Trellis without specifying a rotation value, width is equal to 8 and height is equal to 4.
for x in range(trellis.pixels.width): led_on.append([]) for y in range(trellis.pixels.height): led_on[x].append(False)
Let's take a look at the two parts of this section of code.
We append x
, or 8, empty lists to our initial list:
for x in range(trellis.pixels.width): led_on.append([])
If you were to print(led_on)
now, it would look like this:
[[], [], [], [], [], [], [], []]
Then we append four entries of False
to each of the x
empty lists:
for y in range(trellis.pixels.height): led_on[x].append(False)
Finally, if you were to print(led_on)
now, it would look like this:
[[False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False]] [False, False, False, False]]
Each four member list represents an x
coordinate, 0 - 7. Each False
represents a y
coordinate, 0 - 3. For example, if (3, 2)
were set to True
, the list would look like this:
[[False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, True, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [False, False, False, False]] [False, False, False, False]]
Now we have our representation of the NeoPIxel grid and we can start toggling!
Extra Credit: List Comprehensions
We used five lines of code to create our list. It was easy to see what was happening in each section of code, and to explain how it was affecting the creation of our list. It turns out, however, that there's a way to do it in one line of code!
List comprehensions provide a more concise way to create lists. They consist of brackets containing an expression followed by a for
clause, potentially followed by further for
or if
clauses. As you can see, we used two for
clauses in our list creation code. Our list comprehension consists of two for
clauses as well.
You can replace every line of code discussed in the previous section with the following line:
led_on = [[False for y in range(trellis.pixels.height)] for x in range(trellis.pixels.width)]
It does exactly the same thing as the code in the previous section: creates a multidimensional list made up of x
lists, each containing y
entries of False
. And, it's much shorter. Handy!
NeoPixels On: True or False?
Now that we have our button presses tracked and our multidimensional list, we can easily toggle the NeoPixels. We're going to use the list to track whether they are on or off. Each time we press a button, we'll check to see whether it's associated list entry is True
or False
, If it's False
, that means the LED is currently off. If it's True
, it means the LED is currently on. Based on these results, that button press will change the list entry and turn the LED to the appropriate status. Let's take a look!
Here is our LED toggle code:
x, y = press if not led_on[x][y]: print("Turning on:", press) pixel_index = ((x + (y * 8)) * 256 // 32) trellis.pixels[x, y] = wheel(pixel_index & 255) led_on[x][y] = True else: print("Turning off:", press) trellis.pixels[x, y] = (0, 0, 0) led_on[x][y] = False
press
is already an x, y
coordinate, but we need to have access to x
and y
separately. So, we first unpack press
with x, y = press
.
We need access to x
and y
to use our list. Remember, we're using a multidimensional list containing x
number of lists made up of y
number. of entries. So, to access them, we'll use led_on[x][y]
.
Next, we have an if/else
block. The if not led_on[x][y]:
says if the led_on
list entry found at [x][y]
is False
, run the code indented below it. The else
says, "otherwise," which is to say, if the led_on
list entry found at [x][y]
is True
, run the code indented below it.
If the list entry is False
when we press a button, we send a print
statement, turn on the LED associated with that button to the rainbow color that matches it's location in the rainbow spread over all the buttons. Then, we set the list entry to True
.
if not led_on[x][y]: print("Turning on:", press) pixel_index = ((x + (y * 8)) * 256 // 32) trellis.pixels[x, y] = wheel(pixel_index & 255) led_on[x][y] = True
If the list entry is True
when we press a button, we send a print
statement, turn the LED associated with that button off. Then, we set the list entry to False
.
else: print("Turning off:", press) trellis.pixels[x, y] = (0, 0, 0) led_on[x][y] = False
You may have noticed that to address the pixels, we use trellis.pixels[x, y]
, but to address the list we use led_on[x][y]
. This is because the NeoPixel code is specially designed to work with an [x, y]
coordinate assignment. The multidimensional list, however, only works by addressing [x]
and [y]
separately.
Whew! That's it! Now it's time to press, press, press!
NeoTrellis M4 NeoPixel Toggle Code
Here's the full program. To use with CircuitPython, you need to first install a few libraries, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, open the directory examples/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.
Your CIRCUITPY drive should now look similar to the following image:
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT from rainbowio import colorwheel import adafruit_trellism4 trellis = adafruit_trellism4.TrellisM4Express() led_on = [] for x in range(trellis.pixels.width): led_on.append([]) for y in range(trellis.pixels.height): led_on[x].append(False) trellis.pixels.fill((0, 0, 0)) current_press = set() while True: pressed = set(trellis.pressed_keys) for press in pressed - current_press: x, y = press if not led_on[x][y]: print("Turning on:", press) pixel_index = (x + (y * 8)) * 256 // 32 trellis.pixels[x, y] = colorwheel(pixel_index & 255) led_on[x][y] = True else: print("Turning off:", press) trellis.pixels[x, y] = (0, 0, 0) led_on[x][y] = False current_press = pressed
Text editor powered by tinymce.