odd behavior from 12 joystick controlled LED outputs

Just as something to do, my goal is to have 4 LEDs “off” while the other 8 LEDS are “on”. I want to be able to slide the off LEDs around the bar using the x-axis of my thumb stick. I have it almost working but as you can see in the gif, but there is some odd behavior on the left side of the bar.

For some reason the left most two LEDS sometimes stay low when the off LEDS slide in that area. When i reset the arduino, they always start out low until the off LEDs slider over them first.

I started off thinking I could easily do this with a for loop. After fiddling with it, the code got kind of convoluted but I couldn’t think of a simpler way to do it. Help with cleaning up my the way I’m going about this would be appreciated too. If not though thats fine, I’m more worried about just getting it working in general.

Here’s a guy of whats going on: https://gfycat.com/HandyParchedBlackrussianterrier

and here’s my code:

#define ELEMENTS(x)  (sizeof(x) / sizeof(x[0]))

int led[] = {2,3,4,5,6,7,8,9,10,11,12,13};

void setup() {
  Serial.begin(9600);
 
for (int i = 0; i < ELEMENTS(led); i++){
   pinMode(led[i], OUTPUT);
  }
}


void loop() {
  
  int xAxis = analogRead(A0);
  
  Serial.println(xAxis);
 
   xAxis = map(xAxis, 0, 1025, 0, 9);
  for (int i = 0; i < ELEMENTS(led); i++){
   
   digitalWrite(led[xAxis], LOW);
   digitalWrite(led[xAxis+1], LOW);
   digitalWrite(led[xAxis+2], LOW);
   digitalWrite(led[xAxis+3], LOW);
   delay(5);
   digitalWrite(led[xAxis+4], HIGH);
   digitalWrite(led[xAxis+5], HIGH);
   digitalWrite(led[xAxis+6], HIGH);
   digitalWrite(led[xAxis+7], HIGH);
   
   digitalWrite(led[xAxis+8], HIGH);
   digitalWrite(led[xAxis+9], HIGH);
   digitalWrite(led[xAxis-1], HIGH);
   digitalWrite(led[xAxis-2], HIGH);

}}
   xAxis = map(xAxis, 0, 1025, 0, 9);

The range of values from analogRead() is 0 to 1023. Since you never get a 1025 as the input value, you'll never get a 9 as the output.

   digitalWrite(led[xAxis-1], HIGH);
   digitalWrite(led[xAxis-2], HIGH);

Which pins are you diddling with when xAxis is 0? When it is 1?

PaulS:

   xAxis = map(xAxis, 0, 1025, 0, 9);

The range of values from analogRead() is 0 to 1023. Since you never get a 1025 as the input value, you'll never get a 9 as the output.

   digitalWrite(led[xAxis-1], HIGH);

digitalWrite(led[xAxis-2], HIGH);



Which pins are you diddling with when xAxis is 0? When it is 1?

I switched the mapping from 1023 to 1025 because when the joystick was all the way right the four LEDS would be all the way to the right of the bar BUT the left most led of the 4 off ones would flicker on and off. By changing the max range of the mapping in the code to 1025 it eliminated that issue.

when the joystick axis is 0 the 4 middle LEDs are off and the rest are active.

from the middle to the left the positions are 4,3,2,1,0. and to the right its 5,6,7,8.

the weird thing is like u see in the gif, sometimes it works. but when i push the joystick back left it activates and deactivates the left most two LEDs at random.

because when the joystick was all the way right

Does "all the way right" mean high values? Or low values?

By changing the max range of the mapping in the code to 1025 it eliminated that issue.

You misspelled "masked that issue by making a more significant issue visible".

but when i push the joystick back left it activates and deactivates the left most two LEDs at random.

Not at random.

When xAxis is 0, you are accessing the pins in the -1 and -2 position of the array. What values are in those positions?

When xAxis is 1, you are accessing the pin in the -1 position of the array. What value is in that position?

PaulS:
Does "all the way right" mean high values? Or low values?
You misspelled "masked that issue by making a more significant issue visible".
Not at random.

When xAxis is 0, you are accessing the pins in the -1 and -2 position of the array. What values are in those positions?

When xAxis is 1, you are accessing the pin in the -1 position of the array. What value is in that position?

joystick all the way right means high values.

yes i did mask the problem hah. but 1023 Vs 1025 has no bearing on the particular issue in the OP, since I was having this issue before i changed it to 1025. I will work on a proper fix when i get the current issue sorted out, thanks!

the left most LEDs are positions 0 and 1 according to the mapped joystick+serial monitor.

I assumed my code was balanced, having this issue on only one said of the LED bar is really odd to me. 12 LEDs total, even number of outputs and all.

