Back to the basics: Arduino, Interrupts, Joystick, Button, NeoPixel!
2021-10-01 | By Fredy Martinez
License: Public Domain Arduino
Sometimes going back to the basics is a great way to start the day. It is very easy to get caught up with the final product without realizing the small steps needed to reach it. In this project we will be using an Arduino Uno and using basic interrupt logic to create a nice lightshow.
Justification
With the semester starting up I wanted to create a project that would provide me with a quick refresher. Arduino is a commonly used microcontroller, while the components used: a joystick, LED ring, and button are easily found parts that most have access to.
Bill of Materials
- Arduino Uno
$22.0
https://www.digikey.com/en/products/detail/arduino/A000066/2784006
- Neo Pixel Ring
$11.95
https://www.digikey.com/en/products/detail/adafruit-industries-llc/2856/5878296
- 2-Axis Joystick
$3.95
https://www.digikey.com/en/products/detail/sparkfun-electronics/COM-09032/6823623
- Buttons
$3.99
https://www.digikey.com/en/products/detail/osepp-electronics-ltd/LS-00001/11198555
- Breadboard
$4.99
https://www.digikey.com/en/products/detail/digilent-inc/240-131/7916812
- Jumper Wire
$2.00
https://www.digikey.com/en/products/detail/sparkfun-electronics/PRT-12794/5993859
Other Useful Information
Project Description
The first step after collecting all the materials you will need is to wire the components up. Begin by connecting the Arduino 5V and GND pins to the breadboard. This will power the rails and will make powering the joystick, button, and LED ring easier. Next populate the board with the joystick and the button. The joystick is a 5 pin, 2-axis, analog sensor while the button is a 3-pin digital sensor. Using the rails power both these sensors, (5V to +5V of joystick and VCC of button), do the same for their corresponding GND connections. Next, wire the joysticks VRx and VRy to A0 and A1 (any other analog pin is fine but code should be changed to match). The last pins on both sensors correspond to the buttons, the joystick can also be used as a button with input coming from its SW pin. Wire the SW pin to digital pin 2 and the button OUT pin to digital pin 3.
The last step is to wire the LED ring, begin by wiring the power and GND to the corresponding rails. Lastly, wire the Data Input pin to digital pin 6 ( any can be used except 2 and 3, and code most reflects this change)
Once all the wiring is done, connect the arduino to the arduino IDE and run the code below. The code uses the above wiring, so any change made to the wiring should be manually changed in the code. This project was built using smaller sets of code which tied into the final product. I first began by testing the joystick, this allowed me to verify the high, neutral, and low position values. Next, I tested the NeoPixel LEDs in order to get familiar with how to communicate with them. The ring is a very diverse item that can be used in multiple projects. For more information on how to communicate with them, check out the library in detail. Lastly, this project uses interrupts instead of constantly polling the button sensors. Interrupts are important as explained in the All About Cirucit’s tutorial.
“An Interrupt’s job is to make sure that the processor responds quickly to important events. When a certain signal is detected, an Interrupt (as the name suggests) interrupts whatever the processor is doing, and executes some code designed to react to whatever external stimulus is being fed to the Arduino. Once that code has wrapped up, the processor goes back to whatever it was originally doing as if nothing happened!“
This was tested by simplify using both interrupt vectors and printing out when one was used. Once all the small parts of this project were tested and verified we moved to integrating it all together. Check out the final product in the demo video.
Code
#include <Adafruit_NeoPixel.h>
#define PIN 6
const int VRyPin = A0;
const int VRxPin = A1;
const int buttonPin = 2;
const int smallBPin = 3;
int VRx = 0; // value read from the horizontal pot
int VRy = 0; // value read from the vertical pot
int SW = 0; // value read from the switch
int counter = 0;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(160, PIN, NEO_GRB + NEO_KHZ800);
// variables will change:
volatile int buttonState = 0; // variable for reading the pushbutton status
// 1 500 1024
void setup() {
Serial.begin(9600);
pinMode(buttonPin,INPUT_PULLUP);
// Attach an interrupt to the ISR vector
attachInterrupt(0, button_ISR, CHANGE);
pinMode(smallBPin,INPUT);
attachInterrupt(1, button2_ISR, CHANGE);
strip.begin();
strip.setBrightness(30); //adjust brightness here
strip.show(); // Initialize all pixels to 'off'
// Some example procedures showing how to display to the pixels:
colorWipe(strip.Color(255, 0, 0), 3); // Red
colorWipe(strip.Color(0, 255, 0), 3); // Green
colorWipe(strip.Color(0, 0, 255), 3); // Blue
colorWipe(strip.Color(0, 0, 0), 0); // Blue
strip.show();
}
void loop() {
VRy = analogRead(VRyPin);
if(VRy> 800){
strip.setPixelColor(counter, strip.Color(255, 0, 0));
strip.show();
strip.setPixelColor((counter-1), strip.Color(0, 0, 0));
strip.show();
counter = (counter + 1);
delay(5);
}
if(VRy < 300){
strip.setPixelColor(abs(counter), strip.Color(0, 255, 0));
strip.show();
strip.setPixelColor((abs(counter)+1), strip.Color(0, 0, 0));
strip.show();
counter = (counter-16);
delay(5);
}
}
void button_ISR() {
colorWipe(strip.Color(0, 0, 0), 1); // Blue
strip.show();
}
void button2_ISR() {
rainbowCycle(1);
strip.show();
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum