Seeking help with programming Adafruit pro trinket + Neopixels and Audio FX board

Raekalia

New Member
Hey all, I posted this on the Adafruit forum as well but if there's anyone here who'd be able to help me out, that'd be super awesome <3 I realise this isn't about a specific movie prop but the code would be so useful for my other projects as well if I/ or anyone else wanted to add sound and light to those too! If you want to follow my build, I'm on instagram too @raekalia.props - if you can't help then at least give me a follow so you can watch me struggle and feel that sweet sweet schadenfreude ;)

------


I'm very new to microcontrollers and circuitry in general, this is actually my first project and I've made a lot of progress from the 0% knowledge I started out with 2 weeks ago but I'm a little stuck now...I'm making a weird alien box for university which has reed (magnetic) switch activated lights and sounds. I've followed this guide to a T pretty much in terms of circuitry - https://learn.adafruit.com/ray-gun-blaster

However I'm using 4 switches instead of 1, 2 Neopixel rings rather than 1, stereo rather than mono and I haven't added the laser. When I finished the circuit and input the code, I realised a bit too late that of course the code would only apply to 1 switch instead of the 4 that I have; I'm not yet adept enough to start changing the code more than just the colours and speed of the LEDs so I don't know how to accomodate this code to my circuit. Would anyone be able to help me make this code for 4 switches as opposed to 1 so that I'd be able to play around with different light settings for each switch after? I'm not really sure how easy/difficult this is so please let me know.

// Original Kaleidoscope eyes code from Phillip Burgess.
// Modified to play spinning animation when push button is set to low
//Written by Philip Burgess for Adafruit Industries.
//Adafruit invests time and resources providing this open source code,
//please support Adafruit and open-source hardware by purchasing products
//from Adafruit!
//BSD license, all text above must be included in any redistribution.

#include <Adafruit_NeoPixel.h>

#define PIN 0 //NeoPixel Pin
#define FIREPIN 2 // Fire button

int buttonState = 0; //Default button state

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(12, PIN);


uint8_t offset = 0; // Position of spinny eyes
uint32_t color = 0x00ff5a; // HEX color here
uint32_t prevTime;

void setup() {
pixels.begin();
prevTime = millis();
pinMode(FIREPIN, INPUT_PULLUP); //Button enabler
}

void loop() {
uint8_t i;
uint32_t t;
buttonState = digitalRead(FIREPIN); //Trigger button state
if (buttonState == LOW) { // If button pressed
for(i=0; i<16; i++) { //Run the animation
uint32_t c = 0; //Blank color
if(((offset + i) & 7) < 2) c = color; // 4 pixels on...
pixels.setPixelColor(i, c); //Set the color of pixels
}
pixels.show();
offset++;
}

t = millis();
if((t - prevTime) > 10) { // Every 10th of a second...

for(i=0; i<32; i++) pixels.setPixelColor(i, 0);
prevTime = t;
}

else {
pixels.setPixelColor(i, 0,0,0); //Button not pressed, turn off pixels
pixels.show(); //Show no pixels
delay(25); //duration of spinniness
}
}
 
Last edited by a moderator:
Breaking it down:

* I'm using 4 switches instead of 1,

* 2 Neopixel rings rather than 1,
Will the Neopixels be connected together and function using the same code?

* Stereo rather than mono.
Why Stereo?