You are not answering my questions. You are, under some circumstances, referencing positions in the array that do not exist. Why?

PaulS:
You are not answering my questions. You are, under some circumstances, referencing positions in the array that do not exist. Why?

So the LED array references the actual digital outputs on the Arduino. Im using digital output 2-13.

My thought process for using

 for (int i = 0; i < ELEMENTS(led); i++){
   
   digitalWrite(led[xAxis], LOW);
   digitalWrite(led[xAxis+1], LOW);
   digitalWrite(led[xAxis+2], LOW);
   digitalWrite(led[xAxis+3], LOW);
   delay(5);
   digitalWrite(led[xAxis+4], HIGH);
   digitalWrite(led[xAxis+5], HIGH);
   digitalWrite(led[xAxis+6], HIGH);
   digitalWrite(led[xAxis+7], HIGH);
   
   digitalWrite(led[xAxis+8], HIGH);
   digitalWrite(led[xAxis+9], HIGH);
  digitalWrite(led[xAxis-1], HIGH);
  digitalWrite(led[xAxis-2], HIGH);

}

so for example if LED output 3 was LOW on the Arduino all the digital writes in the for loop would correspond to that single output.

This: digitalWrite(led[xAxis+1], LOW);

would mean +1 the currently LOW LED, always putting the one next to it LOW as well.

Doing this:
digitalWrite(led[xAxis], LOW);
digitalWrite(led[xAxis+1], LOW);
digitalWrite(led[xAxis+2], LOW);
digitalWrite(led[xAxis+3], LOW);

I was hoping would make a row of 4 LOW based on a central LOW LED and the 3 others surrounding it.

I wish i could figure out a much simpler way to do this, I feel like there would be but i can’t imagine how.

I was hoping would make a row of 4 LOW based on a central LOW LED and the 3 others surrounding it.

That is not based on a central pin. It is based on the left-most LED's pin.

I wish i could figure out a much simpler way to do this

Draw a picture with 12 LEDs on it. For each value of xAxis (from 0 to 8/9), indicate which LEDs should be lit.

PaulS:
That is not based on a central pin. It is based on the left-most LED's pin.
Draw a picture with 12 LEDs on it. For each value of xAxis (from 0 to 8/9), indicate which LEDs should be lit.

Right, I can draw the picture and see how i want them lit at any one instance, but how to do I make that correlate with moving the mapped movements of the thumb stick?

int led[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const int LEDS = sizeof led / sizeof led[0];

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < LEDS; i++) {
    pinMode(led[i], OUTPUT);
  }
}

void loop() {
  int xAxis = map(analogRead(A0), 0, 1023, 0, 9);

  Serial.println(xAxis);

  for (int i = 0; i < LEDS; i++) {
    // Turn the LED off if it is the one at index 'xAxis'
    // or one of the next three.
    boolean off = (i == xAxis)  ||
                  (i == xAxis + 1)  ||
                  (i == xAxis + 2)  ||
                  (i == xAxis + 3);
    // Note: Since 'i' goes up to 11 and 'xAxis' goes up to 9
    // when 'xAxis' is 9 (xAxis + 3 == 12) only the last three
    // lights are extinguished
    digitalWrite(led[i], !off);
  }
}

Right, I can draw the picture and see how i want them lit at any one instance, but how to do I make that correlate with moving the mapped movements of the thumb stick?

I'm going to guess that your picture will look something like this:

xAxis = 0 : 111100000000
xAxis = 1 : 011100000000
.
.
.
xAxis = 8 : 000000001111

where 1 means the LED is lit and 0 means that it is not.

If this is the case, then the LED pins to light are xAxis+0, xAxis+1, xAxis+2, and xAxis+3 of the led array, regardless of the value of xAxis.

If not, then I'll need to wait to see the picture.

PaulS:
I’m going to guess that your picture will look something like this:

xAxis = 0 : 111100000000
xAxis = 1 : 011100000000
.
.
.
xAxis = 8 : 000000001111

where 1 means the LED is lit and 0 means that it is not.

If this is the case, then the LED pins to light are xAxis+0, xAxis+1, xAxis+2, and xAxis+3 of the led array, regardless of the value of xAxis.

If not, then I’ll need to wait to see the picture.

I changed the code to this:

void loop() {
  
  int xAxis = analogRead(A0);
  
  
 
   xAxis = map(xAxis, 0, 1025, 0, 9);
   Serial.println(xAxis);
  for (int i = 0; i < ELEMENTS(led); i++){
   
   digitalWrite(led[xAxis+0], HIGH);
   digitalWrite(led[xAxis+1], HIGH);
   digitalWrite(led[xAxis+2], HIGH);
   digitalWrite(led[xAxis+3], HIGH);


  

}}

