ICM Final Code with Pcomp Final
I worked with Sydney Meyers on my pcomp final for which we used code in Arduino to control a control panel and a grid of neopixels.
In the below code we are adding the Adafruit NeoPixel and NeoTrellis libraries. We included math.h so that we could access the floor and ceiling when we were dividing up our neopixel matrix. AVR came from the neopixel library.
We need to define our LED digital input pin on the Arduino and then how many pixels per strip we are using and how many strips of neopixels we are using.
#include "Adafruit_NeoPixel.h" #include "Adafruit_NeoTrellis.h" #include <math.h> #ifdef __AVR__ #include <avr/power.h> #endif #define LED_PIN 6 #define PIXELS_PER_STRIP 15 #define NUM_STRIPS 15
Below we need to initialize characters and booleans. The Adafruit library initializes the number of pixels per strip, the number strips, the digital input pin, the RGB value and the type of signal to communicate. And we are initializing the trellis class which is defined in the NeoTrellis library.
Adafruit_NeoPixel pixels(PIXELS_PER_STRIP*NUM_STRIPS, LED_PIN, NEO_GRB + NEO_KHZ800); char data[100]; // for debugging print statements with sprintf bool trellisKeys[NEO_TRELLIS_NUM_KEYS] = ; int formerButton = 0; int buttonState = 0; Adafruit_NeoTrellis trellis;
Below we used a function from the NeoTrellis library that checks to see if the pad is being pressed and sets the color of the keys when they are pressed.
TrellisCallback blink(keyEvent evt) { // Check is the pad pressed? if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) { if (trellisKeys[evt.bit.NUM] == false) { trellisKeys[evt.bit.NUM] = true; trellis.pixels.setPixelColor(evt.bit.NUM, 255, 255, 255); //white trellis keys } else { trellis.pixels.setPixelColor(evt.bit.NUM, 0); //off falling trellisKeys[evt.bit.NUM] = false; } } trellis.pixels.show(); return 0; }
Here we are setting up everything.
We define the pin input for our reset button
We begin serial communication
The rest of the code we pulled from the NeoPixel “basic strand test” and the NeoTrellis “basic test”. We edited the code so that it fit our needs. We changed the color around quite a bit.
void setup() { pinMode (2, INPUT); //pixels Serial.begin(9600); #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) clock_prescale_set(clock_div_1); #endif pixels.begin(); // TRELLIS if (!trellis.begin()) { //Serial.println("Could not start trellis, check wiring?"); while (1); } else { //Serial.println("NeoPixel Trellis started"); } //activate all keys and set callbacks for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { trellis.activateKey(i, SEESAW_KEYPAD_EDGE_RISING); // trellis.activateKey(i, SEESAW_KEYPAD_EDGE_FALLING); trellis.registerCallback(i, blink); } //do a little animation to show we're on for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) { trellis.pixels.setPixelColor(i, Wheel(map(i, 0, trellis.pixels.numPixels(), 0, 255))); trellis.pixels.show(); delay(50); } for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) { trellis.pixels.setPixelColor(i, 0x000000); trellis.pixels.show(); delay(50); } //PIXELS for (int i = 0; i < PIXELS_PER_STRIP * NUM_STRIPS; i++) { pixels.setPixelColor(i, 0x181818); //set to gray light (dimmed so it doesnt pull too much power and turn yellow at the bottom) } pixels.show(); }
Below is our loop, which means that is loops through with every new frame and checks if anything has changed.
We check the button state with a digital read and serial print it for debugging purposes
We check to see if the current button state does not equal the previous button state and the button state equals 1 , if this is true then trigger the reset function, if its not true then don’t do anything.
Then we map our 3 potentiometers:
PotH (Hue value) is attached to A1 in the Arduino and is mapped (0, 1023, 0, 65536) Hue reads at 65536
PotS (Saturation value) is attached to A3 in the Arduino and is mapped from (0, 1023, 0, 255) Saturation reads at 255
PotV (Value value) is attached to A7 and is mapped from (0, 1023, 0, 140). We changed 255 to 140 because full brightness was too bright and resulting in a gradient of color rather than solid color.
We then have serial prints for debugging.
We then check to see if any of the NeoTrellis keys have been switched to true using a for loop. If the state on the NeoTrellis is true then display that grouping on LEDs on the matrix using the values from PotH, PotS, PotV. We are also using modulo and division to figure out the columns and the rows, see picture below.
We then can use serial print to debug
void loop() { buttonState = digitalRead(2); Serial.println(buttonState); if ( buttonState != formerButton && buttonState == 1) { //if former button state does not equal current button state && current button equals 1 reset(); } formerButton = buttonState; int NEWmappedPotH = map(analogRead(A1), 0, 1023, 0, 65536); //HUE int NEWmappedPotS = map(analogRead(A3), 0, 1023, 0, 255); //SATURATION int NEWmappedPotV = map(analogRead(A7), 0, 1023, 0, 140); //VALUE Serial.print(NEWmappedPotH); Serial.print(","); Serial.print(NEWmappedPotS); Serial.print(","); Serial.println(NEWmappedPotV); //ALL TRELLIS KEYS for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { //look through array of trellis keys if (trellisKeys[i] == true) { //if key state is true // use division then modulo to map a 1d array to a 2d array int row = i / 4; // 4 = number of trellis rows int col = i % 4; // 4 = number of trellis columns //effecting color of LED matrix uint32_t rgbcolor = pixels.gamma32(pixels.ColorHSV(NEWmappedPotH, NEWmappedPotS, NEWmappedPotV)); setGridColor(row, col, rgbcolor); // Serial.print(row); // Serial.print(", "); // Serial.println(col); } } trellis.read(); // interrupt management does all the work! :) pixels.show(); delay(20); //the trellis has a resolution of around 60hz }
The below code was pulled from the NeoTrellis “basic test” code and makes a quick light animation on the NeoTrellis when it is first turned on. This if a helpful visual queue to know if the NeoTrellis is getting the correct amount of power and it it is plugged into the breadboard correctly.
// Input a value 0 to 255 to get a color value. // The colors are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { if (WheelPos < 85) { return trellis.pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } else if (WheelPos < 170) { WheelPos -= 85; return trellis.pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else { WheelPos -= 170; return trellis.pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3); } return 0; }
The below code tells the 15x15 pixels matrix which pixels to light up when specific NeoTrellis buttons are activated. We are using ceiling and floor to help us divide 15 (pixels) by 4 (buttons).
We also have math that helps us move through the 225 pixels as they snake through our matrix, we are flipping from positive to negative with each row. See drawing below.
We then have serial print for debugging.
void setGridColor(int row, int col, uint32_t rgbcolor) { // unsigned 32 bit integer can represent 0 to (2^32)-1 // signed 32 bit integer can represent -(2^16) to (2^16)-1 float lightsPerRow = (float)NUM_STRIPS / 4.0; int startRow = (int)max(0, floor(lightsPerRow * row)); int endRow = (int)min(NUM_STRIPS, ceil(lightsPerRow * (row + 1))); float lightsPerCol = (float)PIXELS_PER_STRIP / 4.0; int startCol = (int)max(0, floor(lightsPerCol * col)); int endCol = (int)min(PIXELS_PER_STRIP, ceil(lightsPerCol * (col + 1))); // sprintf(data, "Selected (%d, %d)", row, col); // Serial.println(data); // // Serial.println(NUM_STRIPS / 4.0); // sprintf(data, "\tRows %d - %d (%f lights per row)", startRow, endRow, lightsPerRow); // Serial.println(data); // sprintf(data, "\tCols %d - %d (%f lights per col)", startCol, endCol, lightsPerCol); // Serial.println(data); // sprintf(data, "\tSet to color %d", rgbcolor); // Serial.println(data); //Dealing with the way the pixels are assembled on the lightwall to account for the squiggle for (int r = 0; r < NUM_STRIPS; r++) { for (int c = 0; c < PIXELS_PER_STRIP; c++) { if (r >= startRow && r < endRow && c >= startCol && c < endCol) { int pixelIndex; if (r % 2 == 0) { //math to map back from the 2d index to a 1d index pixelIndex = r * PIXELS_PER_STRIP + c; } else { //reverse math to accomodate the snaking of LEDs pixelIndex = (r + 1) * PIXELS_PER_STRIP - c - 1; } //sprintf is a serial print format // sprintf(data, "\tSetting pixel %d to color %d", pixelIndex, rgbcolor); // Serial.println(data); pixels.setPixelColor(pixelIndex, rgbcolor); } } } }
Lastly we are defining our reset function for the reset button.
First we use a for loop to turn the NeoTrellis reading to false.
We then set the trellis key lights to off, hex code 000000
We then set the neopixels to a dim white hex code 181818
void reset() { pixels.begin(); for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { trellisKeys[i] = false; } for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) { trellis.pixels.setPixelColor(i, 0x000000); trellis.pixels.show(); delay(50); } //PIXELS for (int i = 0; i < PIXELS_PER_STRIP * NUM_STRIPS; i++) { pixels.setPixelColor(i, 0x181818); //set to gray light (dimmed so it doesnt pull too much power and turn yellow at the bottom) } pixels.show(); }