* Your QUESTION: Make this code for 4 switches as opposed to 1 (so that I'd be able to play around with different light settings for each switch after).


.
 
Last edited by a moderator:
Yes the neopixel rings are connected together and function using the same code!

I chose Stereo because the box is 25x25x25cm - the sound exits nicely from 2 opposing sides and some of my sfx 'volley' between the speakers. Basically it just sounds cooler hehe

Breaking it down:

* I'm using 4 switches instead of 1,

* 2 Neopixel rings rather than 1,
Will the Neopixels be connected together and function using the same code?

* Stereo rather than mono.
Why Stereo?

* Your QUESTION: Make this code for 4 switches as opposed to 1 (so that I'd be able to play around with different light settings for each switch after).


.
 
Last edited by a moderator:
Re mono/stereo, if you are using the same FX board as given in the Adafruit example, the board is basically agnostic. It will play what you give it for a file; mono, stereo, low bit rate, high bit rate, etc. The main difference is you run out of memory earlier.

As per the buttons;

"buttonState" is the variable which holds the information about if a button has been pressed. It can be easily expanded to hold information on WHICH button has been pressed; the brackets following the "if (buttonState == LOW)" statement can be cloned.

The simplest way is to clone every statement regarding the button; define buttons 1, 2, 3, 4. Initialize (aka pinMode(FIREPIN, INPUT_PULLUP);) buttons 1, 2, 3, 4, read four buttons (buttonState = digitalRead(FIREPIN);) into four buttonStates (aka buttonState1, buttonState2, etc.) and then you have four loops with a test; "if (buttonState1 == LOW)" followed by the specific animation.

Better coding practice is to test for which button is being pressed, including the null test (no buttons are pressed) and read that into a single variable; thus the part of the program containing the lighting animation reads something like;

if (buttonState = 1)
{
play first animation;
}
if (buttonState = 2)
{
play second animation;
}
if (buttonState = 0)
{
turn off all the lights;
}

(The last statement here is the equivalent of the "else {}" in your code example.)



One question you need to ask is if more than one button can even be held down at the same time. That will guide your programming choices.

And, yes, purists would probably argue that setting and testing the button should take place in loops rather than individual lines; things like;

for (i = 1; i < 5; i ++)
{
buttonTest = digitalRead(i)
if (buttonTest > 0)
{
buttonState = i;
}
}

And then you might use switch/case for the different animations. But crawl before you try to walk!
 
Last edited by a moderator:
It was too much for me to do when I was using my work computer on break, but let me see if I can break down some of your sample code for you:

#define FIREPIN 2 // Fire button

//this is an assembler directive (it doesn't exist after the code is compiled). It is basically a wild-card replace; everywhere in your code where "FIREPIN" appears the assembler will plug in the value "2" instead. The reason to do it is to make it easier for you to find all the places where that pin is specified, so you can change it in one place at the top of the code instead of searching for all the occurrences by hand.

int buttonState = 0; //Default button state

This creates the variable buttonState. They've used an INT capable of holding a large value (which can be positive or negative as well). In the same line, it is set to a starting value.

pinMode(FIREPIN, INPUT_PULLUP); //Button enabler

This is another twofer. It tells the Arduino to set the indicated pin as an input pin, and it activate an internal pull-up resistor. The last needs a little explanation. Inputs can "float"; if they are left unconnected they can pick up leakage currents and drift from one state to another. The standard practice is to hold them to a value through a medium-value resistor (pulling "up" to supply or "down" to ground. Then the button or switch or other input hauls the switch the other way; with the internal pull-UP resistor switched on, you ground the pin (aka connect it to the negative lead of the power supply) in order to change the state of the input.

buttonState = digitalRead(FIREPIN); //Trigger button state

This reads the value of the pin you set to "input" in the last line. It is pin #2; remember, wherever FIREPIN appears in the code, it gets replaced by "2" due to the assembler directive we discussed first. Then it assigns that value to the variable we initialized in the next highlighted statement.

if (buttonState == LOW) { // If button pressed

Finally, the first logic of this code. This tests to see if a statement is true, and if so, executes all the code within the following brackets. Since we set the button as INPUT and did a DIGITAL read on it, it can only contain two values; HIGH or LOW, which can also be expressed as 1 or 0, or even TRUE or FALSE. HIGH and LOW are preferred here as it is least semantically ambiguous to the humans building and maintaining the code. Since the input is pulled-up inside the chip (because of the INPUT_PULLUP statement), when the button is pressed it drags the input LOW -- to ground.

And that's all the code concerned with reading buttons or switches in this sample code. The other lines are all concerned with the neoPixel library.
 
Last edited by a moderator:
I hope you don't mind if I reference your post in my uni workbook! Thanks so much for the breakdown - easier to understand what's going on there now
 
Back
Top