So it works the same, 4 lit in the middle. But as I move the joystick around to the other LEDs, they light up and stay lit. Moving the joystick fully left and fully right once leaves every LED permanently lit.

I’m not sure how to write the code in the pseudo code in your picture.

i would love for X position on the thumb stick to be able to mean a certain set of LEDs on and off like a binary number, I’m just not sure how to go about that.

RPELE:
4 lit in the middle.

Oh. That's the opposite of what the code looked like it was doing (four UNLIT in the middle). For four LIT in the middle:

// Turn the LED on if it is the one at index 'xAxis'
    // or one of the next three.
    boolean on = (i == xAxis)  ||
                  (i == xAxis + 1)  ||
                  (i == xAxis + 2)  ||
                  (i == xAxis + 3);
    // Note: Since 'i' goes up to 11 and 'xAxis' goes up to 9
    // when 'xAxis' is 9 (xAxis + 3 == 12) only the last three
    // lights are lit
    digitalWrite(led[i], on);

Or, add another for loop above the existing for loop, iterating from 0 to 11, in which you turn the led[index] pin off.

johnwasser:
Oh. That’s the opposite of what the code looked like it was doing (four UNLIT in the middle). For four LIT in the middle:

// Turn the LED on if it is the one at index 'xAxis'

// or one of the next three.
    boolean on = (i == xAxis)  ||
                  (i == xAxis + 1)  ||
                  (i == xAxis + 2)  ||
                  (i == xAxis + 3);
    // Note: Since ‘i’ goes up to 11 and ‘xAxis’ goes up to 9
    // when ‘xAxis’ is 9 (xAxis + 3 == 12) only the last three
    // lights are lit
    digitalWrite(led[i], on);

I was trying to make the 4 UNLIT LEDS move actually. This bit of code is awesome! thank you very much.

How would I go about getting the opposite effect though? Moving around 4 unlit LEDs while the rest of the LEDs in the row are LIT.

what does the “||” mean after the first three lines?

RPELE:
I was trying to make the 4 UNLIT LEDS move actually. This bit of code is awesome! thank you very much. How would I go about getting the opposite effect though? Moving around 4 unlit LEDs while the rest of the LEDs in the row are LIT.

what does the "||" mean after the first three lines?

See the sketch I posted in Reply #9 for moving the 4 unlit LEDs.
The "||" means OR. The result is true if either side of the OR is true.

johnwasser:
See the sketch I posted in Reply #9 for moving the 4 unlit LEDs.
The "||" means OR. The result is true if either side of the OR is true.

ohhh ok, the OR makes sense.

so If i wanted to do the opposite of your code, would it be as simple as adding "!" infant of the xAxis variables?

// Turn the LED on if it is the one at index 'xAxis'
    // or one of the next three.
    boolean on = (i == !xAxis)  ||
                  (i == !xAxis + 1)  ||
                  (i == !xAxis + 2)  ||
                  (i == !xAxis + 3);
    // Note: Since 'i' goes up to 11 and 'xAxis' goes up to 9
    // when 'xAxis' is 9 (xAxis + 3 == 12) only the last three
    // lights are lit
    digitalWrite(led[i], on);

so If i wanted to do the opposite of your code, would it be as simple as adding "!" infant of the xAxis variables?

No. You might want to use !=, but not'ing a value rarely makes sense.

RPELE:
ohhh ok, the OR makes sense.

so If i wanted to do the opposite of your code, would it be as simple as adding "!" infant of the xAxis variables?

// Turn the LED on if it is the one at index 'xAxis'

// or one of the next three.
   boolean on = (i == !xAxis)  ||
                 (i == !xAxis + 1)  ||
                 (i == !xAxis + 2)  ||
                 (i == !xAxis + 3);
   // Note: Since 'i' goes up to 11 and 'xAxis' goes up to 9
   // when 'xAxis' is 9 (xAxis + 3 == 12) only the last three
   // lights are lit
   digitalWrite(led[i], on);

NO! No, no, no, no. That won't be even close. Just go to Reply #9 and use that sketch. I've already done all of the work for you.

johnwasser:
NO! No, no, no, no. That won't be even close. Just go to Reply #9 and use that sketch. I've already done all of the work for you.

ah, somehow i missed reply 9. Thank you this helps a great deal!

With your improved method of using || and booleans, the 0-9 mapping on the x-axis isn't really required anymore. Would I be better off mapping xAxis with the max number of LEDs in the array?

int xAxis = map(analogRead(A0), 0, 1023, 0, 12);

This way would i be able to eliminate some of the (i == xAxis +number) if I wanted to increase or decrease the amount of "moveable" off LEDs in this line?