Open k1darklord opened 3 months ago
Hey there, so youre building your own GC con?!, very nice!
Are you using an arduino leonardo board right? If so, the pins for the ledstrips are digital pin 2 (D2/PD1) and 3 (D3/PD0):
The analog pins A2 (PF5) and A3 (PF4) were not used originally.
Here is the complete pinout i used for my con:
/* PINOUT (follows Nintendo naming (X=up, B=down)) */
#define PIN_UP 4
#define PIN_DOWN 5
#define PIN_LEFT 6
#define PIN_RIGHT 7
#define PIN_A 11 //XBOX B
#define PIN_B 9 //XBOX A
#define PIN_X 8 //XBOX Y
#define PIN_Y 10 //XBOX X
#define PIN_L 0 //XBOX LB
#define PIN_R 1 //XBOX RB
// Not used
//#define PIN_ZL - //XBOX LT
//#define PIN_ZR - //XBOX RT
//#define PIN_LS - //XBOX LS (left analog click)
//#define PIN_RS - //XBOX RS (right analog click)
#define PIN_PLUS 13 //XBOX START
#define PIN_MINUS A0 //XBOX BACK
#define PIN_HOME A1
#define PIN_L_LED 2
#define PIN_R_LED 3
#define PIN_PLUS_LED 12
If you still want to use A2 and A3 pins, you could change the pin assignation for PIN_L_LED and PIN_R_LED defined pins before flashing the code to your board:
#define PIN_L_LED A2
#define PIN_R_LED A3
I hope that helps you to finish up your build!
Thank you so much for replying to me, I am building the controller and it looks amazing (all my 3d prints are done so its onto the wiring). I tried plugging the Arduino leonardo into my pc with the 5v going to pin +5v ground going to the GND below +5v data going to pin D2 They where the only pins populated on the board to test. The Pc sees it as a switch controller (pokken) and still no lighting. They are 5v WS2812. Are the lights meant to come on when the arduino is plugged into a computer (or switch) or do they come on with a button press? I have no idea why these wont work and thank you for your assistance.
I finished it, I still cannot get the led strips to light (the start button works how it should and lights when pressed).
I did have one problem the inputs where being dropped on quick button presses so I looked into the code and changed this:
Now its really responsive just need to tinker with the fastled code to see if I can make it shine!
Oh its looking fantastic!, well done!
Yes the code its adapted to work as a pokken controller to get nswitch compatibility.
About the led strips, the lights are reactive only (they should light up when you move any of the sticks or press the top buttons on them)
BTW do you have another Leonardo board to test a little script for the leds? (i experienced issues when using with cheap aliexpress led strips in the past, so since then i always test them before using it on any of my diy projects) At any means i will be openong my controller to check the led strip connections to be sure what pins i used at the end (maybe i changed some of them and didnt update the code properly)
I'm not an experienced GC player myself, but i didnt notice any dropped input but if i get better maybe i could start to notice it.
Thanks, I'm really pleased with how it has come out and for a 3d print it feels substantial and not like its about to break! Fantastic design on your part and thank you again for sharing.
I checked for dropped inputs using a Joypad test program and for me there was dropped inputs until I changed that debounce setting, it could well be caused by the microswitches I am using but its sorted spot on now no delay or dropped inputs!
I have tried the LED strip on another Arduino using FastLED example code that animated them no problem. I was playing around with the code as I realised if I mess it up then I can always just put it back to stock really easily and not hurt anything so my plan is to have the lights animated in a circular motion from it being plugged in.
I have a few hours today so time to dip my toe back into coding which I have always found so difficult to understand but if I take my time I may get somewhere. Should I succeed I shall post back to let you know.
I did manage to make it so the start button is illuminated until it is pushed I wonder if it would be possible to make it pulse on and off???
Okay i check my wiring and this is how should you go using my code...
Digital pins 2 & 3: for the led on the left and right top buttons on top of the sticks. Digital pin 12: for the led on the start button on top. Analog pins A2 & A3: are for the left and right led strips DIN point (both led strips should have 8 single leds on it)
So thats its how it goes (sorry for my earlier comment with a wrong pinout indication)
Success! After literal hours of playing around and having close to zero idea what I was doing I managed to junk together working code, I have 16LEDs on each strip (set to low brightness so just in the limit for the Leonardo) and I have managed to get the lights animated spinning and looking all pretty! I could not figure out how to get the start button to pulse which would have been nice but I'm thrilled at where it is from having no lights to really nice lighting.
Here is the code if you want to have a look for yourself at any point and thank you again for such a good project! -
`` /* Groove Coaster Controller Code for Arduino Leonardo and clones
/ in case you want to disable one type of gamepad / //#define DISABLE_XINPUT
//use real analog sticks //#define WITH_ANALOG
// Enable on-the-fly SOCD config. If disabled, itll lock in // the default configuration but still use the SOCD resolution code. // #define ENABLE_SOCD_CONFIG
//make it so holding start+select triggers the HOME button //#define HOME_HOTKEY //delay in ms for start+select to become HOME in HOME_HOTKEY mode
/ PINOUT (follows Nintendo naming (X=up, B=down)) /
// Not used //#define PIN_ZL - //XBOX LT //#define PIN_ZR - //XBOX RT //#define PIN_LS - //XBOX LS (left analog click) //#define PIN_RS - //XBOX RS (right analog click)
typedef struct point_s { int x; int y; } point_t;
typedef struct range_s { point_t min; point_t max; point_t center; } range_t;
range_t g_range_l = {{400, 400}, {600, 600}, {511, 511}}; range_t g_range_r = {{400, 400}, {600, 600}, {511, 511}};
bool g_calibrating = false;
/ Buttons declarations /
unsigned long startAndSelTime = 0; unsigned long currTime = 0;
byte internalButtonStatus[4];
Bounce joystickUP = Bounce(); Bounce joystickDOWN = Bounce(); Bounce joystickLEFT = Bounce(); Bounce joystickRIGHT = Bounce(); Bounce buttonA = Bounce(); Bounce buttonB = Bounce(); Bounce buttonX = Bounce(); Bounce buttonY = Bounce(); Bounce buttonL = Bounce(); Bounce buttonR = Bounce(); // Not used //Bounce buttonZL = Bounce(); //Bounce buttonZR = Bounce(); //Bounce buttonLS = Bounce(); //Bounce buttonRS = Bounce(); Bounce buttonPLUS = Bounce(); Bounce buttonMINUS = Bounce(); Bounce buttonHOME = Bounce();
/ MODE DECLARATIONS / typedef enum { RIGHT_ANALOG_MODE, ANALOG_MODE, DIGITAL, } State_t; State_t state;
typedef enum { NEUTRAL, // LEFT/UP + DOWN/RIGHT = NEUTRAL NEGATIVE, // LEFT/UP beats DOWN/RIGHT POSITIVE, // DOWN/RIGHT beats LEFT/UP LAST_INPUT, //Last input has priority; not a valid state if being used for initial_input } Socd_t; Socd_t x_socd_type = NEUTRAL; // controls left/right and up/down resolution type Socd_t y_socd_type = NEGATIVE; Socd_t x_initial_input, y_initial_input = NEUTRAL;
/ mode selectors / bool xinput; bool modeChanged;
//#define CLK_PIN 4
CRGB leds[NUM_LEDS];
void checkModeChange() { if (buttonStatus[BUTTONSTART] && buttonStatus[BUTTONSELECT]) {
if (buttonStatus[BUTTONL3] && buttonStatus[BUTTONR3])
{
if (!modeChanged)
{
// read inputs at time of press
bool up = !joystickUP.read();
bool down = !joystickDOWN.read();
bool left = !joystickLEFT.read();
bool right = !joystickRIGHT.read();
if (up && down)
y_socd_type = LAST_INPUT;
else if (up)
y_socd_type = NEGATIVE;
else if (down)
y_socd_type = POSITIVE;
else if (!up && !down)
y_socd_type = NEUTRAL;
if (left && right)
x_socd_type = LAST_INPUT;
else if (left)
x_socd_type = NEGATIVE;
else if (right)
x_socd_type = POSITIVE;
else if (!left && !right)
x_socd_type = NEUTRAL;
EEPROM.put(4, x_socd_type);
EEPROM.put(6, y_socd_type);
modeChanged = true;
}
}
else
if ( !modeChanged )
{
bool need_update = true;
if (internalButtonStatus[BUTTONLEFT])
state = ANALOG_MODE;
else if (internalButtonStatus[BUTTONRIGHT])
state = RIGHT_ANALOG_MODE;
else if (internalButtonStatus[BUTTONUP])
state = DIGITAL;
else need_update = false;
if (need_update) EEPROM.put(0, state);
modeChanged = true;
}
else
{
modeChanged = false;
}
} }
void setupPins() { joystickUP.attach(PIN_UP, INPUT_PULLUP); joystickDOWN.attach(PIN_DOWN, INPUT_PULLUP); joystickLEFT.attach(PIN_LEFT, INPUT_PULLUP); joystickRIGHT.attach(PIN_RIGHT, INPUT_PULLUP); buttonA.attach(PIN_A, INPUT_PULLUP); // XBOX B buttonB.attach(PIN_B, INPUT_PULLUP); // XBOX A buttonX.attach(PIN_X, INPUT_PULLUP); // XBOX Y buttonY.attach(PIN_Y, INPUT_PULLUP); // XBOX X buttonL.attach(PIN_L, INPUT_PULLUP); // XBOX LB buttonR.attach(PIN_R, INPUT_PULLUP); // XBOX RB // Not used //buttonZL.attach(PIN_ZL, INPUT_PULLUP); // XBOX LT //buttonZR.attach(PIN_ZR, INPUT_PULLUP); // XBOX RT //buttonLS.attach(PIN_LS, INPUT_PULLUP); // XBOX LS //buttonRS.attach(PIN_RS, INPUT_PULLUP); // XBOX RS buttonPLUS.attach(PIN_PLUS, INPUT_PULLUP); // XBOX START buttonMINUS.attach(PIN_MINUS, INPUT_PULLUP); // XBOX BACK buttonHOME.attach(PIN_HOME, INPUT_PULLUP);
joystickUP.interval(MILLIDEBOUNCE); joystickDOWN.interval(MILLIDEBOUNCE); joystickLEFT.interval(MILLIDEBOUNCE); joystickRIGHT.interval(MILLIDEBOUNCE); buttonA.interval(MILLIDEBOUNCE); buttonB.interval(MILLIDEBOUNCE); buttonX.interval(MILLIDEBOUNCE); buttonY.interval(MILLIDEBOUNCE); buttonL.interval(MILLIDEBOUNCE); buttonR.interval(MILLIDEBOUNCE); // Not used //buttonZL.interval(MILLIDEBOUNCE); //buttonZR.interval(MILLIDEBOUNCE); //buttonLS.interval(MILLIDEBOUNCE); //buttonRS.interval(MILLIDEBOUNCE); buttonPLUS.interval(MILLIDEBOUNCE); buttonMINUS.interval(MILLIDEBOUNCE); buttonHOME.interval(MILLIDEBOUNCE);
pinMode(PIN_L_LED, OUTPUT); pinMode(PIN_R_LED, OUTPUT); pinMode(PIN_PLUS_LED, OUTPUT); pinMode(DATA_PIN1, OUTPUT); pinMode(DATA_PIN2, OUTPUT); }
void setup() {
modeChanged = false; EEPROM.get(0, state); EEPROM.get(2, xinput);
EEPROM.get(4, x_socd_type); EEPROM.get(6, y_socd_type);
setupPins(); delay(500);
/ force Xinput / xinput = true;
/ force nswitch / xinput = false;
/ set xinput mode according to held button / // if select is held on boot, NSWitch mode int value = digitalRead(PIN_MINUS); if (value == LOW) { xinput = false; EEPROM.put(2, xinput); } // if start is held on boot, XInput mode else { value = digitalRead(PIN_PLUS); if (value == LOW) { xinput = true; EEPROM.put(2, xinput); } }
// if (digitalRead(PIN_LS) == LOW) && digitalRead(PIN_RS) == LOW) // { // g_calibrating = true; // }
g_range_l.center.x = analogRead(PIN_LANALOGX); g_range_l.center.y = analogRead(PIN_LANALOGY); g_range_r.center.x = analogRead(PIN_RANALOGX); g_range_r.center.y = analogRead(PIN_RANALOGY);
if (!g_calibrating) { EEPROM.get(8, g_range_l.min.x); EEPROM.get(10, g_range_l.min.y); EEPROM.get(12, g_range_l.max.x); EEPROM.get(14, g_range_l.max.y);
EEPROM.get(16, g_range_r.min.x);
EEPROM.get(18, g_range_r.min.y);
EEPROM.get(20, g_range_r.max.x);
EEPROM.get(22, g_range_r.max.y);
}
SetupHardware(xinput); GlobalInterruptEnable();
FastLED.addLeds<LED_TYPE,DATA_PIN1,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); FastLED.addLeds<LED_TYPE,DATA_PIN2,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
// set master brightness control FastLED.setBrightness(BRIGHTNESS); }
typedef void (*SimplePatternList[])(); SimplePatternList gPatterns = { rainbow, confetti, sinelon, juggle, bpm };
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current uint8_t gHue = 0; // rotating "base color" used by many of the patterns
void loop() {
currTime = millis();
axisRead();
buttonRead(); checkModeChange(); convert_dpad(); send_pad_state(); }
void axisRead() { point_t curr;
// left analog X curr.x = analogRead(PIN_LANALOGX); curr.y = analogRead(PIN_LANALOGY);
if ((curr.x - g_range_l.center.x < DEADZONE) && (curr.x - g_range_l.center.x > -DEADZONE)) buttonStatus[AXISLX] = 127; else if (curr.x < g_range_l.min.x) { g_range_l.min.x = curr.x - 10;
if (g_calibrating)
EEPROM.put(8, g_range_l.min.x);
buttonStatus[AXISLX] = 0;
} else if (curr.x > g_range_l.max.x) { g_range_l.max.x = curr.x + 10; if (g_calibrating) EEPROM.put(12, g_range_l.max.x); buttonStatus[AXISLX] = 255; } else if (curr.x > g_range_l.center.x) { buttonStatus[AXISLX] = map(curr.x, g_range_l.center.x, g_range_l.max.x, 127, 255); } else if (curr.x < g_range_l.center.x) { buttonStatus[AXISLX] = map(curr.x, g_range_l.min.x, g_range_l.center.x, 0, 127); } buttonStatus[AXISLX] *= -1;
if ((curr.y - g_range_l.center.y < DEADZONE) && (curr.y - g_range_l.center.y > -DEADZONE)) buttonStatus[AXISLY] = 127; else if (curr.y < g_range_l.min.y) { g_range_l.min.y = curr.y - 10; if (g_calibrating) EEPROM.put(10, g_range_l.min.y); buttonStatus[AXISLY] = 0; } else if (curr.y > g_range_l.max.y) { g_range_l.max.y = curr.y + 10; if (g_calibrating) EEPROM.put(14, g_range_l.max.y); buttonStatus[AXISLY] = 255; } else if (curr.y > g_range_l.center.y) { buttonStatus[AXISLY] = map(curr.y, g_range_l.center.y, g_range_l.max.y, 127, 255); } else if (curr.y < g_range_l.center.y) { buttonStatus[AXISLY] = map(curr.y, g_range_l.min.y, g_range_l.center.y, 0, 127); } buttonStatus[AXISLY] *= -1;
// right analog
curr.x = analogRead(PIN_RANALOGX); curr.y = analogRead(PIN_RANALOGY);
if ((curr.x - g_range_r.center.x < 50) && (curr.x - g_range_r.center.x > -50)) buttonStatus[AXISRX] = 127; else if (curr.x < g_range_r.min.x) { g_range_r.min.x = curr.x - 10; if (g_calibrating) EEPROM.put(16, g_range_r.min.x); buttonStatus[AXISRX] = 0; } else if (curr.x > g_range_r.max.x) { g_range_r.max.x = curr.x + 10; if (g_calibrating) EEPROM.put(20, g_range_r.max.x); buttonStatus[AXISRX] = 255; } else if (curr.x > g_range_r.center.x) { buttonStatus[AXISRX] = map(curr.x, g_range_r.center.x, g_range_r.max.x, 127, 255); } else if (curr.x < g_range_r.center.x) { buttonStatus[AXISRX] = map(curr.x, g_range_r.min.x, g_range_r.center.x, 0, 127); } buttonStatus[AXISRX] *= -1;
if ((curr.y - g_range_r.center.y < 50) && (curr.y - g_range_r.center.y > -50)) buttonStatus[AXISRY] = 127; else if (curr.y < g_range_r.min.y) { g_range_r.min.y = curr.y - 10; if (g_calibrating) EEPROM.put(18, g_range_r.min.y); buttonStatus[AXISRY] = 0; } else if (curr.y > g_range_r.max.y) { g_range_r.max.y = curr.y + 10; if (g_calibrating) EEPROM.put(22, g_range_r.max.y); buttonStatus[AXISRY] = 255; } else if (curr.y > g_range_r.center.y) { buttonStatus[AXISRY] = map(curr.y, g_range_r.center.y, g_range_r.max.y, 127, 255); } else if (curr.y < g_range_r.center.y) { buttonStatus[AXISRY] = map(curr.y, g_range_r.min.y, g_range_r.center.y, 0, 127); } buttonStatus[AXISRY] *= -1;
}
void convert_dpad() { byte cleanButtonStatus[4] = {0}; // Prevent SOCD inputs (left+right or up+down) from making it to the logic below. clean_all_socd(internalButtonStatus, cleanButtonStatus, x_socd_type, y_socd_type);
// force digital mode for dpad (TODO: allow the other modes as well) buttonStatus[BUTTONUP] = cleanButtonStatus[BUTTONUP]; buttonStatus[BUTTONDOWN] = cleanButtonStatus[BUTTONDOWN]; buttonStatus[BUTTONLEFT] = cleanButtonStatus[BUTTONLEFT]; buttonStatus[BUTTONRIGHT] = cleanButtonStatus[BUTTONRIGHT]; return;
switch (state) { case DIGITAL: buttonStatus[AXISLX] = 128; buttonStatus[AXISLY] = 128; buttonStatus[AXISRX] = 128; buttonStatus[AXISRY] = 128; buttonStatus[BUTTONUP] = cleanButtonStatus[BUTTONUP]; buttonStatus[BUTTONDOWN] = cleanButtonStatus[BUTTONDOWN]; buttonStatus[BUTTONLEFT] = cleanButtonStatus[BUTTONLEFT]; buttonStatus[BUTTONRIGHT] = cleanButtonStatus[BUTTONRIGHT]; break;
case RIGHT_ANALOG_MODE:
buttonStatus[AXISLX] = 128;
buttonStatus[AXISLY] = 128;
buttonStatus[BUTTONUP] = 0;
buttonStatus[BUTTONDOWN] = 0;
buttonStatus[BUTTONLEFT] = 0;
buttonStatus[BUTTONRIGHT] = 0;
if ((cleanButtonStatus[BUTTONUP]) && (cleanButtonStatus[BUTTONRIGHT])) {
buttonStatus[AXISRY] = 0;
buttonStatus[AXISRX] = 255;
}
else if ((cleanButtonStatus[BUTTONUP]) && (cleanButtonStatus[BUTTONLEFT])) {
buttonStatus[AXISRY] = 0;
buttonStatus[AXISRX] = 0;
}
else if ((cleanButtonStatus[BUTTONDOWN]) && (cleanButtonStatus[BUTTONRIGHT])) {
buttonStatus[AXISRY] = 255;
buttonStatus[AXISRX] = 255;
}
else if ((cleanButtonStatus[BUTTONDOWN]) && (cleanButtonStatus[BUTTONLEFT])) {
buttonStatus[AXISRY] = 255;
buttonStatus[AXISRX] = 0;
}
else if (cleanButtonStatus[BUTTONUP]) {
buttonStatus[AXISRY] = 0;
buttonStatus[AXISRX] = 128;
}
else if (cleanButtonStatus[BUTTONDOWN]) {
buttonStatus[AXISRY] = 255;
buttonStatus[AXISRX] = 128;
}
else if (cleanButtonStatus[BUTTONLEFT]) {
buttonStatus[AXISRX] = 0;
buttonStatus[AXISRY] = 128;
}
else if (cleanButtonStatus[BUTTONRIGHT]) {
buttonStatus[AXISRX] = 255;
buttonStatus[AXISRY] = 128;
}
else {
buttonStatus[AXISRX] = 128;
buttonStatus[AXISRY] = 128;
}
break;
case ANALOG_MODE:
/* fallthrough */
default:
buttonStatus[AXISRX] = 128;
buttonStatus[AXISRY] = 128;
buttonStatus[BUTTONUP] = 0;
buttonStatus[BUTTONDOWN] = 0;
buttonStatus[BUTTONLEFT] = 0;
buttonStatus[BUTTONRIGHT] = 0;
if ((cleanButtonStatus[BUTTONUP]) && (cleanButtonStatus[BUTTONRIGHT])) {
buttonStatus[AXISLY] = 0;
buttonStatus[AXISLX] = 255;
}
else if ((cleanButtonStatus[BUTTONDOWN]) && (cleanButtonStatus[BUTTONRIGHT])) {
buttonStatus[AXISLY] = 255;
buttonStatus[AXISLX] = 255;
}
else if ((cleanButtonStatus[BUTTONDOWN]) && (cleanButtonStatus[BUTTONLEFT])) {
buttonStatus[AXISLY] = 255;
buttonStatus[AXISLX] = 0;
}
else if ((cleanButtonStatus[BUTTONUP]) && (cleanButtonStatus[BUTTONLEFT])) {
buttonStatus[AXISLY] = 0;
buttonStatus[AXISLX] = 0;
}
else if (cleanButtonStatus[BUTTONUP]) {
buttonStatus[AXISLY] = 0;
buttonStatus[AXISLX] = 128;
}
else if (cleanButtonStatus[BUTTONDOWN]) {
buttonStatus[AXISLY] = 255;
buttonStatus[AXISLX] = 128;
}
else if (cleanButtonStatus[BUTTONLEFT]) {
buttonStatus[AXISLX] = 0;
buttonStatus[AXISLY] = 128;
}
else if (cleanButtonStatus[BUTTONRIGHT]) {
buttonStatus[AXISLX] = 255;
buttonStatus[AXISLY] = 128;
}
else {
buttonStatus[AXISLX] = 128;
buttonStatus[AXISLY] = 128;
}
break;
} // Call the current pattern function once, updating the "leds" array gPatterns[gCurrentPatternNumber]();
// send the "leds" array out to the actual LED strip
FastLED.show();
// insert a delay to keep the framerate modest
FastLED.delay(1000/FRAMES_PER_SECOND);
// do some periodic updates EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically }
void nextPattern() { // add one to the current pattern number, and wrap around at the end gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns); }
void rainbow() { // FastLEDs built-in rainbow generator fill_rainbow( leds, NUM_LEDS, gHue, 7); }
void confetti() { // random colored speckles that blink in and fade smoothly fadeToBlackBy( leds, NUM_LEDS, 10); int pos = random16(NUM_LEDS); leds[pos] += CHSV( gHue + random8(64), 200, 255); }
void sinelon() { // a colored dot sweeping back and forth, with fading trails fadeToBlackBy( leds, NUM_LEDS, 20); int pos = beatsin16( 13, 0, NUM_LEDS-1 ); leds[pos] += CHSV( gHue, 255, 192); }
void bpm() { // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint8_t BeatsPerMinute = 62; CRGBPalette16 palette = PartyColors_p; uint8_t beat = beatsin8( BeatsPerMinute, 64, 255); for( int i = 0; i < NUM_LEDS; i++) { //9948 leds[i] = ColorFromPalette(palette, gHue+(i2), beat-gHue+(i10)); } }
void juggle() { // eight colored dots, weaving in and out of sync with each other fadeToBlackBy( leds, NUM_LEDS, 20); uint8_t dothue = 0; for( int i = 0; i < 8; i++) { leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255); dothue += 32; } }
void buttonRead()
{
// for SOCD cleaning to work properly we need directions to update
// on any change instead of on fall
joystickUP.update(); joystickDOWN.update(); joystickLEFT.update(); joystickRIGHT.update();
if (joystickUP.changed() || joystickDOWN.changed() || joystickLEFT.changed() || joystickRIGHT.changed())
{
internalButtonStatus[BUTTONUP] = !joystickUP.read();
internalButtonStatus[BUTTONDOWN] = !joystickDOWN.read();
internalButtonStatus[BUTTONLEFT] = !joystickLEFT.read();
internalButtonStatus[BUTTONRIGHT] = !joystickRIGHT.read();
}
if (buttonA.update()) {
buttonStatus[BUTTONA] = buttonA.fell();
}
if (buttonR.update()) {
buttonStatus[BUTTONRB] = buttonR.fell();
digitalWrite(PIN_R_LED, LOW);
}
if (buttonR.fell()) {
digitalWrite(PIN_R_LED, HIGH);
}
if (buttonB.update()) {
buttonStatus[BUTTONB] = buttonB.fell();
}
if (buttonX.update()) {
buttonStatus[BUTTONX] = buttonX.fell();
}
if (buttonY.update()) {
buttonStatus[BUTTONY] = buttonY.fell();
}
if (buttonL.update()) {
buttonStatus[BUTTONLB] = buttonL.fell();
digitalWrite(PIN_L_LED, LOW);
}
if (buttonL.fell()) {
digitalWrite(PIN_L_LED, HIGH);
}
// Not used
// if (buttonZL.update()) {
// buttonStatus[BUTTONLT] = buttonZL.fell();
// }
// if (buttonZR.update()) {
// buttonStatus[BUTTONRT] = buttonZR.fell();
// }
// if (buttonLS.update()) {
// buttonStatus[BUTTONL3] = buttonLS.fell();
// }
// if (buttonRS.update()) {
// buttonStatus[BUTTONR3] = buttonRS.fell();
// }
if (buttonPLUS.update()) { buttonStatus[BUTTONSTART] = buttonPLUS.fell(); digitalWrite(PIN_PLUS_LED, HIGH);
}
if (buttonPLUS.fell()) {
digitalWrite(PIN_PLUS_LED, LOW);
}
if (buttonMINUS.update()) { buttonStatus[BUTTONSELECT] = buttonMINUS.fell(); }
if (buttonHOME.update()) { buttonStatus[BUTTONHOME] = buttonHOME.fell(); }
if (buttonStatus[BUTTONSTART] && buttonStatus[BUTTONSELECT]) { if (startAndSelTime == 0) startAndSelTime = millis(); else if (currTime - startAndSelTime > HOME_DELAY) { buttonStatus[BUTTONHOME] = 1; } } else { startAndSelTime = 0; buttonStatus[BUTTONHOME] = 0; }
}
void clean_all_socd(byte internalButtonStatus, byte cleanButtonStatus, Socd_t x_socd_type, Socd_t y_socd_type) { clean_socd(internalButtonStatus[BUTTONLEFT], &cleanButtonStatus[BUTTONLEFT], internalButtonStatus[BUTTONRIGHT], &cleanButtonStatus[BUTTONRIGHT], x_socd_type, &x_initial_input); clean_socd(internalButtonStatus[BUTTONUP], &cleanButtonStatus[BUTTONUP], internalButtonStatus[BUTTONDOWN], &cleanButtonStatus[BUTTONDOWN], y_socd_type, &y_initial_input); } /** Cleans the given (possible) simultaneous opposite cardinal direction inputs according to the preferences provided.
@note Given two simultaneous opposite cardinal direction inputs, clean_socd will make sure that both are not actually sent. The method used to resolve this conflict is determined by input_priority. The x (LEFT/RIGHT) and y (UP/DOWN) axes can be handled with the same logic as long as the negative and positive inputs are correctly arranged, so pointers are used to make the same function handle both.
@param[in] negative_in The LEFT/UP input variable. @param[out] negative_out The LEFT/UP resulting value. @param[in] positive_in The DOWN/RIGHT input variable. @param[out] positive_out The DOWN/RIGHT resulting value. @param[in] input_priority Determines the SOCD resolution method used. @see Socd_t for how each resolution method works. @param[in,out] initial_input If input_priority = LAST_INPUT and SOCD cleaning is needed, this is used to determine which input was made last. If only one input is made, this variable is set to that input, even if input_priority != LAST_INPUT. / void clean_socd(byte negative_in, byte negative_out, byte positive_in, byte positive_out, Socd_t input_priority, Socd_t initial_input) { if (negative_in && positive_in) // SOCD that needs to be resolved { switch (input_priority) { case NEUTRAL: negative_out = positive_out = false; break; case NEGATIVE: negative_out = true; positive_out = false; break; case POSITIVE: negative_out = false; positive_out = true; break; case LAST_INPUT: // Check which input was made first to figure out which input was made last, which wins. switch (initial_input) { case NEGATIVE: negative_out = false; positive_out = true; break; case POSITIVE: negative_out = true; positive_out = false; break; // This is a fallback case for when there hasnt been an input since starting up. case NEUTRAL: negative_out = positive_out = false; break; } } } else // no SOCD to resolve, which means our current input (if any) can be output as is, but also should be remembered as the initial input. { positive_out = positive_in; negative_out = negative_in; if (negative_in && !positive_in) initial_input = NEGATIVE; if (positive_in && !negative_in) *initial_input = POSITIVE; } } ``
Hey, you should post a video on how your leds are going on now, i like the idea of having different led light effects :)
u didnt understand what you want tonachieve with the start button led :o
dont know if this works for a video of the lights or not https://github.com/user-attachments/assets/a674686f-6b66-4e67-bfb0-e8b1f1a4883d
Firstly thank you for your design it is fantastic! I am however having a problem in getting the WS2812 ledstrip to light, I have wired it up to the 5v, gnd and pins a2 and a3 separate data but daisy chained power and ground.
Am I doing something wrong, won't lie I am not very familiar with using an Arduino leonardo so its all very new to me if you could provide any help and if I have posted this in the wrong area sorry.
Thanks for any help you may be able to provide.